Browse Source

vncconfig: add option to force view-only remote client connections

Specifies that the server must ignore all keyboard or mouse events sent
by the client.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2180903
Signed-off-by: Carlos Santos <casantos@redhat.com>
pull/1670/head
Carlos Santos 6 months ago
parent
commit
7597f8d42b

+ 3
- 3
common/rfb/SConnection.cxx View File



static LogWriter vlog("SConnection"); static LogWriter vlog("SConnection");


SConnection::SConnection()
SConnection::SConnection(AccessRights accessRights)
: readyForSetColourMapEntries(false), : readyForSetColourMapEntries(false),
is(0), os(0), reader_(0), writer_(0), ssecurity(0), is(0), os(0), reader_(0), writer_(0), ssecurity(0),
authFailureTimer(this, &SConnection::handleAuthFailureTimeout), authFailureTimer(this, &SConnection::handleAuthFailureTimeout),
state_(RFBSTATE_UNINITIALISED), preferredEncoding(encodingRaw), state_(RFBSTATE_UNINITIALISED), preferredEncoding(encodingRaw),
accessRights(AccessNone), hasRemoteClipboard(false),
accessRights(accessRights), hasRemoteClipboard(false),
hasLocalClipboard(false), hasLocalClipboard(false),
unsolicitedClipboardAttempt(false) unsolicitedClipboardAttempt(false)
{ {
} }


state_ = RFBSTATE_QUERYING; state_ = RFBSTATE_QUERYING;
setAccessRights(ssecurity->getAccessRights());
setAccessRights(accessRights & ssecurity->getAccessRights());
queryConnection(ssecurity->getUserName()); queryConnection(ssecurity->getUserName());


// If the connection got approved right away then we can continue // If the connection got approved right away then we can continue

+ 4
- 1
common/rfb/SConnection.h View File

class SConnection : public SMsgHandler { class SConnection : public SMsgHandler {
public: public:


SConnection();
SConnection(AccessRights accessRights);
virtual ~SConnection(); virtual ~SConnection();


// Methods to initialise the connection // Methods to initialise the connection
// clipboard via handleClipboardRequest(). // clipboard via handleClipboardRequest().
virtual void sendClipboardData(const char* data); 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 // setAccessRights() allows a security package to limit the access rights
// of a SConnection to the server. How the access rights are treated // of a SConnection to the server. How the access rights are treated
// is up to the derived class. // is up to the derived class.

+ 3
- 2
common/rfb/VNCSConnectionST.cxx View File

static Cursor emptyCursor(0, 0, Point(0, 0), NULL); static Cursor emptyCursor(0, 0, Point(0, 0), NULL);


VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, 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), inProcessMessages(false),
pendingSyncFence(false), syncFence(false), fenceFlags(0), pendingSyncFence(false), syncFence(false), fenceFlags(0),
fenceDataLen(0), fenceData(NULL), congestionTimer(this), fenceDataLen(0), fenceData(NULL), congestionTimer(this),

+ 2
- 1
common/rfb/VNCSConnectionST.h View File

class VNCSConnectionST : private SConnection, class VNCSConnectionST : private SConnection,
public Timer::Callback { public Timer::Callback {
public: public:
VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse);
VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse,
AccessRights ar);
virtual ~VNCSConnectionST(); virtual ~VNCSConnectionST();


// SConnection methods // SConnection methods

+ 3
- 1
common/rfb/VNCServer.h View File

// outgoing is set to true if the socket was created by connecting out // 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 // to another host, or false if the socket was created by accept()ing
// an incoming connection. // an incoming connection.
virtual void addSocket(network::Socket* sock, bool outgoing=false) = 0;
// accessRights allows to set the access rights to the server.
virtual void addSocket(network::Socket* sock, bool outgoing=false,
AccessRights accessRights = AccessDefault) = 0;


// removeSocket() tells the server to stop serving the Socket. The // removeSocket() tells the server to stop serving the Socket. The
// caller retains ownership of the Socket - the server must NOT // caller retains ownership of the Socket - the server must NOT

+ 2
- 2
common/rfb/VNCServerST.cxx View File



// VNCServer 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 // - Check the connection isn't black-marked
// *** do this in getSecurity instead? // *** do this in getSecurity instead?
connectTimer.start(secsToMillis(rfb::Server::maxConnectionTime)); connectTimer.start(secsToMillis(rfb::Server::maxConnectionTime));
disconnectTimer.stop(); disconnectTimer.stop();


VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing, accessRights);
clients.push_front(client); clients.push_front(client);
client->init(); client->init();
} }

