diff --git a/common/network/Socket.h b/common/network/Socket.h index 117851c191..7085d73a15 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 0000000000..65e6ce24f3 --- /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 0000000000..adf4393d29 --- /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 2cae2356c8..360434a9f1 100644 --- a/common/rfb/CMakeLists.txt +++ b/common/rfb/CMakeLists.txt @@ -1,4 +1,5 @@ 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 33b2d850e6..7a930af560 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -43,24 +43,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), hasRemoteClipboard(false), + accessRights(accessRights), hasRemoteClipboard(false), hasLocalClipboard(false), unsolicitedClipboardAttempt(false) { @@ -254,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 b163d6273e..cc88cd1e64 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -42,7 +43,7 @@ namespace rfb { class SConnection : public SMsgHandler { public: - SConnection(); + SConnection(AccessRights accessRights); virtual ~SConnection(); // Methods to initialise the connection @@ -175,20 +176,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 uint16_t 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 fbc3de6f97..8e296c5ac9 100644 --- a/common/rfb/SSecurity.h +++ b/common/rfb/SSecurity.h @@ -62,7 +62,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 2a8dfa3eb7..cea6264411 100644 --- a/common/rfb/SSecurityRSAAES.cxx +++ b/common/rfb/SSecurityRSAAES.cxx @@ -76,7 +76,7 @@ SSecurityRSAAES::SSecurityRSAAES(SConnection* sc, uint32_t _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); @@ -578,12 +578,12 @@ void SSecurityRSAAES::verifyPass() throw AuthFailureException("No password configured for VNC Auth"); if (password == passwd) { - accessRights = SConnection::AccessDefault; + accessRights = AccessDefault; return; } if (!passwdReadOnly.empty() && password == passwdReadOnly) { - accessRights = SConnection::AccessView; + accessRights = AccessView; return; } diff --git a/common/rfb/SSecurityRSAAES.h b/common/rfb/SSecurityRSAAES.h index eaeb13a17c..0c4fc85258 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 { char username[256]; char password[256]; - SConnection::AccessRights accessRights; + AccessRights accessRights; rdr::InStream* rais; rdr::OutStream* raos; diff --git a/common/rfb/SSecurityStack.cxx b/common/rfb/SSecurityStack.cxx index 8b1c2a47b1..9c0321d421 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 8b412bdf73..cf7b10d0e1 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 c126d82fdc..2813f29971 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 86cf420a7f..91713f8902 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 cbd0ccd2f9..c1ef1f1c04 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,13 +103,13 @@ bool SSecurityVncAuth::processMsg() throw AuthFailureException("No password configured for VNC Auth"); if (verifyResponse(passwd.c_str())) { - accessRights = SConnection::AccessDefault; + accessRights = AccessDefault; return true; } if (!passwdReadOnly.empty() && verifyResponse(passwdReadOnly.c_str())) { - accessRights = SConnection::AccessView; + accessRights = AccessView; return true; } diff --git a/common/rfb/SSecurityVncAuth.h b/common/rfb/SSecurityVncAuth.h index 2bd27791f7..7f27b02bfa 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 { uint8_t 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 906f5f66c1..f1194eb69a 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 edc0391edc..2f117a7579 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 3f97634b1d..cf14bd8621 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 560a0ffadf..fb4210680c 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -55,6 +55,8 @@ #include #include +#include + #include #include #include @@ -128,9 +130,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++; @@ -680,7 +680,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; @@ -693,7 +693,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 f688b317ad..d303831e8d 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 40e3abfc1e..388dcc9559 100644 --- a/tests/perf/encperf.cxx +++ b/tests/perf/encperf.cxx @@ -41,6 +41,8 @@ #include #include +#include + #include #include @@ -134,7 +136,7 @@ class SConn : public rfb::SConnection { 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) +void SConn::setAccessRights(rfb::AccessRights) { } 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..e0c9928a92 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); @@ -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 ed9ddda4b1..b07c02f463 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 b3d5e54c48..da298d3562 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 b5a5867182..4cf37937ba 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 677097a6e6..9cc5bf792e 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 @@ 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 @@ -107,9 +107,9 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, 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 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); diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx index b7cc1cce63..8e88b79b83 100644 --- a/win/rfb_win32/SocketManager.cxx +++ b/win/rfb_win32/SocketManager.cxx @@ -24,8 +24,12 @@ #include #include + +#include + #include #include +#include #include #include @@ -55,7 +59,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; @@ -103,7 +107,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)) { @@ -135,7 +139,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++) { @@ -146,7 +150,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 e5ca02e64a..809c470efa 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 a93ca298d0..1a278678b3 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 39223c7954..20503c3310 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 a243d95e19..38b2ef16ed 100644 --- a/win/winvnc/VNCServerWin32.cxx +++ b/win/winvnc/VNCServerWin32.cxx @@ -363,11 +363,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; @@ -398,25 +398,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);