From 2be25eac8a96b3910701052d768ee465def36d56 Mon Sep 17 00:00:00 2001 From: Jan Grulich 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* 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 + +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 #include +#include #include #include #include @@ -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 - #include #include #include +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* 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 #include +#include + #include #include #include @@ -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 #include +#include + #include #include @@ -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 [:]\n", - programName); + fprintf(stderr," %s [parameters] -connect " + "[-view-only] [:]\n", programName); fprintf(stderr," %s [parameters] -disconnect\n", programName); fprintf(stderr," %s [parameters] [-set] = ...\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 #include +#include + #include #include 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* sockets, - SocketServer* sockserv) + VNCServer* sockserv) { std::list::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 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* 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 #include + +#include + #include #include +#include #include 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::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::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 -#include #include +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);