+ 2
- 1
common/rfb/VNCServerST.h View File

// addSocket // addSocket
// Causes the server to allocate an RFB-protocol management // Causes the server to allocate an RFB-protocol management
// structure for the socket & initialise it. // 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 // removeSocket
// Clean up any resources associated with the Socket // Clean up any resources associated with the Socket

+ 3
- 0
tests/perf/encperf.cxx View File

#include <rdr/OutStream.h> #include <rdr/OutStream.h>
#include <rdr/FileInStream.h> #include <rdr/FileInStream.h>


#include <rfb/AccessRights.h>

#include <rfb/PixelFormat.h> #include <rfb/PixelFormat.h>


#include <rfb/CConnection.h> #include <rfb/CConnection.h>
} }


SConn::SConn() SConn::SConn()
: SConnection(rfb::AccessDefault)
{ {
out = new DummyOutStream; out = new DummyOutStream;
setStreams(NULL, out); setStreams(NULL, out);

+ 2
- 1
unix/vncconfig/vncExt.c View File

return True; return True;
} }


Bool XVncExtConnect(Display* dpy, const char* hostAndPort)
Bool XVncExtConnect(Display* dpy, const char* hostAndPort, Bool viewOnly)
{ {
xVncExtConnectReq* req; xVncExtConnectReq* req;
xVncExtConnectReply rep; xVncExtConnectReply rep;
req->vncExtReqType = X_VncExtConnect; req->vncExtReqType = X_VncExtConnect;
req->length += (strLen + 3) >> 2; req->length += (strLen + 3) >> 2;
req->strLen = strLen; req->strLen = strLen;
req->viewOnly = (CARD8)viewOnly;
Data(dpy, hostAndPort, strLen); Data(dpy, hostAndPort, strLen);
if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
UnlockDisplay(dpy); UnlockDisplay(dpy);

+ 2
- 2
unix/vncconfig/vncExt.h View File

char** XVncExtListParams(Display* dpy, int* nParams); char** XVncExtListParams(Display* dpy, int* nParams);
void XVncExtFreeParamList(char** list); void XVncExtFreeParamList(char** list);
Bool XVncExtSelectInput(Display* dpy, Window w, int mask); 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, Bool XVncExtGetQueryConnect(Display* dpy, char** addr,
char** user, int* timeout, void** opaqueId); char** user, int* timeout, void** opaqueId);
Bool XVncExtApproveConnect(Display* dpy, void* opaqueId, int approve); Bool XVncExtApproveConnect(Display* dpy, void* opaqueId, int approve);
CARD8 vncExtReqType; /* always VncExtConnect */ CARD8 vncExtReqType; /* always VncExtConnect */
CARD16 length B16; CARD16 length B16;
CARD8 strLen; CARD8 strLen;
CARD8 pad0;
CARD8 viewOnly;
CARD16 pad1 B16; CARD16 pad1 B16;
} xVncExtConnectReq; } xVncExtConnectReq;
#define sz_xVncExtConnectReq 8 #define sz_xVncExtConnectReq 8

+ 9
- 4
unix/vncconfig/vncconfig.cxx View File

