aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Santos <casantos@redhat.com>2023-11-29 18:52:52 -0300
committerCarlos Santos <casantos@redhat.com>2024-04-26 11:28:07 -0300
commit7597f8d42b236c99d175a02cea7e76593e16b886 (patch)
treed421a171c74db5884f0d4b1b9a4dcade52866a51
parentd77e2b01f972ef12b722e3ef9d22efdc241689c3 (diff)
downloadtigervnc-7597f8d42b236c99d175a02cea7e76593e16b886.tar.gz
tigervnc-7597f8d42b236c99d175a02cea7e76593e16b886.zip
vncconfig: add option to force view-only remote client connections
Specifies that the server must ignore all keyboard or mouse events sent by the client. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2180903 Signed-off-by: Carlos Santos <casantos@redhat.com>
-rw-r--r--common/rfb/SConnection.cxx6
-rw-r--r--common/rfb/SConnection.h5
-rw-r--r--common/rfb/VNCSConnectionST.cxx5
-rw-r--r--common/rfb/VNCSConnectionST.h3
-rw-r--r--common/rfb/VNCServer.h4
-rw-r--r--common/rfb/VNCServerST.cxx4
-rw-r--r--common/rfb/VNCServerST.h3
-rw-r--r--tests/perf/encperf.cxx3
-rw-r--r--unix/vncconfig/vncExt.c3
-rw-r--r--unix/vncconfig/vncExt.h4
-rw-r--r--unix/vncconfig/vncconfig.cxx13
-rw-r--r--unix/vncconfig/vncconfig.man7
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc4
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.h2
-rw-r--r--unix/xserver/hw/vnc/vncExt.c2
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.cc8
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.h2
17 files changed, 49 insertions, 29 deletions
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index 462c34c2..7a930af5 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -43,12 +43,12 @@ using namespace rfb;
static LogWriter vlog("SConnection");
-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(AccessNone), hasRemoteClipboard(false),
+ accessRights(accessRights), hasRemoteClipboard(false),
hasLocalClipboard(false),
unsolicitedClipboardAttempt(false)
{
@@ -242,7 +242,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 fb8b0b4c..cc88cd1e 100644
--- a/common/rfb/SConnection.h
+++ b/common/rfb/SConnection.h
@@ -43,7 +43,7 @@ namespace rfb {
class SConnection : public SMsgHandler {
public:
- SConnection();
+ SConnection(AccessRights accessRights);
virtual ~SConnection();
// Methods to initialise the connection
@@ -176,6 +176,9 @@ 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.
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 906f5f66..f1194eb6 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -51,8 +51,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 edc0391e..2f117a75 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 6d75f8f8..cf14bd86 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -39,7 +39,9 @@ namespace rfb {
// 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;
+ // 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
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index edf23a4f..fb421068 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -132,7 +132,7 @@ VNCServerST::~VNCServerST()
// 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?
@@ -163,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();
}
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 4a8efa46..d303831e 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -56,7 +56,8 @@ namespace rfb {
// 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
diff --git a/tests/perf/encperf.cxx b/tests/perf/encperf.cxx
index 55fa386e..388dcc95 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>
@@ -303,6 +305,7 @@ void Manager::getStats(double& ratio, unsigned long long& encodedBytes,
}
SConn::SConn()
+: SConnection(rfb::AccessDefault)
{
out = new DummyOutStream;
setStreams(NULL, out);
diff --git a/unix/vncconfig/vncExt.c b/unix/vncconfig/vncExt.c
index f19123b8..4ec671b8 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 2b24469e..4383248c 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 f39e9934..e0c9928a 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);
@@ -240,13 +240,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 ed9ddda4..b07c02f4 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/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index a2160a72..4cf37937 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -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 a42b5440..9cc5bf79 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -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
diff --git a/unix/xserver/hw/vnc/vncExt.c b/unix/xserver/hw/vnc/vncExt.c
index 89c10550..e98275c2 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 1dfe76d7..b260e626 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -267,7 +267,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");
}
}
@@ -343,7 +343,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 {
@@ -362,7 +362,9 @@ int vncConnectClient(const char *addr)
try {
network::Socket* sock = new network::TcpSocket(host.c_str(), port);
- desktop[0]->addClient(sock, true);
+ vlog.info("Reverse connection: %s:%d%s", host.c_str(), port,
+ viewOnly ? " (view only)" : "");
+ 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 c317d8a2..333e32a9 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);