]> source.dussan.org Git - tigervnc.git/commitdiff
Move auth failure delay to SConnection
authorPierre Ossman <ossman@cendio.se>
Mon, 18 May 2020 16:57:26 +0000 (18:57 +0200)
committerPierre Ossman <ossman@cendio.se>
Tue, 19 May 2020 18:05:30 +0000 (20:05 +0200)
It's a generic feature that is better handled as part of SConnection's
state machine.

common/rfb/SConnection.cxx
common/rfb/SConnection.h
common/rfb/VNCSConnectionST.cxx
common/rfb/VNCSConnectionST.h

index 4869199a088328ebd8d649f452ea95401000405c..e9dbd665b94db63e597211d89a2da6c8f5088104 100644 (file)
@@ -51,9 +51,9 @@ const SConnection::AccessRights SConnection::AccessFull           = 0xffff;
 
 SConnection::SConnection()
   : readyForSetColourMapEntries(false),
-    is(0), os(0), reader_(0), writer_(0),
-    ssecurity(0), state_(RFBSTATE_UNINITIALISED),
-    preferredEncoding(encodingRaw),
+    is(0), os(0), reader_(0), writer_(0), ssecurity(0),
+    authFailureTimer(this, &SConnection::handleAuthFailureTimeout),
+    state_(RFBSTATE_UNINITIALISED), preferredEncoding(encodingRaw),
     clientClipboard(NULL), hasLocalClipboard(false)
 {
   defaultMajorVersion = 3;
@@ -98,6 +98,7 @@ void SConnection::processMsg()
   case RFBSTATE_PROTOCOL_VERSION: processVersionMsg();      break;
   case RFBSTATE_SECURITY_TYPE:    processSecurityTypeMsg(); break;
   case RFBSTATE_SECURITY:         processSecurityMsg();     break;
+  case RFBSTATE_SECURITY_FAILURE: processSecurityFailure(); break;
   case RFBSTATE_INITIALISATION:   processInitMsg();         break;
   case RFBSTATE_NORMAL:           reader_->readMsg();       break;
   case RFBSTATE_QUERYING:
@@ -240,16 +241,52 @@ void SConnection::processSecurityMsg()
   } catch (AuthFailureException& e) {
     vlog.error("AuthFailureException: %s", e.str());
     state_ = RFBSTATE_SECURITY_FAILURE;
-    authFailure(e.str());
+    // Introduce a slight delay of the authentication failure response
+    // to make it difficult to brute force a password
+    authFailureMsg.replaceBuf(strDup(e.str()));
+    authFailureTimer.start(100);
   }
 }
 
+void SConnection::processSecurityFailure()
+{
+  // Silently drop any data if we are currently delaying an
+  // authentication failure response as otherwise we would close
+  // the connection on unexpected data, and an attacker could use
+  // that to detect our delayed state.
+
+  while (is->checkNoWait(1))
+    is->skip(1);
+}
+
 void SConnection::processInitMsg()
 {
   vlog.debug("reading client initialisation");
   reader_->readClientInit();
 }
 