{ {
fprintf(stderr,"usage: %s [parameters]\n", fprintf(stderr,"usage: %s [parameters]\n",
programName); programName);
fprintf(stderr," %s [parameters] -connect <host>[:<port>]\n",
programName);
fprintf(stderr," %s [parameters] -connect "
"[-view-only] <host>[:<port>]\n", programName);
fprintf(stderr," %s [parameters] -disconnect\n", programName); fprintf(stderr," %s [parameters] -disconnect\n", programName);
fprintf(stderr," %s [parameters] [-set] <Xvnc-param>=<value> ...\n", fprintf(stderr," %s [parameters] [-set] <Xvnc-param>=<value> ...\n",
programName); programName);
if (i < argc) { if (i < argc) {
for (; i < argc; i++) { for (; i < argc; i++) {
if (strcmp(argv[i], "-connect") == 0) { if (strcmp(argv[i], "-connect") == 0) {
Bool viewOnly = False;
i++; i++;
if (strcmp(argv[i], "-view-only") == 0) {
viewOnly = True;
i++;
}
if (i >= argc) usage(); if (i >= argc) usage();
if (!XVncExtConnect(dpy, argv[i])) {
if (!XVncExtConnect(dpy, argv[i], viewOnly)) {
fprintf(stderr,"connecting to %s failed\n",argv[i]); fprintf(stderr,"connecting to %s failed\n",argv[i]);
} }
} else if (strcmp(argv[i], "-disconnect") == 0) { } else if (strcmp(argv[i], "-disconnect") == 0) {
if (!XVncExtConnect(dpy, "")) {
if (!XVncExtConnect(dpy, "", False)) {
fprintf(stderr,"disconnecting all clients failed\n"); fprintf(stderr,"disconnecting all clients failed\n");
} }
} else if (strcmp(argv[i], "-get") == 0) { } else if (strcmp(argv[i], "-get") == 0) {

+ 4
- 3
unix/vncconfig/vncconfig.man View File

.br .br
.B vncconfig .B vncconfig
.RI [ parameters ] .RI [ parameters ]
.B \-connect
.B \-connect \fP[\fB-view-only\fP]
.IR host [: port ] .IR host [: port ]
.br .br
.B vncconfig .B vncconfig


.SH OPTIONS .SH OPTIONS
.TP .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 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 (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 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 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 .TP
.B \-disconnect .B \-disconnect

+ 2
- 2
unix/xserver/hw/vnc/XserverDesktop.cc View File

} }
} }


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); 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); vncSetNotifyFd(sock->getFd(), screenIndex, true, false);
} }



+ 1
- 1
unix/xserver/hw/vnc/XserverDesktop.h View File

void add_copied(const rfb::Region &dest, const rfb::Point &delta); void add_copied(const rfb::Region &dest, const rfb::Point &delta);
void handleSocketEvent(int fd, bool read, bool write); void handleSocketEvent(int fd, bool read, bool write);
void blockHandler(int* timeout); void blockHandler(int* timeout);
void addClient(network::Socket* sock, bool reverse);
void addClient(network::Socket* sock, bool reverse, bool viewOnly);
void disconnectClients(); void disconnectClients();


// QueryConnect methods called from X server code // QueryConnect methods called from X server code

+ 1
- 1
unix/xserver/hw/vnc/vncExt.c View File

address[stuff->strLen] = 0; address[stuff->strLen] = 0;


rep.success = 0; rep.success = 0;
if (vncConnectClient(address) == 0)
if (vncConnectClient(address, (int)stuff->viewOnly) == 0)
rep.success = 1; rep.success = 1;


rep.type = X_Reply; rep.type = X_Reply;

+ 5
- 3
unix/xserver/hw/vnc/vncExtInit.cc View File



if (scr == 0 && vncInetdSock != -1 && listeners.empty()) { if (scr == 0 && vncInetdSock != -1 && listeners.empty()) {
network::Socket* sock = new network::TcpSocket(vncInetdSock); network::Socket* sock = new network::TcpSocket(vncInetdSock);
desktop[scr]->addClient(sock, false);
desktop[scr]->addClient(sock, false, false);
vlog.info("added inetd sock"); vlog.info("added inetd sock");
} }
} }
desktop[scr]->sendClipboardData(data); desktop[scr]->sendClipboardData(data);
} }


int vncConnectClient(const char *addr)
int vncConnectClient(const char *addr, int viewOnly)
{ {
if (strlen(addr) == 0) { if (strlen(addr) == 0) {
try { try {


try { try {
network::Socket* sock = new network::TcpSocket(host.c_str(), port); 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) { } catch (rdr::Exception& e) {
vlog.error("Reverse connection: %s",e.str()); vlog.error("Reverse connection: %s",e.str());
return -1; return -1;

+ 1
- 1
unix/xserver/hw/vnc/vncExtInit.h View File

void vncAnnounceClipboard(int available); void vncAnnounceClipboard(int available);
void vncSendClipboardData(const char* data); 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, void vncGetQueryConnect(uint32_t *opaqueId, const char**username,
const char **address, int *timeout); const char **address, int *timeout);

Loading…
Cancel
Save