tigervnc/SOURCES/tigervnc-add-option-to-force-view-only-remote-connections.patch

1114 lines
42 KiB
Diff
Raw Permalink Normal View History

2024-07-03 08:45:09 +00:00
From 2be25eac8a96b3910701052d768ee465def36d56 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Tue, 28 May 2024 13:07:58 +0200
Subject: vncconfig: add option to force view only remote client connections
diff --git a/common/network/Socket.h b/common/network/Socket.h
index 901bab1..576fe15 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -111,41 +111,6 @@ namespace network {
SocketException(const char* text, int err_) : rdr::SystemException(text, err_) {}
};
- class SocketServer {
- public:
- virtual ~SocketServer() {}
-
- // addSocket() tells the server to serve the Socket. The caller
- // retains ownership of the Socket - the only way for the server
- // to discard a Socket is by calling shutdown() on it.
- // outgoing is set to true if the socket was created by connecting out
- // to another host, or false if the socket was created by accept()ing
- // an incoming connection.
- virtual void addSocket(network::Socket* sock, bool outgoing=false) = 0;
-
- // removeSocket() tells the server to stop serving the Socket. The
- // caller retains ownership of the Socket - the server must NOT
- // delete the Socket! This call is used mainly to cause per-Socket
- // resources to be freed.
- virtual void removeSocket(network::Socket* sock) = 0;
-
- // getSockets() gets a list of sockets. This can be used to generate an
- // fd_set for calling select().
- virtual void getSockets(std::list<network::Socket*>* sockets) = 0;
-
- // processSocketReadEvent() tells the server there is a Socket read event.
- // The implementation can indicate that the Socket is no longer active
- // by calling shutdown() on it. The caller will then call removeSocket()
- // soon after processSocketEvent returns, to allow any pre-Socket
- // resources to be tidied up.
- virtual void processSocketReadEvent(network::Socket* sock) = 0;
-
- // processSocketReadEvent() tells the server there is a Socket write event.
- // This is only necessary if the Socket has been put in non-blocking
- // mode and needs this callback to flush the buffer.
- virtual void processSocketWriteEvent(network::Socket* sock) = 0;
- };
-
}
#endif // __NETWORK_SOCKET_H__
diff --git a/common/rfb/AccessRights.cxx b/common/rfb/AccessRights.cxx
new file mode 100644
index 0000000..65e6ce2
--- /dev/null
+++ b/common/rfb/AccessRights.cxx
@@ -0,0 +1,36 @@
+/* Copyright 2024 TigerVNC Team
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include "AccessRights.h"
+
+namespace rfb
+{
+
+ // AccessRights values
+ const AccessRights AccessNone = 0x0000;
+ const AccessRights AccessView = 0x0001;
+ const AccessRights AccessKeyEvents = 0x0002;
+ const AccessRights AccessPtrEvents = 0x0004;
+ const AccessRights AccessCutText = 0x0008;
+ const AccessRights AccessSetDesktopSize = 0x0010;
+ const AccessRights AccessNonShared = 0x0020;
+ const AccessRights AccessDefault = 0x03ff;
+ const AccessRights AccessNoQuery = 0x0400;
+ const AccessRights AccessFull = 0xffff;
+
+} /* namespace rfb */
diff --git a/common/rfb/AccessRights.h b/common/rfb/AccessRights.h
new file mode 100644
index 0000000..adf4393
--- /dev/null
+++ b/common/rfb/AccessRights.h
@@ -0,0 +1,41 @@
+/* Copyright 2024 TigerVNC Team
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef COMMON_RFB_ACCESSRIGHTS_H_
+#define COMMON_RFB_ACCESSRIGHTS_H_
+
+#include <stdint.h>
+
+namespace rfb
+{
+
+ typedef uint16_t AccessRights;
+ extern const AccessRights AccessNone; // No rights at all
+ extern const AccessRights AccessView; // View display contents
+ extern const AccessRights AccessKeyEvents; // Send key events
+ extern const AccessRights AccessPtrEvents; // Send pointer events
+ extern const AccessRights AccessCutText; // Send/receive clipboard events
+ extern const AccessRights AccessSetDesktopSize; // Change desktop size
+ extern const AccessRights AccessNonShared; // Exclusive access to the server
+ extern const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
+ extern const AccessRights AccessNoQuery; // Connect without local user accepting
+ extern const AccessRights AccessFull; // All of the available AND FUTURE rights
+
+} /* namespace rfb */
+
+#endif /* COMMON_RFB_ACCESSRIGHTS_H_ */
diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt
index ea1954e..1603aa5 100644
--- a/common/rfb/CMakeLists.txt
+++ b/common/rfb/CMakeLists.txt
@@ -3,6 +3,7 @@ include_directories(${JPEG_INCLUDE_DIR})
include_directories(${PIXMAN_INCLUDE_DIRS})
add_library(rfb STATIC
+ AccessRights.cxx
Blacklist.cxx
Congestion.cxx
CConnection.cxx
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index 3587484..eaa1c6f 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -42,24 +42,12 @@ using namespace rfb;
static LogWriter vlog("SConnection");
-// AccessRights values
-const SConnection::AccessRights SConnection::AccessView = 0x0001;
-const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
-const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
-const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
-const SConnection::AccessRights SConnection::AccessSetDesktopSize = 0x0010;
-const SConnection::AccessRights SConnection::AccessNonShared = 0x0020;
-const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
-const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
-const SConnection::AccessRights SConnection::AccessFull = 0xffff;
-
-
-SConnection::SConnection()
+SConnection::SConnection(AccessRights accessRights)
: readyForSetColourMapEntries(false),
is(0), os(0), reader_(0), writer_(0), ssecurity(0),
authFailureTimer(this, &SConnection::handleAuthFailureTimeout),
state_(RFBSTATE_UNINITIALISED), preferredEncoding(encodingRaw),
- accessRights(0x0000), clientClipboard(NULL), hasLocalClipboard(false),
+ accessRights(accessRights), clientClipboard(NULL), hasLocalClipboard(false),
unsolicitedClipboardAttempt(false)
{
defaultMajorVersion = 3;
@@ -252,7 +240,7 @@ bool SConnection::processSecurityMsg()
}
state_ = RFBSTATE_QUERYING;
- setAccessRights(ssecurity->getAccessRights());
+ setAccessRights(accessRights & ssecurity->getAccessRights());
queryConnection(ssecurity->getUserName());
// If the connection got approved right away then we can continue
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
index 38969c2..e8d9695 100644
--- a/common/rfb/SConnection.h
+++ b/common/rfb/SConnection.h
@@ -27,6 +27,7 @@
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
+#include <rfb/AccessRights.h>
#include <rfb/SMsgHandler.h>
#include <rfb/SecurityServer.h>
#include <rfb/Timer.h>
@@ -40,7 +41,7 @@ namespace rfb {
class SConnection : public SMsgHandler {
public:
- SConnection();
+ SConnection(AccessRights accessRights);
virtual ~SConnection();
// Methods to initialise the connection
@@ -173,20 +174,12 @@ namespace rfb {
// clipboard via handleClipboardRequest().
virtual void sendClipboardData(const char* data);
+ // getAccessRights() returns the access rights of a SConnection to the server.
+ AccessRights getAccessRights() { return accessRights; }
+
// setAccessRights() allows a security package to limit the access rights
// of a SConnection to the server. How the access rights are treated
// is up to the derived class.
-
- typedef rdr::U16 AccessRights;
- static const AccessRights AccessView; // View display contents
- static const AccessRights AccessKeyEvents; // Send key events
- static const AccessRights AccessPtrEvents; // Send pointer events
- static const AccessRights AccessCutText; // Send/receive clipboard events
- static const AccessRights AccessSetDesktopSize; // Change desktop size
- static const AccessRights AccessNonShared; // Exclusive access to the server
- static const AccessRights AccessDefault; // The default rights, INCLUDING FUTURE ONES
- static const AccessRights AccessNoQuery; // Connect without local user accepting
- static const AccessRights AccessFull; // All of the available AND FUTURE rights
virtual void setAccessRights(AccessRights ar);
virtual bool accessCheck(AccessRights ar) const;
diff --git a/common/rfb/SSecurity.h b/common/rfb/SSecurity.h
index cef2027..6ebdbdf 100644
--- a/common/rfb/SSecurity.h
+++ b/common/rfb/SSecurity.h
@@ -63,7 +63,7 @@ namespace rfb {
// for this security type.
virtual const char* getUserName() const = 0;
- virtual SConnection::AccessRights getAccessRights() const { return SConnection::AccessDefault; }
+ virtual AccessRights getAccessRights() const { return AccessDefault; }
protected:
SConnection* sc;
diff --git a/common/rfb/SSecurityRSAAES.cxx b/common/rfb/SSecurityRSAAES.cxx
index 15d2e97..9d6da87 100644
--- a/common/rfb/SSecurityRSAAES.cxx
+++ b/common/rfb/SSecurityRSAAES.cxx
@@ -74,7 +74,7 @@ SSecurityRSAAES::SSecurityRSAAES(SConnection* sc, rdr::U32 _secType,
keySize(_keySize), isAllEncrypted(_isAllEncrypted), secType(_secType),
serverKey(), clientKey(),
serverKeyN(NULL), serverKeyE(NULL), clientKeyN(NULL), clientKeyE(NULL),
- accessRights(SConnection::AccessDefault),
+ accessRights(AccessDefault),
rais(NULL), raos(NULL), rawis(NULL), rawos(NULL)
{
assert(keySize == 128 || keySize == 256);
@@ -580,12 +580,12 @@ void SSecurityRSAAES::verifyPass()
throw AuthFailureException("No password configured for VNC Auth");
if (strcmp(password.buf, passwd.buf) == 0) {
- accessRights = SConnection::AccessDefault;
+ accessRights = AccessDefault;
return;
}
if (passwdReadOnly.buf && strcmp(password.buf, passwdReadOnly.buf) == 0) {
- accessRights = SConnection::AccessView;
+ accessRights = AccessView;
return;
}
diff --git a/common/rfb/SSecurityRSAAES.h b/common/rfb/SSecurityRSAAES.h
index 17e0d40..17e1405 100644
--- a/common/rfb/SSecurityRSAAES.h
+++ b/common/rfb/SSecurityRSAAES.h
@@ -39,7 +39,7 @@ namespace rfb {
virtual bool processMsg();
virtual const char* getUserName() const;
virtual int getType() const { return secType; }
- virtual SConnection::AccessRights getAccessRights() const
+ virtual AccessRights getAccessRights() const
{
return accessRights;
}
@@ -82,7 +82,7 @@ namespace rfb {
CharArray username;
CharArray password;
- SConnection::AccessRights accessRights;
+ AccessRights accessRights;
rdr::InStream* rais;
rdr::OutStream* raos;
diff --git a/common/rfb/SSecurityStack.cxx b/common/rfb/SSecurityStack.cxx
index 8b1c2a4..9c0321d 100644
--- a/common/rfb/SSecurityStack.cxx
+++ b/common/rfb/SSecurityStack.cxx
@@ -71,14 +71,14 @@ const char* SSecurityStack::getUserName() const
return c;
}
-SConnection::AccessRights SSecurityStack::getAccessRights() const
+AccessRights SSecurityStack::getAccessRights() const
{
- SConnection::AccessRights accessRights;
+ AccessRights accessRights;
if (!state0 && !state1)
return SSecurity::getAccessRights();
- accessRights = SConnection::AccessFull;
+ accessRights = AccessFull;
if (state0)
accessRights &= state0->getAccessRights();
diff --git a/common/rfb/SSecurityStack.h b/common/rfb/SSecurityStack.h
index 8b412bd..cf7b10d 100644
--- a/common/rfb/SSecurityStack.h
+++ b/common/rfb/SSecurityStack.h
@@ -32,7 +32,7 @@ namespace rfb {
virtual bool processMsg();
virtual int getType() const { return type; };
virtual const char* getUserName() const;
- virtual SConnection::AccessRights getAccessRights() const;
+ virtual AccessRights getAccessRights() const;
protected:
short state;
SSecurity* state0;
diff --git a/common/rfb/SSecurityVeNCrypt.cxx b/common/rfb/SSecurityVeNCrypt.cxx
index 70d50d2..45d63b4 100644
--- a/common/rfb/SSecurityVeNCrypt.cxx
+++ b/common/rfb/SSecurityVeNCrypt.cxx
@@ -180,7 +180,7 @@ const char* SSecurityVeNCrypt::getUserName() const
return ssecurity->getUserName();
}
-SConnection::AccessRights SSecurityVeNCrypt::getAccessRights() const
+AccessRights SSecurityVeNCrypt::getAccessRights() const
{
if (ssecurity == NULL)
return SSecurity::getAccessRights();
diff --git a/common/rfb/SSecurityVeNCrypt.h b/common/rfb/SSecurityVeNCrypt.h
index afbf724..d1fa831 100644
--- a/common/rfb/SSecurityVeNCrypt.h
+++ b/common/rfb/SSecurityVeNCrypt.h
@@ -37,7 +37,7 @@ namespace rfb {
virtual bool processMsg();
virtual int getType() const { return chosenType; }
virtual const char* getUserName() const;
- virtual SConnection::AccessRights getAccessRights() const;
+ virtual AccessRights getAccessRights() const;
protected:
SSecurity *ssecurity;
diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx
index a19404d..fcce4b2 100644
--- a/common/rfb/SSecurityVncAuth.cxx
+++ b/common/rfb/SSecurityVncAuth.cxx
@@ -54,7 +54,7 @@ VncAuthPasswdParameter SSecurityVncAuth::vncAuthPasswd
SSecurityVncAuth::SSecurityVncAuth(SConnection* sc)
: SSecurity(sc), sentChallenge(false),
- pg(&vncAuthPasswd), accessRights(0)
+ pg(&vncAuthPasswd), accessRights(AccessNone)
{
}
@@ -103,12 +103,12 @@ bool SSecurityVncAuth::processMsg()
throw AuthFailureException("No password configured for VNC Auth");
if (verifyResponse(passwd)) {
- accessRights = SConnection::AccessDefault;
+ accessRights = AccessDefault;
return true;
}
if (passwdReadOnly.buf && verifyResponse(passwdReadOnly)) {
- accessRights = SConnection::AccessView;
+ accessRights = AccessView;
return true;
}
diff --git a/common/rfb/SSecurityVncAuth.h b/common/rfb/SSecurityVncAuth.h
index 94d5aaf..b7448f4 100644
--- a/common/rfb/SSecurityVncAuth.h
+++ b/common/rfb/SSecurityVncAuth.h
@@ -55,7 +55,7 @@ namespace rfb {
virtual bool processMsg();
virtual int getType() const {return secTypeVncAuth;}
virtual const char* getUserName() const {return 0;}
- virtual SConnection::AccessRights getAccessRights() const { return accessRights; }
+ virtual AccessRights getAccessRights() const { return accessRights; }
static StringParameter vncAuthPasswdFile;
static VncAuthPasswdParameter vncAuthPasswd;
private:
@@ -65,7 +65,7 @@ namespace rfb {
rdr::U8 response[vncAuthChallengeSize];
bool sentChallenge;
VncAuthPasswdGetter* pg;
- SConnection::AccessRights accessRights;
+ AccessRights accessRights;
};
}
#endif
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 23024c5..441ad3b 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -48,8 +48,9 @@ static LogWriter vlog("VNCSConnST");
static Cursor emptyCursor(0, 0, Point(0, 0), NULL);
VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
- bool reverse)
- : sock(s), reverseConnection(reverse),
+ bool reverse, AccessRights ar)
+ : SConnection(ar),
+ sock(s), reverseConnection(reverse),
inProcessMessages(false),
pendingSyncFence(false), syncFence(false), fenceFlags(0),
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 72b0c52..66567a6 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -40,7 +40,8 @@ namespace rfb {
class VNCSConnectionST : private SConnection,
public Timer::Callback {
public:
- VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse);
+ VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse,
+ AccessRights ar);
virtual ~VNCSConnectionST();
// SConnection methods
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index 4535b56..a081f63 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -23,17 +23,48 @@
#ifndef __RFB_VNCSERVER_H__
#define __RFB_VNCSERVER_H__
-#include <network/Socket.h>
-
#include <rfb/UpdateTracker.h>
#include <rfb/SSecurity.h>
#include <rfb/ScreenSet.h>
+namespace network { class Socket; }
+
namespace rfb {
- class VNCServer : public UpdateTracker,
- public network::SocketServer {
+ class VNCServer : public UpdateTracker {
public:
+ // addSocket() tells the server to serve the Socket. The caller
+ // retains ownership of the Socket - the only way for the server
+ // to discard a Socket is by calling shutdown() on it.
+ // outgoing is set to true if the socket was created by connecting out
+ // to another host, or false if the socket was created by accept()ing
+ // an incoming connection.
+ // accessRights allows to set the access rights to the server.
+ virtual void addSocket(network::Socket* sock, bool outgoing=false,
+ AccessRights accessRights = AccessDefault) = 0;
+
+ // removeSocket() tells the server to stop serving the Socket. The
+ // caller retains ownership of the Socket - the server must NOT
+ // delete the Socket! This call is used mainly to cause per-Socket
+ // resources to be freed.
+ virtual void removeSocket(network::Socket* sock) = 0;
+
+ // getSockets() gets a list of sockets. This can be used to generate an
+ // fd_set for calling select().
+ virtual void getSockets(std::list<network::Socket*>* sockets) = 0;
+
+ // processSocketReadEvent() tells the server there is a Socket read event.
+ // The implementation can indicate that the Socket is no longer active
+ // by calling shutdown() on it. The caller will then call removeSocket()
+ // soon after processSocketEvent returns, to allow any pre-Socket
+ // resources to be tidied up.
+ virtual void processSocketReadEvent(network::Socket* sock) = 0;
+
+ // processSocketReadEvent() tells the server there is a Socket write event.
+ // This is only necessary if the Socket has been put in non-blocking
+ // mode and needs this callback to flush the buffer.
+ virtual void processSocketWriteEvent(network::Socket* sock) = 0;
+
// blockUpdates()/unblockUpdates() tells the server that the pixel buffer
// is currently in flux and may not be accessed. The attributes of the
// pixel buffer may still be accessed, but not the frame buffer itself.
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 411cfd5..6f7c039 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -55,6 +55,8 @@
#include <assert.h>
#include <stdlib.h>
+#include <network/Socket.h>
+
#include <rfb/ComparingUpdateTracker.h>
#include <rfb/KeyRemapper.h>
#include <rfb/LogWriter.h>
@@ -126,9 +128,9 @@ VNCServerST::~VNCServerST()
}
-// SocketServer methods
+// VNCServer methods
-void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
+void VNCServerST::addSocket(network::Socket* sock, bool outgoing, AccessRights accessRights)
{
// - Check the connection isn't black-marked
// *** do this in getSecurity instead?
@@ -161,7 +163,7 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
connectTimer.start(secsToMillis(rfb::Server::maxConnectionTime));
disconnectTimer.stop();
- VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
+ VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing, accessRights);
clients.push_front(client);
client->init();
}
@@ -233,8 +235,6 @@ void VNCServerST::processSocketWriteEvent(network::Socket* sock)
throw rdr::Exception("invalid Socket in VNCServerST");
}
-// VNCServer methods
-
void VNCServerST::blockUpdates()
{
blockCounter++;
@@ -677,7 +677,7 @@ void VNCServerST::queryConnection(VNCSConnectionST* client,
}
// - Does the client have the right to bypass the query?
- if (client->accessCheck(SConnection::AccessNoQuery))
+ if (client->accessCheck(AccessNoQuery))
{
approveConnection(client->getSock(), true, NULL);
return;
@@ -690,7 +690,7 @@ void VNCServerST::clientReady(VNCSConnectionST* client, bool shared)
{
if (!shared) {
if (rfb::Server::disconnectClients &&
- client->accessCheck(SConnection::AccessNonShared)) {
+ client->accessCheck(AccessNonShared)) {
// - Close all the other connected clients
slog.debug("non-shared connection - closing clients");
closeClients("Non-shared connection requested", client->getSock());
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 159e3a4..3610062 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -51,12 +51,13 @@ namespace rfb {
virtual ~VNCServerST();
- // Methods overridden from SocketServer
+ // Methods overridden from VNCServer
// addSocket
// Causes the server to allocate an RFB-protocol management
// structure for the socket & initialise it.
- virtual void addSocket(network::Socket* sock, bool outgoing=false);
+ virtual void addSocket(network::Socket* sock, bool outgoing=false,
+ AccessRights ar=AccessDefault);
// removeSocket
// Clean up any resources associated with the Socket
@@ -76,9 +77,6 @@ namespace rfb {
// Flush pending data from the Socket on to the network.
virtual void processSocketWriteEvent(network::Socket* sock);
-
- // Methods overridden from VNCServer
-
virtual void blockUpdates();
virtual void unblockUpdates();
virtual void setPixelBuffer(PixelBuffer* pb, const ScreenSet& layout);
diff --git a/tests/perf/encperf.cxx b/tests/perf/encperf.cxx
index 8fb9553..fa87b16 100644
--- a/tests/perf/encperf.cxx
+++ b/tests/perf/encperf.cxx
@@ -41,6 +41,8 @@
#include <rdr/OutStream.h>
#include <rdr/FileInStream.h>
+#include <rfb/AccessRights.h>
+
#include <rfb/PixelFormat.h>
#include <rfb/CConnection.h>
@@ -134,7 +136,7 @@ public:
void getStats(double&, unsigned long long&, unsigned long long&);
- virtual void setAccessRights(AccessRights ar);
+ virtual void setAccessRights(rfb::AccessRights ar);
virtual void setDesktopSize(int fb_width, int fb_height,
const rfb::ScreenSet& layout);
@@ -303,6 +305,7 @@ void Manager::getStats(double& ratio, unsigned long long& encodedBytes,
}
SConn::SConn()
+: SConnection(rfb::AccessDefault)
{
out = new DummyOutStream;
setStreams(NULL, out);
@@ -329,7 +332,7 @@ void SConn::getStats(double& ratio, unsigned long long& bytes,
manager->getStats(ratio, bytes, rawEquivalent);
}
-void SConn::setAccessRights(AccessRights ar)
+void SConn::setAccessRights(rfb::AccessRights)
{
}
diff --git a/unix/vncconfig/vncExt.c b/unix/vncconfig/vncExt.c
index f19123b..4ec671b 100644
--- a/unix/vncconfig/vncExt.c
+++ b/unix/vncconfig/vncExt.c
@@ -228,7 +228,7 @@ Bool XVncExtSelectInput(Display* dpy, Window w, int mask)
return True;
}
-Bool XVncExtConnect(Display* dpy, const char* hostAndPort)
+Bool XVncExtConnect(Display* dpy, const char* hostAndPort, Bool viewOnly)
{
xVncExtConnectReq* req;
xVncExtConnectReply rep;
@@ -243,6 +243,7 @@ Bool XVncExtConnect(Display* dpy, const char* hostAndPort)
req->vncExtReqType = X_VncExtConnect;
req->length += (strLen + 3) >> 2;
req->strLen = strLen;
+ req->viewOnly = (CARD8)viewOnly;
Data(dpy, hostAndPort, strLen);
if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
UnlockDisplay(dpy);
diff --git a/unix/vncconfig/vncExt.h b/unix/vncconfig/vncExt.h
index 2b24469..4383248 100644
--- a/unix/vncconfig/vncExt.h
+++ b/unix/vncconfig/vncExt.h
@@ -46,7 +46,7 @@ char* XVncExtGetParamDesc(Display* dpy, const char* param);
char** XVncExtListParams(Display* dpy, int* nParams);
void XVncExtFreeParamList(char** list);
Bool XVncExtSelectInput(Display* dpy, Window w, int mask);
-Bool XVncExtConnect(Display* dpy, const char* hostAndPort);
+Bool XVncExtConnect(Display* dpy, const char* hostAndPort, Bool viewOnly);
Bool XVncExtGetQueryConnect(Display* dpy, char** addr,
char** user, int* timeout, void** opaqueId);
Bool XVncExtApproveConnect(Display* dpy, void* opaqueId, int approve);
@@ -181,7 +181,7 @@ typedef struct {
CARD8 vncExtReqType; /* always VncExtConnect */
CARD16 length B16;
CARD8 strLen;
- CARD8 pad0;
+ CARD8 viewOnly;
CARD16 pad1 B16;
} xVncExtConnectReq;
#define sz_xVncExtConnectReq 8
diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx
index 276d0e6..0d644ed 100644
--- a/unix/vncconfig/vncconfig.cxx
+++ b/unix/vncconfig/vncconfig.cxx
@@ -177,8 +177,8 @@ static void usage()
{
fprintf(stderr,"usage: %s [parameters]\n",
programName);
- fprintf(stderr," %s [parameters] -connect <host>[:<port>]\n",
- programName);
+ fprintf(stderr," %s [parameters] -connect "
+ "[-view-only] <host>[:<port>]\n", programName);
fprintf(stderr," %s [parameters] -disconnect\n", programName);
fprintf(stderr," %s [parameters] [-set] <Xvnc-param>=<value> ...\n",
programName);
@@ -241,13 +241,18 @@ int main(int argc, char** argv)
if (i < argc) {
for (; i < argc; i++) {
if (strcmp(argv[i], "-connect") == 0) {
+ Bool viewOnly = False;
i++;
+ if (strcmp(argv[i], "-view-only") == 0) {
+ viewOnly = True;
+ i++;
+ }
if (i >= argc) usage();
- if (!XVncExtConnect(dpy, argv[i])) {
+ if (!XVncExtConnect(dpy, argv[i], viewOnly)) {
fprintf(stderr,"connecting to %s failed\n",argv[i]);
}
} else if (strcmp(argv[i], "-disconnect") == 0) {
- if (!XVncExtConnect(dpy, "")) {
+ if (!XVncExtConnect(dpy, "", False)) {
fprintf(stderr,"disconnecting all clients failed\n");
}
} else if (strcmp(argv[i], "-get") == 0) {
diff --git a/unix/vncconfig/vncconfig.man b/unix/vncconfig/vncconfig.man
index ed9ddda..b07c02f 100644
--- a/unix/vncconfig/vncconfig.man
+++ b/unix/vncconfig/vncconfig.man
@@ -7,7 +7,7 @@ vncconfig \- configure and control a VNC server
.br
.B vncconfig
.RI [ parameters ]
-.B \-connect
+.B \-connect \fP[\fB-view-only\fP]
.IR host [: port ]
.br
.B vncconfig
@@ -55,12 +55,13 @@ is no VNC extension.
.SH OPTIONS
.TP
-.B \-connect \fIhost\fP[:\fIport\fP]
+.B \-connect \fP[\fB-view-only\fP] \fIhost\fP[:\fIport\fP]
Tells an Xvnc server to make a "reverse" connection to a listening VNC viewer
(normally connections are made the other way round - the viewer connects to the
server). \fIhost\fP is the host where the listening viewer is running. If it's
not listening on the default port of 5500, you can specify \fIhost:port\fP
-instead.
+instead. The \fB-view-only\fP option specifies that the server must ignore all
+keyboard or mouse events sent by the client.
.
.TP
.B \-disconnect
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index f9c8109..6719c43 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -26,6 +26,8 @@
#include <signal.h>
#include <unistd.h>
+#include <network/Socket.h>
+
#include <rfb/LogWriter.h>
#include <x0vncserver/XDesktop.h>
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 603e1e5..5f08f10 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -311,7 +311,7 @@ void XserverDesktop::handleSocketEvent(int fd, bool read, bool write)
bool XserverDesktop::handleListenerEvent(int fd,
std::list<SocketListener*>* sockets,
- SocketServer* sockserv)
+ VNCServer* sockserv)
{
std::list<SocketListener*>::iterator i;
@@ -332,7 +332,7 @@ bool XserverDesktop::handleListenerEvent(int fd,
}
bool XserverDesktop::handleSocketEvent(int fd,
- SocketServer* sockserv,
+ VNCServer* sockserv,
bool read, bool write)
{
std::list<Socket*> sockets;
@@ -402,10 +402,10 @@ void XserverDesktop::blockHandler(int* timeout)
}
}
-void XserverDesktop::addClient(Socket* sock, bool reverse)
+void XserverDesktop::addClient(Socket* sock, bool reverse, bool viewOnly)
{
vlog.debug("new client, sock %d reverse %d",sock->getFd(),reverse);
- server->addSocket(sock, reverse);
+ server->addSocket(sock, reverse, viewOnly ? AccessView : AccessDefault);
vncSetNotifyFd(sock->getFd(), screenIndex, true, false);
}
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 57ee808..1382677 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -42,7 +42,7 @@ namespace rfb {
class VNCServerST;
}
-namespace network { class SocketListener; class Socket; class SocketServer; }
+namespace network { class SocketListener; class Socket; }
class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
public rfb::Timer::Callback {
@@ -72,7 +72,7 @@ public:
void add_copied(const rfb::Region &dest, const rfb::Point &delta);
void handleSocketEvent(int fd, bool read, bool write);
void blockHandler(int* timeout);
- void addClient(network::Socket* sock, bool reverse);
+ void addClient(network::Socket* sock, bool reverse, bool viewOnly);
void disconnectClients();
// QueryConnect methods called from X server code
@@ -107,9 +107,9 @@ public:
protected:
bool handleListenerEvent(int fd,
std::list<network::SocketListener*>* sockets,
- network::SocketServer* sockserv);
+ rfb::VNCServer* sockserv);
bool handleSocketEvent(int fd,
- network::SocketServer* sockserv,
+ rfb::VNCServer* sockserv,
bool read, bool write);
virtual bool handleTimeout(rfb::Timer* t);
diff --git a/unix/xserver/hw/vnc/vncExt.c b/unix/xserver/hw/vnc/vncExt.c
index 89c1055..e98275c 100644
--- a/unix/xserver/hw/vnc/vncExt.c
+++ b/unix/xserver/hw/vnc/vncExt.c
@@ -348,7 +348,7 @@ static int ProcVncExtConnect(ClientPtr client)
address[stuff->strLen] = 0;
rep.success = 0;
- if (vncConnectClient(address) == 0)
+ if (vncConnectClient(address, (int)stuff->viewOnly) == 0)
rep.success = 1;
rep.type = X_Reply;
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index 8dbc048..2e0dc9e 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -262,7 +262,7 @@ void vncExtensionInit(void)
if (scr == 0 && vncInetdSock != -1 && listeners.empty()) {
network::Socket* sock = new network::TcpSocket(vncInetdSock);
- desktop[scr]->addClient(sock, false);
+ desktop[scr]->addClient(sock, false, false);
vlog.info("added inetd sock");
}
}
@@ -338,7 +338,7 @@ void vncSendClipboardData(const char* data)
desktop[scr]->sendClipboardData(data);
}
-int vncConnectClient(const char *addr)
+int vncConnectClient(const char *addr, int viewOnly)
{
if (strlen(addr) == 0) {
try {
@@ -357,8 +357,10 @@ int vncConnectClient(const char *addr)
try {
network::Socket* sock = new network::TcpSocket(host, port);
+ vlog.info("Reverse connection: %s:%d%s", host, port,
+ viewOnly ? " (view only)" : "");
delete [] host;
- desktop[0]->addClient(sock, true);
+ desktop[0]->addClient(sock, true, (bool)viewOnly);
} catch (rdr::Exception& e) {
vlog.error("Reverse connection: %s",e.str());
return -1;
diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h
index c317d8a..333e32a 100644
--- a/unix/xserver/hw/vnc/vncExtInit.h
+++ b/unix/xserver/hw/vnc/vncExtInit.h
@@ -57,7 +57,7 @@ void vncRequestClipboard(void);
void vncAnnounceClipboard(int available);
void vncSendClipboardData(const char* data);
-int vncConnectClient(const char *addr);
+int vncConnectClient(const char *addr, int viewOnly);
void vncGetQueryConnect(uint32_t *opaqueId, const char**username,
const char **address, int *timeout);
diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx
index 5463b24..9c9a736 100644
--- a/win/rfb_win32/SocketManager.cxx
+++ b/win/rfb_win32/SocketManager.cxx
@@ -24,8 +24,12 @@
#include <winsock2.h>
#include <list>
+
+#include <network/Socket.h>
+
#include <rfb/LogWriter.h>
#include <rfb/Timer.h>
+#include <rfb/VNCServer.h>
#include <rfb_win32/SocketManager.h>
using namespace rfb;
@@ -54,7 +58,7 @@ static void requestAddressChangeEvents(network::SocketListener* sock_) {
void SocketManager::addListener(network::SocketListener* sock_,
- network::SocketServer* srvr,
+ VNCServer* srvr,
AddressChangeNotifier* acn) {
WSAEVENT event = WSACreateEvent();
long flags = FD_ACCEPT | FD_CLOSE;
@@ -102,7 +106,7 @@ void SocketManager::remListener(network::SocketListener* sock) {
}
-void SocketManager::addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing) {
+void SocketManager::addSocket(network::Socket* sock_, VNCServer* srvr, bool outgoing) {
WSAEVENT event = WSACreateEvent();
if (!event || !addEvent(event, this) ||
(WSAEventSelect(sock_->getFd(), event, FD_READ | FD_CLOSE) == SOCKET_ERROR)) {
@@ -134,7 +138,7 @@ void SocketManager::remSocket(network::Socket* sock_) {
throw rdr::Exception("Socket not registered");
}
-bool SocketManager::getDisable(network::SocketServer* srvr)
+bool SocketManager::getDisable(VNCServer* srvr)
{
std::map<HANDLE,ListenInfo>::iterator i;
for (i=listeners.begin(); i!=listeners.end(); i++) {
@@ -145,7 +149,7 @@ bool SocketManager::getDisable(network::SocketServer* srvr)
throw rdr::Exception("Listener not registered");
}
-void SocketManager::setDisable(network::SocketServer* srvr, bool disable)
+void SocketManager::setDisable(VNCServer* srvr, bool disable)
{
bool found = false;
std::map<HANDLE,ListenInfo>::iterator i;
diff --git a/win/rfb_win32/SocketManager.h b/win/rfb_win32/SocketManager.h
index e5ca02e..809c470 100644
--- a/win/rfb_win32/SocketManager.h
+++ b/win/rfb_win32/SocketManager.h
@@ -19,22 +19,28 @@
// -=- SocketManager.h
// Socket manager class for Win32.
-// Passed a network::SocketListener and a network::SocketServer when
+// Passed a network::SocketListener and a rfb::VNCServer when
// constructed. Uses WSAAsyncSelect to get notifications of network
// connection attempts. When an incoming connection is received,
-// the manager will call network::SocketServer::addClient(). If
+// the manager will call rfb::VNCServer::addClient(). If
// addClient returns true then the manager registers interest in
// network events on that socket, and calls
-// network::SocketServer::processSocketEvent().
+// rfb::VNCServer::processSocketEvent().
#ifndef __RFB_WIN32_SOCKET_MGR_H__
#define __RFB_WIN32_SOCKET_MGR_H__
#include <map>
-#include <network/Socket.h>
#include <rfb_win32/EventManager.h>
+namespace network {
+ class SocketListener;
+ class Socket;
+}
+
namespace rfb {
+ class VNCServer;
+
namespace win32 {
class SocketManager : public EventManager, EventHandler {
@@ -52,21 +58,21 @@ namespace rfb {
};
// Add a listening socket. Incoming connections will be added to the supplied
- // SocketServer.
+ // VNCServer.
void addListener(network::SocketListener* sock_,
- network::SocketServer* srvr,
+ VNCServer* srvr,
AddressChangeNotifier* acn = 0);
// Remove and delete a listening socket.
void remListener(network::SocketListener* sock);
// Add an already-connected socket. Socket events will cause the supplied
- // SocketServer to be called. The socket must ALREADY BE REGISTERED with
- // the SocketServer.
- void addSocket(network::Socket* sock_, network::SocketServer* srvr, bool outgoing=true);
+ // VNCServer to be called. The socket must ALREADY BE REGISTERED with
+ // the VNCServer.
+ void addSocket(network::Socket* sock_, VNCServer* srvr, bool outgoing=true);
- bool getDisable(network::SocketServer* srvr);
- void setDisable(network::SocketServer* srvr, bool disable);
+ bool getDisable(VNCServer* srvr);
+ void setDisable(VNCServer* srvr, bool disable);
protected:
virtual int checkTimeouts();
@@ -75,11 +81,11 @@ namespace rfb {
struct ConnInfo {
network::Socket* sock;
- network::SocketServer* server;
+ VNCServer* server;
};
struct ListenInfo {
network::SocketListener* sock;
- network::SocketServer* server;
+ VNCServer* server;
AddressChangeNotifier* notifier;
bool disable;
};
diff --git a/win/winvnc/ManagedListener.cxx b/win/winvnc/ManagedListener.cxx
index a93ca29..1a27867 100644
--- a/win/winvnc/ManagedListener.cxx
+++ b/win/winvnc/ManagedListener.cxx
@@ -45,7 +45,7 @@ ManagedListener::~ManagedListener() {
}
-void ManagedListener::setServer(network::SocketServer* svr) {
+void ManagedListener::setServer(rfb::VNCServer* svr) {
if (svr == server)
return;
vlog.info("set server to %p", svr);
diff --git a/win/winvnc/ManagedListener.h b/win/winvnc/ManagedListener.h
index 39223c7..20503c3 100644
--- a/win/winvnc/ManagedListener.h
+++ b/win/winvnc/ManagedListener.h
@@ -27,7 +27,7 @@ namespace winvnc {
// -=- ManagedListener
// Wrapper class which simplifies the management of a listening socket
- // on a specified port, attached to a SocketManager and SocketServer.
+ // on a specified port, attached to a SocketManager and VNCServer.
// Reopens sockets & reconfigures filters & callbacks as appropriate.
// Handles addition/removal of Listeners from SocketManager internally.
@@ -36,7 +36,7 @@ namespace winvnc {
ManagedListener(rfb::win32::SocketManager* mgr);
~ManagedListener();
- void setServer(network::SocketServer* svr);
+ void setServer(rfb::VNCServer* svr);
void setPort(int port, bool localOnly=false);
void setFilter(const char* filter);
void setAddressChangeNotifier(rfb::win32::SocketManager::AddressChangeNotifier* acn);
@@ -49,7 +49,7 @@ namespace winvnc {
network::TcpFilter* filter;
rfb::win32::SocketManager* manager;
rfb::win32::SocketManager::AddressChangeNotifier* addrChangeNotifier;
- network::SocketServer* server;
+ rfb::VNCServer* server;
int port;
bool localOnly;
};
diff --git a/win/winvnc/VNCServerWin32.cxx b/win/winvnc/VNCServerWin32.cxx
index 79769e9..b884352 100644
--- a/win/winvnc/VNCServerWin32.cxx
+++ b/win/winvnc/VNCServerWin32.cxx
@@ -366,11 +366,11 @@ void VNCServerWin32::getConnInfo(ListConnInfo * listConn)
if (!conn->authenticated())
status = 3;
- else if (conn->accessCheck(rfb::SConnection::AccessPtrEvents |
- rfb::SConnection::AccessKeyEvents |
- rfb::SConnection::AccessView))
+ else if (conn->accessCheck(rfb::AccessPtrEvents |
+ rfb::AccessKeyEvents |
+ rfb::AccessView))
status = 0;
- else if (conn->accessCheck(rfb::SConnection::AccessView))
+ else if (conn->accessCheck(rfb::AccessView))
status = 1;
else
status = 2;
@@ -401,25 +401,25 @@ void VNCServerWin32::setConnStatus(ListConnInfo* listConn)
if (status == 3) {
conn->close(0);
} else {
- rfb::SConnection::AccessRights ar;
+ rfb::AccessRights ar;
- ar = rfb::SConnection::AccessDefault;
+ ar = rfb::AccessDefault;
switch (status) {
case 0:
- ar |= rfb::SConnection::AccessPtrEvents |
- rfb::SConnection::AccessKeyEvents |
- rfb::SConnection::AccessView;
+ ar |= rfb::AccessPtrEvents |
+ rfb::AccessKeyEvents |
+ rfb::AccessView;
break;
case 1:
- ar |= rfb::SConnection::AccessView;
- ar &= ~(rfb::SConnection::AccessPtrEvents |
- rfb::SConnection::AccessKeyEvents);
+ ar |= rfb::AccessView;
+ ar &= ~(rfb::AccessPtrEvents |
+ rfb::AccessKeyEvents);
break;
case 2:
- ar &= ~(rfb::SConnection::AccessPtrEvents |
- rfb::SConnection::AccessKeyEvents |
- rfb::SConnection::AccessView);
+ ar &= ~(rfb::AccessPtrEvents |
+ rfb::AccessKeyEvents |
+ rfb::AccessView);
break;
}
conn->setAccessRights(ar);