+bool SConnection::handleAuthFailureTimeout(Timer* t)
+{
+  if (state_ != RFBSTATE_SECURITY_FAILURE) {
+    close("SConnection::handleAuthFailureTimeout: invalid state");
+    return false;
+  }
+
+  try {
+    os->writeU32(secResultFailed);
+    if (!client.beforeVersion(3,8)) // 3.8 onwards have failure message
+      os->writeString(authFailureMsg.buf);
+    os->flush();
+  } catch (rdr::Exception& e) {
+    close(e.str());
+    return false;
+  }
+
+  close(authFailureMsg.buf);
+
+  return false;
+}
+
 void SConnection::throwConnFailedException(const char* format, ...)
 {
        va_list ap;
@@ -378,19 +415,6 @@ void SConnection::authSuccess()
 {
 }
 
-void SConnection::authFailure(const char* reason)
-{
-  if (state_ != RFBSTATE_SECURITY_FAILURE)
-    throw Exception("SConnection::authFailure: invalid state");
-
-  os->writeU32(secResultFailed);
-  if (!client.beforeVersion(3,8)) // 3.8 onwards have failure message
-    os->writeString(reason);
-  os->flush();
-
-  throw AuthFailureException(reason);
-}
-
 void SConnection::queryConnection(const char* userName)
 {
   approveConnection(true);
index db3ab08c8fbf227d04e223d42c4f0510e7ffbf30..a7c4e0a6acc81b892ec20dde07112c9bc3364bc5 100644 (file)
 
 #include <rdr/InStream.h>
 #include <rdr/OutStream.h>
+
 #include <rfb/SMsgHandler.h>
 #include <rfb/SecurityServer.h>
+#include <rfb/Timer.h>
 
 namespace rfb {
 
@@ -102,10 +104,6 @@ namespace rfb {
     // authSuccess() is called when authentication has succeeded.
     virtual void authSuccess();
 
-    // authFailure() is called when authentication has failed. The default
-    // implementation will inform the client and throw a AuthFailureException.
-    virtual void authFailure(const char* reason);
-
     // queryConnection() is called when authentication has succeeded, but
     // before informing the client.  It can be overridden to query a local user
     // to accept the incoming connection, for example.  The userName argument
@@ -240,15 +238,25 @@ namespace rfb {
     void processSecurityTypeMsg();
     void processSecurityType(int secType);
     void processSecurityMsg();
+    void processSecurityFailure();
     void processInitMsg();
 
+    bool handleAuthFailureTimeout(Timer* t);
+
     int defaultMajorVersion, defaultMinorVersion;
+
     rdr::InStream* is;
     rdr::OutStream* os;
+
     SMsgReader* reader_;
     SMsgWriter* writer_;
+
     SecurityServer security;
     SSecurity* ssecurity;
+
+    MethodTimer<SConnection> authFailureTimer;
+    CharArray authFailureMsg;
+
     stateEnum state_;
     rdr::S32 preferredEncoding;
     AccessRights accessRights;
index 5d2d4b1366b46a3fac6a2ee41c72b5287f3bc4df..39efb6c6a6fb98d79c6b1849b6dd57c301f17ed1 100644 (file)
@@ -52,8 +52,7 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
     losslessTimer(this), server(server_),
     updateRenderedCursor(false), removeRenderedCursor(false),
     continuousUpdates(false), encodeManager(this), idleTimer(this),
-    pointerEventTime(0), clientHasCursor(false),
-    authFailureTimer(this)
+    pointerEventTime(0), clientHasCursor(false)
 {
   setStreams(&sock->inStream(), &sock->outStream());
   peerEndpoint.buf = sock->getPeerEndpoint();
@@ -152,15 +151,6 @@ void VNCSConnectionST::processMessages()
     sock->cork(true);
 
     while (getInStream()->checkNoWait(1)) {
-      // Silently drop any data if we are currently delaying an
-      // authentication failure response as otherwise we would close
-      // the connection on unexpected data, and an attacker could use
-      // that to detect our delayed state.
-      if (state() == RFBSTATE_SECURITY_FAILURE) {
-        getInStream()->skip(1);
-        continue;
-      }
-
       if (pendingSyncFence) {
         syncFence = true;
         pendingSyncFence = false;
@@ -437,14 +427,6 @@ void VNCSConnectionST::authSuccess()
   updates.add_changed(server->getPixelBuffer()->getRect());
 }
 
-void VNCSConnectionST::authFailure(const char* reason)
-{
-  // Introduce a slight delay of the authentication failure response
-  // to make it difficult to brute force a password
-  authFailureMsg.replaceBuf(strDup(reason));
-  authFailureTimer.start(100);
-}
-
 void VNCSConnectionST::queryConnection(const char* userName)
 {
   server->queryConnection(this, userName);
@@ -787,8 +769,6 @@ bool VNCSConnectionST::handleTimeout(Timer* t)
     if ((t == &congestionTimer) ||
         (t == &losslessTimer))
       writeFramebufferUpdate();
-    else if (t == &authFailureTimer)
-      SConnection::authFailure(authFailureMsg.buf);
   } catch (rdr::Exception& e) {
     close(e.str());
   }
index c8f4c24f07a52508b60158b48ca58acabd1ffed4..7ec2d40b4157a37e0cdfb93a3b30181687442396 100644 (file)
@@ -111,7 +111,6 @@ namespace rfb {
     // These methods are invoked as callbacks from processMsg()
 
     virtual void authSuccess();
-    virtual void authFailure(const char* reason);
     virtual void queryConnection(const char* userName);
     virtual void clientInit(bool shared);
     virtual void setPixelFormat(const PixelFormat& pf);
@@ -189,9 +188,6 @@ namespace rfb {
     Point pointerEventPos;
     bool clientHasCursor;
 
-    Timer authFailureTimer;
-    CharArray authFailureMsg;
-
     CharArray closeReason;
   };
 }