diff --git a/common/network/Socket.h b/common/network/Socket.h index 117851c191..e44bbc2596 100644 --- a/common/network/Socket.h +++ b/common/network/Socket.h @@ -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 diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index 33b2d850e6..ea3a4a9434 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -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; @@ -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 diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index b163d6273e..b45532b2a7 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -42,7 +42,7 @@ namespace rfb { class SConnection : public SMsgHandler { public: - SConnection(); + SConnection(bool viewOnly); virtual ~SConnection(); // Methods to initialise the connection @@ -236,6 +236,7 @@ namespace rfb { void cleanup(); void writeFakeColourMap(void); + bool viewOnly; bool readyForSetColourMapEntries; bool processVersionMsg(); diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index 90311770da..cd534ab7ba 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -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), diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index edc0391edc..7c86889817 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, + bool viewOnly); virtual ~VNCSConnectionST(); // SConnection methods diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 7bed8831c6..a372348670 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -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? @@ -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(); } diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index 028903c982..293f92e7b5 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -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 diff --git a/tests/perf/encperf.cxx b/tests/perf/encperf.cxx index 40e3abfc1e..d977f74fc0 100644 --- a/tests/perf/encperf.cxx +++ b/tests/perf/encperf.cxx @@ -303,6 +303,7 @@ void Manager::getStats(double& ratio, unsigned long long& encodedBytes, } SConn::SConn() +: SConnection(false) { out = new DummyOutStream; setStreams(NULL, out); diff --git a/unix/vncconfig/vncExt.c b/unix/vncconfig/vncExt.c index f19123b889..4ec671b885 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 2b24469e34..4383248c9f 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 f39e9934ae..27f018d10f 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 [:]\n", - programName); + fprintf(stderr," %s [parameters] -connect " + "[-viewOnly|-view-only] [:]\n", programName); fprintf(stderr," %s [parameters] -disconnect\n", programName); fprintf(stderr," %s [parameters] [-set] = ...\n", programName); @@ -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) { diff --git a/unix/vncconfig/vncconfig.man b/unix/vncconfig/vncconfig.man index ed9ddda4b1..b47787fac1 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-viewOnly\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-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 diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index b5a5867182..91c24f86ef 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); vncSetNotifyFd(sock->getFd(), screenIndex, true, false); } diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h index 677097a6e6..692777f2b5 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.h +++ b/unix/xserver/hw/vnc/XserverDesktop.h @@ -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 diff --git a/unix/xserver/hw/vnc/vncExt.c b/unix/xserver/hw/vnc/vncExt.c index 89c105503f..e98275c2c8 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 1dfe76d741..b260e62664 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 c317d8a216..333e32a90d 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);