mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2024-11-25 01:24:04 +01:00
Add support for relaying unix sockets
This commit is contained in:
parent
61613c4e65
commit
3bae812364
@ -88,6 +88,9 @@ namespace rfb {
|
||||
|
||||
virtual void clearLocalClipboards() {}
|
||||
|
||||
virtual void receivedUnixRelayData(const char name[], const unsigned char *buf,
|
||||
const unsigned len) {}
|
||||
|
||||
protected:
|
||||
virtual ~SDesktop() {}
|
||||
};
|
||||
|
@ -98,6 +98,9 @@ namespace rfb {
|
||||
virtual void udpUpgrade(const char *resp) = 0;
|
||||
virtual void udpDowngrade(const bool) = 0;
|
||||
|
||||
virtual void subscribeUnixRelay(const char *name) = 0;
|
||||
virtual void unixRelay(const char *name, const rdr::U8 *buf, const unsigned len) = 0;
|
||||
|
||||
ConnParams cp;
|
||||
};
|
||||
}
|
||||
|
@ -100,6 +100,12 @@ void SMsgReader::readMsg()
|
||||
case msgTypeUpgradeToUdp:
|
||||
readUpgradeToUdp();
|
||||
break;
|
||||
case msgTypeSubscribeUnixRelay:
|
||||
readSubscribeUnixRelay();
|
||||
break;
|
||||
case msgTypeUnixRelay:
|
||||
readUnixRelay();
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown message type %d\n", msgType);
|
||||
throw Exception("unknown message type");
|
||||
@ -357,3 +363,42 @@ void SMsgReader::readUpgradeToUdp()
|
||||
|
||||
handler->udpUpgrade(resp);
|
||||
}
|
||||
|
||||
void SMsgReader::readSubscribeUnixRelay()
|
||||
{
|
||||
const rdr::U8 namelen = is->readU8();
|
||||
char name[64];
|
||||
if (namelen >= sizeof(name)) {
|
||||
vlog.error("Ignoring subscribe with too large name");
|
||||
is->skip(namelen);
|
||||
return;
|
||||
}
|
||||
is->readBytes(name, namelen);
|
||||
name[namelen] = '\0';
|
||||
|
||||
handler->subscribeUnixRelay(name);
|
||||
}
|
||||
|
||||
void SMsgReader::readUnixRelay()
|
||||
{
|
||||
const rdr::U8 namelen = is->readU8();
|
||||
char name[64];
|
||||
if (namelen >= sizeof(name)) {
|
||||
vlog.error("Ignoring relay packet with too large name");
|
||||
is->skip(namelen);
|
||||
return;
|
||||
}
|
||||
is->readBytes(name, namelen);
|
||||
name[namelen] = '\0';
|
||||
|
||||
const rdr::U32 len = is->readU32();
|
||||
rdr::U8 buf[1024 * 1024];
|
||||
if (len >= sizeof(buf)) {
|
||||
vlog.error("Ignoring relay packet with too large data");
|
||||
is->skip(len);
|
||||
return ;
|
||||
}
|
||||
is->readBytes(buf, len);
|
||||
|
||||
handler->unixRelay(name, buf, len);
|
||||
}
|
||||
|
@ -65,6 +65,9 @@ namespace rfb {
|
||||
|
||||
void readUpgradeToUdp();
|
||||
|
||||
void readSubscribeUnixRelay();
|
||||
void readUnixRelay();
|
||||
|
||||
SMsgHandler* handler;
|
||||
rdr::InStream* is;
|
||||
};
|
||||
|
@ -749,3 +749,29 @@ void SMsgWriter::writeUdpUpgrade(const char *resp)
|
||||
|
||||
endMsg();
|
||||
}
|
||||
|
||||
void SMsgWriter::writeSubscribeUnixRelay(const bool success, const char *msg)
|
||||
{
|
||||
startMsg(msgTypeSubscribeUnixRelay);
|
||||
|
||||
const rdr::U8 len = strlen(msg);
|
||||
os->writeU8(success);
|
||||
os->writeU8(len);
|
||||
os->writeBytes(msg, len);
|
||||
|
||||
endMsg();
|
||||
}
|
||||
|
||||
void SMsgWriter::writeUnixRelay(const char *name, const rdr::U8 *buf, const unsigned len)
|
||||
{
|
||||
startMsg(msgTypeUnixRelay);
|
||||
|
||||
const rdr::U8 namelen = strlen(name);
|
||||
os->writeU8(namelen);
|
||||
os->writeBytes(name, namelen);
|
||||
|
||||
os->writeU32(len);
|
||||
os->writeBytes(buf, len);
|
||||
|
||||
endMsg();
|
||||
}
|
||||
|
@ -129,6 +129,9 @@ namespace rfb {
|
||||
|
||||
void writeUdpUpgrade(const char *resp);
|
||||
|
||||
void writeSubscribeUnixRelay(const bool success, const char *msg);
|
||||
void writeUnixRelay(const char *name, const rdr::U8 *buf, const unsigned len);
|
||||
|
||||
protected:
|
||||
void startMsg(int type);
|
||||
void endMsg();
|
||||
|
@ -51,6 +51,8 @@ static Cursor emptyCursor(0, 0, Point(0, 0), NULL);
|
||||
|
||||
extern rfb::BoolParameter disablebasicauth;
|
||||
|
||||
extern "C" char unixrelaynames[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN];
|
||||
|
||||
VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
||||
bool reverse)
|
||||
: upgradingToUdp(false), sock(s), reverseConnection(reverse),
|
||||
@ -73,6 +75,10 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
||||
memset(bstats_total, 0, sizeof(bstats_total));
|
||||
gettimeofday(&connStart, NULL);
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < MAX_UNIX_RELAYS; i++)
|
||||
unixRelaySubscriptions[i][0] = '\0';
|
||||
|
||||
// Check their permissions, if applicable
|
||||
kasmpasswdpath[0] = '\0';
|
||||
wordexp_t wexp;
|
||||
@ -1780,3 +1786,54 @@ void VNCSConnectionST::udpDowngrade(const bool byServer)
|
||||
vlog.info("Client %s downgrading from udp by %s", sock->getPeerAddress(),
|
||||
byServer ? "the server" : "its own request");
|
||||
}
|
||||
|
||||
void VNCSConnectionST::subscribeUnixRelay(const char *name)
|
||||
{
|
||||
bool read, write, owner;
|
||||
if (!getPerms(read, write, owner) || !write) {
|
||||
// Need write permissions to subscribe
|
||||
writer()->writeSubscribeUnixRelay(false, "No permissions");
|
||||
vlog.info("Client tried to subscribe to unix channel %s without permissions", name);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
bool found = false;
|
||||
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
|
||||
if (!strcmp(name, unixrelaynames[i])) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
writer()->writeSubscribeUnixRelay(false, "No such unix channel");
|
||||
vlog.info("Client tried to subscribe to nonexistent unix channel %s", name);
|
||||
return;
|
||||
}
|
||||
|
||||
writer()->writeSubscribeUnixRelay(true, "Ok");
|
||||
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
|
||||
if (!unixRelaySubscriptions[i][0]) {
|
||||
strcpy(unixRelaySubscriptions[i], name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VNCSConnectionST::unixRelay(const char *name, const rdr::U8 *buf, const unsigned len)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
|
||||
if (!strcmp(unixRelaySubscriptions[i], name)) {
|
||||
server->desktop->receivedUnixRelayData(name, buf, len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VNCSConnectionST::sendUnixRelayData(const char name[], const unsigned char *buf,
|
||||
const unsigned len)
|
||||
{
|
||||
writer()->writeUnixRelay(name, buf, len);
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <rfb/EncodeManager.h>
|
||||
#include <rfb/SConnection.h>
|
||||
#include <rfb/Timer.h>
|
||||
#include <rfb/unixRelayLimits.h>
|
||||
|
||||
namespace rfb {
|
||||
class VNCServerST;
|
||||
@ -200,6 +201,18 @@ namespace rfb {
|
||||
|
||||
bool upgradingToUdp;
|
||||
|
||||
bool isSubscribedToUnixRelay(const char *name) const {
|
||||
unsigned i;
|
||||
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
|
||||
if (!strcmp(unixRelaySubscriptions[i], name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void sendUnixRelayData(const char name[], const unsigned char *buf,
|
||||
const unsigned len);
|
||||
|
||||
private:
|
||||
// SConnection callbacks
|
||||
|
||||
@ -222,6 +235,8 @@ namespace rfb {
|
||||
virtual void handleClipboardAnnounce(bool available);
|
||||
virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
||||
virtual void udpUpgrade(const char *resp);
|
||||
virtual void subscribeUnixRelay(const char *name);
|
||||
virtual void unixRelay(const char *name, const rdr::U8 *buf, const unsigned len);
|
||||
virtual void supportsLocalCursor();
|
||||
virtual void supportsFence();
|
||||
virtual void supportsContinuousUpdates();
|
||||
@ -324,6 +339,8 @@ namespace rfb {
|
||||
|
||||
bool frameTracking;
|
||||
uint32_t udpFramesSinceFull;
|
||||
|
||||
char unixRelaySubscriptions[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN];
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -1244,3 +1244,15 @@ void VNCServerST::refreshClients()
|
||||
(*i)->add_changed_all();
|
||||
}
|
||||
}
|
||||
|
||||
void VNCServerST::sendUnixRelayData(const char name[],
|
||||
const unsigned char *buf, const unsigned len)
|
||||
{
|
||||
// For each client subscribed to this channel, send the data to them
|
||||
std::list<VNCSConnectionST*>::iterator i;
|
||||
for (i = clients.begin(); i != clients.end(); i++) {
|
||||
if ((*i)->isSubscribedToUnixRelay(name)) {
|
||||
(*i)->sendUnixRelayData(name, buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -198,6 +198,7 @@ namespace rfb {
|
||||
const char mimes[][32]);
|
||||
|
||||
void refreshClients();
|
||||
void sendUnixRelayData(const char name[], const unsigned char *buf, const unsigned len);
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -33,6 +33,8 @@ namespace rfb {
|
||||
const int msgTypeRequestFrameStats = 179;
|
||||
const int msgTypeBinaryClipboard = 180;
|
||||
const int msgTypeUpgradeToUdp = 181;
|
||||
const int msgTypeSubscribeUnixRelay = 182;
|
||||
const int msgTypeUnixRelay = 183;
|
||||
|
||||
const int msgTypeServerFence = 248;
|
||||
|
||||
@ -54,6 +56,8 @@ namespace rfb {
|
||||
// same as the other direction
|
||||
//const int msgTypeBinaryClipboard = 180;
|
||||
//const int msgTypeUpgradeToUdp = 181;
|
||||
//const int msgTypeSubscribeUnixRelay = 182;
|
||||
//const int msgTypeUnixRelay = 183;
|
||||
|
||||
const int msgTypeClientFence = 248;
|
||||
|
||||
|
7
common/rfb/unixRelayLimits.h
Normal file
7
common/rfb/unixRelayLimits.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef UNIX_RELAY_LIMITS_H
|
||||
#define UNIX_RELAY_LIMITS_H
|
||||
|
||||
#define MAX_UNIX_RELAYS 4
|
||||
#define MAX_UNIX_RELAY_NAME_LEN 64
|
||||
|
||||
#endif
|
@ -29,6 +29,8 @@
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
@ -51,6 +53,7 @@ extern "C" {
|
||||
void vncSetGlueContext(int screenIndex);
|
||||
|
||||
extern int wakeuppipe[2];
|
||||
extern struct sockaddr_un unixrelayclients[MAX_UNIX_RELAYS];
|
||||
}
|
||||
|
||||
using namespace rfb;
|
||||
@ -323,6 +326,26 @@ void XserverDesktop::handleSocketEvent(int fd, bool read, bool write)
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
|
||||
if (unixrelays[i] == -1)
|
||||
break;
|
||||
if (fd == unixrelays[i]) {
|
||||
do {
|
||||
struct sockaddr_un client;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_un);
|
||||
const ssize_t len = recvfrom(unixrelays[i], unixbuf, sizeof(unixbuf),
|
||||
MSG_DONTWAIT,
|
||||
(struct sockaddr *) &client, &addrlen);
|
||||
if (len <= 0)
|
||||
break;
|
||||
memcpy(&unixrelayclients[i], &client, addrlen);
|
||||
server->sendUnixRelayData(unixrelaynames[i], unixbuf, len);
|
||||
} while (1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (handleListenerEvent(fd, &listeners, server))
|
||||
return;
|
||||
}
|
||||
@ -557,3 +580,21 @@ bool XserverDesktop::handleTimeout(Timer* t)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void XserverDesktop::receivedUnixRelayData(const char name[], const unsigned char *buf,
|
||||
const unsigned len)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
|
||||
if (unixrelays[i] == -1)
|
||||
break;
|
||||
if (strcmp(name, unixrelaynames[i]))
|
||||
continue;
|
||||
|
||||
if (sendto(unixrelays[i], buf, len, 0,
|
||||
(struct sockaddr *) &unixrelayclients[i], sizeof(struct sockaddr_un)) == -1)
|
||||
vlog.error("Error writing unix relay data to %s", name);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,9 @@ public:
|
||||
const char* userName,
|
||||
char** reason);
|
||||
|
||||
virtual void receivedUnixRelayData(const char name[], const unsigned char *buf,
|
||||
const unsigned len);
|
||||
|
||||
protected:
|
||||
bool handleListenerEvent(int fd,
|
||||
std::list<network::SocketListener*>* sockets,
|
||||
@ -138,5 +141,7 @@ private:
|
||||
rfb::Point oldCursorPos;
|
||||
|
||||
bool resizing;
|
||||
|
||||
uint8_t unixbuf[1024 * 1024];
|
||||
};
|
||||
#endif
|
||||
|
@ -89,6 +89,11 @@ Use IPv4 for incoming and outgoing connections. Default is on.
|
||||
Use IPv6 for incoming and outgoing connections. Default is on.
|
||||
.
|
||||
.TP
|
||||
.B \-UnixRelay \fIname:path\fP
|
||||
Create a local named unix socket, for relaying data. May be given multiple times.
|
||||
Example: -UnixRelay audio:/tmp/audiosock
|
||||
.
|
||||
.TP
|
||||
.B \-rfbunixpath \fIpath\fP
|
||||
Specifies the path of a Unix domain socket on which Xvnc listens for
|
||||
connections from viewers, instead of listening on a TCP port.
|
||||
|
@ -237,6 +237,14 @@ void vncExtensionInit(void)
|
||||
fcntl(wakeuppipe[0], F_SETFL, flags | O_NONBLOCK);
|
||||
vncSetNotifyFd(wakeuppipe[0], 0, true, false);
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
|
||||
if (unixrelays[i] == -1)
|
||||
break;
|
||||
vncSetNotifyFd(unixrelays[i], 0, true, false);
|
||||
vlog.info("Listening to unix relay socket %s", unixrelaynames[i]);
|
||||
}
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include <stddef.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <rfb/unixRelayLimits.h>
|
||||
|
||||
// Only from C++
|
||||
#ifdef __cplusplus
|
||||
namespace rfb { class StringParameter; };
|
||||
@ -106,6 +108,9 @@ void vncRefreshScreenLayout(int scrIdx);
|
||||
|
||||
int vncOverrideParam(const char *nameAndValue);
|
||||
|
||||
extern int unixrelays[MAX_UNIX_RELAYS];
|
||||
extern char unixrelaynames[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -61,8 +61,11 @@ from the X Consortium.
|
||||
#include "input.h"
|
||||
#include "mipointer.h"
|
||||
#include "micmap.h"
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifndef WIN32
|
||||
#include <sys/param.h>
|
||||
@ -155,6 +158,73 @@ static char displayNumStr[16];
|
||||
|
||||
static int vncVerbose = DEFAULT_LOG_VERBOSITY;
|
||||
|
||||
int unixrelays[MAX_UNIX_RELAYS];
|
||||
char unixrelaynames[MAX_UNIX_RELAYS][MAX_UNIX_RELAY_NAME_LEN];
|
||||
struct sockaddr_un unixrelayclients[MAX_UNIX_RELAYS];
|
||||
|
||||
static unsigned addrelay(const char * const arg)
|
||||
{
|
||||
const char *ptr = strchr(arg, ':');
|
||||
if (!ptr) {
|
||||
ErrorF("Invalid unixrelay\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const unsigned namelen = ptr - arg;
|
||||
if (namelen >= MAX_UNIX_RELAY_NAME_LEN) {
|
||||
ErrorF("Unix relay name too long\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
unsigned char found = 0;
|
||||
for (i = 0; i < MAX_UNIX_RELAYS; i++) {
|
||||
if (unixrelays[i] == -1) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ErrorF("Too many unix relays\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(unixrelaynames[i], arg, namelen);
|
||||
unixrelaynames[i][namelen] = '\0';
|
||||
|
||||
unixrelays[i] = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (unixrelays[i] < 0) {
|
||||
ErrorF("Failed to create unix sock\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
struct sockaddr_un sa;
|
||||
if (strlen(ptr) >= sizeof(sa.sun_path)) {
|
||||
ErrorF("Unix relay path too long\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sa.sun_family = AF_UNIX;
|
||||
strcpy(sa.sun_path, ptr);
|
||||
|
||||
// SO_REUSEADDR doesn't exist for unix sockets, if the socket exists
|
||||
// (from our previous run), we need to delete it first. Check it's a
|
||||
// socket so we don't delete wrong files
|
||||
struct stat st;
|
||||
if (stat(ptr, &st) == 0) {
|
||||
if (S_ISSOCK(st.st_mode))
|
||||
unlink(ptr);
|
||||
}
|
||||
|
||||
if (bind(unixrelays[i], (struct sockaddr *) &sa, sizeof(struct sockaddr_un))) {
|
||||
ErrorF("Failed to bind unix sock\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *extra_headers = NULL;
|
||||
unsigned extra_headers_len = 0;
|
||||
|
||||
@ -364,6 +434,7 @@ void ddxUseMsg(void)
|
||||
ErrorF("-inetd has been launched from inetd\n");
|
||||
ErrorF("-http-header name=val append this header to all HTTP responses\n");
|
||||
ErrorF("-noclipboard disable clipboard settings modification via vncconfig utility\n");
|
||||
ErrorF("-unixrelay name:path create a local named unix relay socket\n");
|
||||
ErrorF("-verbose [n] verbose startup messages\n");
|
||||
ErrorF("-quiet minimal startup messages\n");
|
||||
ErrorF("-version show the server version\n");
|
||||
@ -416,6 +487,13 @@ ddxProcessArgument(int argc, char *argv[], int i)
|
||||
|
||||
vfbInitializeDefaultScreens();
|
||||
vfbInitializePixmapDepths();
|
||||
|
||||
unsigned r;
|
||||
for (r = 0; r < MAX_UNIX_RELAYS; r++) {
|
||||
unixrelays[r] = -1;
|
||||
unixrelaynames[r][0] = '\0';
|
||||
}
|
||||
|
||||
firstTime = FALSE;
|
||||
vncInitRFB();
|
||||
}
|
||||
@ -668,6 +746,16 @@ ddxProcessArgument(int argc, char *argv[], int i)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[i], "-unixrelay") == 0)
|
||||
{
|
||||
fail_unless_args(argc, i, 1);
|
||||
++i;
|
||||
|
||||
if (addrelay(argv[i]))
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-verbose")) {
|
||||
if (++i < argc && argv[i]) {
|
||||
char *end;
|
||||
|
Loading…
Reference in New Issue
Block a user