Skip to content

Commit

Permalink
vncconfig: add option to force view-only remote client connections
Browse files Browse the repository at this point in the history
Specifies that the server must ignore all keyboard or mouse events sent
by the client.

Doing this trough SocketServer::addSocket() looks as a dirty trick. It
probably requires some refining.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2180903
Signed-off-by: Carlos Santos <casantos@redhat.com>
  • Loading branch information
casantos committed Sep 10, 2023
1 parent 963f11e commit e75b5e7
Show file tree
Hide file tree
Showing 17 changed files with 48 additions and 31 deletions.
4 changes: 3 additions & 1 deletion common/network/Socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ namespace network {
// 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;
// viewOnly is set to true if the server must ignore all keyboard or
// mouse events sent by the client.
virtual void addSocket(network::Socket* sock, bool outgoing=false, bool viewOnly=false) = 0;

// removeSocket() tells the server to stop serving the Socket. The
// caller retains ownership of the Socket - the server must NOT
Expand Down
11 changes: 6 additions & 5 deletions common/rfb/SConnection.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
const SConnection::AccessRights SConnection::AccessFull = 0xffff;


SConnection::SConnection()
: readyForSetColourMapEntries(false),
SConnection::SConnection(bool viewOnly)
: viewOnly(viewOnly), readyForSetColourMapEntries(false),
is(0), os(0), reader_(0), writer_(0), ssecurity(0),
authFailureTimer(this, &SConnection::handleAuthFailureTimeout),
state_(RFBSTATE_UNINITIALISED), preferredEncoding(encodingRaw),
accessRights(0x0000), hasRemoteClipboard(false),
hasLocalClipboard(false),
accessRights(viewOnly ? SConnection::AccessView : 0x0000),
clientClipboard(NULL), hasRemoteClipboard(false), hasLocalClipboard(false),
unsolicitedClipboardAttempt(false)
{
defaultMajorVersion = 3;
Expand Down Expand Up @@ -254,7 +254,8 @@ bool SConnection::processSecurityMsg()
}

state_ = RFBSTATE_QUERYING;
setAccessRights(ssecurity->getAccessRights());
if (!viewOnly)
setAccessRights(ssecurity->getAccessRights());
queryConnection(ssecurity->getUserName());

// If the connection got approved right away then we can continue
Expand Down
3 changes: 2 additions & 1 deletion common/rfb/SConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace rfb {
class SConnection : public SMsgHandler {
public:

SConnection();
SConnection(bool viewOnly);
virtual ~SConnection();

// Methods to initialise the connection
Expand Down Expand Up @@ -236,6 +236,7 @@ namespace rfb {
void cleanup();
void writeFakeColourMap(void);

bool viewOnly;
bool readyForSetColourMapEntries;

bool processVersionMsg();
Expand Down
5 changes: 3 additions & 2 deletions common/rfb/VNCSConnectionST.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,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, bool viewOnly)
: SConnection(viewOnly),
sock(s), reverseConnection(reverse),
inProcessMessages(false),
pendingSyncFence(false), syncFence(false), fenceFlags(0),
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
Expand Down
3 changes: 2 additions & 1 deletion common/rfb/VNCSConnectionST.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
bool viewOnly);
virtual ~VNCSConnectionST();

// SConnection methods
Expand Down
4 changes: 2 additions & 2 deletions common/rfb/VNCServerST.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ VNCServerST::~VNCServerST()

// SocketServer methods

void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
void VNCServerST::addSocket(network::Socket* sock, bool outgoing, bool viewOnly)
{
// - Check the connection isn't black-marked
// *** do this in getSecurity instead?
Expand Down Expand Up @@ -159,7 +159,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, viewOnly);
clients.push_front(client);
client->init();
}
Expand Down
2 changes: 1 addition & 1 deletion common/rfb/VNCServerST.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ 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, bool viewOnly=false);

// removeSocket
// Clean up any resources associated with the Socket
Expand Down
1 change: 1 addition & 0 deletions tests/perf/encperf.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ void Manager::getStats(double& ratio, unsigned long long& encodedBytes,
}

SConn::SConn()
: SConnection(false)
{
out = new DummyOutStream;
setStreams(NULL, out);
Expand Down
3 changes: 2 additions & 1 deletion unix/vncconfig/vncExt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions unix/vncconfig/vncExt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
14 changes: 10 additions & 4 deletions unix/vncconfig/vncconfig.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
"[-viewOnly|-view-only] <host>[:<port>]\n", programName);
fprintf(stderr," %s [parameters] -disconnect\n", programName);
fprintf(stderr," %s [parameters] [-set] <Xvnc-param>=<value> ...\n",
programName);
Expand Down Expand Up @@ -240,13 +240,19 @@ 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], "-viewOnly") == 0 ||
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) {
Expand Down
7 changes: 4 additions & 3 deletions unix/vncconfig/vncconfig.man
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ vncconfig \- configure and control a VNC server
.br
.B vncconfig
.RI [ parameters ]
.B \-connect
.B \-connect \fP[\fB-viewOnly\fP|\fB-view-only\fP]
.IR host [: port ]
.br
.B vncconfig
Expand Down Expand Up @@ -55,12 +55,13 @@ is no VNC extension.

.SH OPTIONS
.TP
.B \-connect \fIhost\fP[:\fIport\fP]
.B \-connect \fP[\fB-viewOnly\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-viewOnly\fP (or \fB-view-Only\fP) option specifies that
the server must ignore all keyboard or mouse events sent by the client.
.
.TP
.B \-disconnect
Expand Down
4 changes: 2 additions & 2 deletions unix/xserver/hw/vnc/XserverDesktop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
vncSetNotifyFd(sock->getFd(), screenIndex, true, false);
}

Expand Down
2 changes: 1 addition & 1 deletion unix/xserver/hw/vnc/XserverDesktop.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
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
Expand Down
2 changes: 1 addition & 1 deletion unix/xserver/hw/vnc/vncExt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 5 additions & 3 deletions unix/xserver/hw/vnc/vncExtInit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion unix/xserver/hw/vnc/vncExtInit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit e75b5e7

Please sign in to comment.