KasmVNC/unix/xserver/hw/vnc/vncExt.c
2020-09-20 12:16:44 +00:00

606 lines
14 KiB
C

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2015 Pierre Ossman for Cendio AB
*
* 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#define NEED_EVENTS
#include "misc.h"
#include "os.h"
#include "dixstruct.h"
#include "extnsionst.h"
#include "scrnintstr.h"
#define _VNCEXT_SERVER_
#define _VNCEXT_PROTO_
#include "vncExt.h"
#include "xorg-version.h"
#include "vncExtInit.h"
#include "RFBGlue.h"
static int ProcVncExtDispatch(ClientPtr client);
static int SProcVncExtDispatch(ClientPtr client);
static void vncResetProc(ExtensionEntry* extEntry);
static void vncClientStateChange(CallbackListPtr*, void *, void *);
static int vncErrorBase = 0;
static int vncEventBase = 0;
int vncNoClipboard = 0;
static struct VncInputSelect* vncInputSelectHead = NULL;
struct VncInputSelect {
ClientPtr client;
Window window;
int mask;
struct VncInputSelect* next;
};
void vncAddExtension(void)
{
ExtensionEntry* extEntry;
extEntry = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors,
ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc,
StandardMinorOpcode);
if (!extEntry) {
FatalError("vncAddExtension: AddExtension failed\n");
}
vncErrorBase = extEntry->errorBase;
vncEventBase = extEntry->eventBase;
if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) {
FatalError("Add ClientStateCallback failed\n");
}
}
int vncNotifyQueryConnect(void)
{
int count;
xVncExtQueryConnectNotifyEvent ev;
ev.type = vncEventBase + VncExtQueryConnectNotify;
count = 0;
for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
if (cur->mask & VncExtQueryConnectMask) {
ev.sequenceNumber = cur->client->sequence;
ev.window = cur->window;
if (cur->client->swapped) {
#if XORG < 112
int n;
swaps(&ev.sequenceNumber, n);
swapl(&ev.window, n);
#else
swaps(&ev.sequenceNumber);
swapl(&ev.window);
#endif
}
WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent),
(char *)&ev);
count++;
}
}
return count;
}
static int ProcVncExtSetParam(ClientPtr client)
{
char *param;
xVncExtSetParamReply rep;
REQUEST(xVncExtSetParamReq);
REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen);
param = malloc(stuff->paramLen+1);
if (param == NULL)
return BadAlloc;
strncpy(param, (char*)&stuff[1], stuff->paramLen);
param[stuff->paramLen] = '\0';
rep.type = X_Reply;
rep.length = 0;
rep.success = 0;
rep.sequenceNumber = client->sequence;
/*
* Prevent change of clipboard related parameters if clipboard is disabled.
*/
if (vncNoClipboard &&
(strncasecmp(param, "SendCutText", 11) == 0 ||
strncasecmp(param, "AcceptCutText", 13) == 0))
goto deny;
if (!vncOverrideParam(param))
goto deny;
rep.success = 1;
// Send DesktopName update if desktop name has been changed
if (strncasecmp(param, "desktop", 7) == 0)
vncUpdateDesktopName();
deny:
free(param);
if (client->swapped) {
#if XORG < 112
int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
#else
swaps(&rep.sequenceNumber);
swapl(&rep.length);
#endif
}
WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep);
return (client->noClientException);
}
static int SProcVncExtSetParam(ClientPtr client)
{
REQUEST(xVncExtSetParamReq);
#if XORG < 112
register char n;
swaps(&stuff->length, n);
#else
swaps(&stuff->length);
#endif
REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq);
return ProcVncExtSetParam(client);
}
static int ProcVncExtGetParam(ClientPtr client)
{
char* param;
char* value;
size_t len;
xVncExtGetParamReply rep;
REQUEST(xVncExtGetParamReq);
REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen);
param = malloc(stuff->paramLen+1);
if (param == NULL)
return BadAlloc;
strncpy(param, (char*)&stuff[1], stuff->paramLen);
param[stuff->paramLen] = 0;
value = vncGetParam(param);
len = value ? strlen(value) : 0;
free(param);
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.success = 0;
if (value)
rep.success = 1;
rep.length = (len + 3) >> 2;
rep.valueLen = len;
if (client->swapped) {
#if XORG < 112
int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.valueLen, n);
#else
swaps(&rep.sequenceNumber);
swapl(&rep.length);
swaps(&rep.valueLen);
#endif
}
WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep);
if (value)
WriteToClient(client, len, value);
free(value);
return (client->noClientException);
}
static int SProcVncExtGetParam(ClientPtr client)
{
REQUEST(xVncExtGetParamReq);
#if XORG < 112
register char n;
swaps(&stuff->length, n);
#else
swaps(&stuff->length);
#endif
REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq);
return ProcVncExtGetParam(client);
}
static int ProcVncExtGetParamDesc(ClientPtr client)
{
char* param;
const char* desc;
size_t len;
xVncExtGetParamDescReply rep;
REQUEST(xVncExtGetParamDescReq);
REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen);
param = malloc(stuff->paramLen+1);
if (param == NULL)
return BadAlloc;
strncpy(param, (char*)&stuff[1], stuff->paramLen);
param[stuff->paramLen] = 0;
desc = vncGetParamDesc(param);
len = desc ? strlen(desc) : 0;
free(param);
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.success = 0;
if (desc)
rep.success = 1;
rep.length = (len + 3) >> 2;
rep.descLen = len;
if (client->swapped) {
#if XORG < 112
int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.descLen, n);
#else
swaps(&rep.sequenceNumber);
swapl(&rep.length);
swaps(&rep.descLen);
#endif
}
WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep);
if (desc)
WriteToClient(client, len, desc);
return (client->noClientException);
}
static int SProcVncExtGetParamDesc(ClientPtr client)
{
REQUEST(xVncExtGetParamDescReq);
#if XORG < 112
register char n;
swaps(&stuff->length, n);
#else
swaps(&stuff->length);
#endif
REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq);
return ProcVncExtGetParamDesc(client);
}
static int ProcVncExtListParams(ClientPtr client)
{
xVncExtListParamsReply rep;
char *params;
size_t len;
REQUEST_SIZE_MATCH(xVncExtListParamsReq);
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
params = vncGetParamList();
if (params == NULL)
return BadAlloc;
len = strlen(params);
rep.length = (len + 3) >> 2;
rep.nParams = vncGetParamCount();
if (client->swapped) {
#if XORG < 112
int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.nParams, n);
#else
swaps(&rep.sequenceNumber);
swapl(&rep.length);
swaps(&rep.nParams);
#endif
}
WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
WriteToClient(client, len, (char*)params);
free(params);
return (client->noClientException);
}
static int SProcVncExtListParams(ClientPtr client)
{
REQUEST(xVncExtListParamsReq);
#if XORG < 112
register char n;
swaps(&stuff->length, n);
#else
swaps(&stuff->length);
#endif
REQUEST_SIZE_MATCH(xVncExtListParamsReq);
return ProcVncExtListParams(client);
}
static int ProcVncExtSelectInput(ClientPtr client)
{
struct VncInputSelect** nextPtr;
struct VncInputSelect* cur;
REQUEST(xVncExtSelectInputReq);
REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
nextPtr = &vncInputSelectHead;
for (cur = vncInputSelectHead; cur; cur = *nextPtr) {
if (cur->client == client && cur->window == stuff->window) {
cur->mask = stuff->mask;
if (!cur->mask) {
*nextPtr = cur->next;
free(cur);
}
break;
}
nextPtr = &cur->next;
}
if (!cur) {
cur = malloc(sizeof(struct VncInputSelect));
if (cur == NULL)
return BadAlloc;
memset(cur, 0, sizeof(struct VncInputSelect));
cur->client = client;
cur->window = stuff->window;
cur->mask = stuff->mask;
cur->next = vncInputSelectHead;
vncInputSelectHead = cur;
}
return (client->noClientException);
}
static int SProcVncExtSelectInput(ClientPtr client)
{
REQUEST(xVncExtSelectInputReq);
#if XORG < 112
register char n;
swaps(&stuff->length, n);
#else
swaps(&stuff->length);
#endif
REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
#if XORG < 112
swapl(&stuff->window, n);
swapl(&stuff->mask, n);
#else
swapl(&stuff->window);
swapl(&stuff->mask);
#endif
return ProcVncExtSelectInput(client);
}
static int ProcVncExtConnect(ClientPtr client)
{
char *address;
xVncExtConnectReply rep;
REQUEST(xVncExtConnectReq);
REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen);
address = malloc(stuff->strLen+1);
if (address == NULL)
return BadAlloc;
strncpy(address, (char*)&stuff[1], stuff->strLen);
address[stuff->strLen] = 0;
rep.success = 0;
if (vncConnectClient(address) == 0)
rep.success = 1;
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
if (client->swapped) {
#if XORG < 112
int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
#else
swaps(&rep.sequenceNumber);
swapl(&rep.length);
#endif
}
WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep);
free(address);
return (client->noClientException);
}
static int SProcVncExtConnect(ClientPtr client)
{
REQUEST(xVncExtConnectReq);
#if XORG < 112
register char n;
swaps(&stuff->length, n);
#else
swaps(&stuff->length);
#endif
REQUEST_AT_LEAST_SIZE(xVncExtConnectReq);
return ProcVncExtConnect(client);
}
static int ProcVncExtGetQueryConnect(ClientPtr client)
{
uint32_t opaqueId;
const char *qcAddress, *qcUsername;
int qcTimeout;
xVncExtGetQueryConnectReply rep;
REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
vncGetQueryConnect(&opaqueId, &qcAddress, &qcUsername, &qcTimeout);
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.timeout = qcTimeout;
rep.addrLen = qcTimeout ? strlen(qcAddress) : 0;
rep.userLen = qcTimeout ? strlen(qcUsername) : 0;
rep.opaqueId = (CARD32)(long)opaqueId;
rep.length = ((rep.userLen + 3) >> 2) + ((rep.addrLen + 3) >> 2);
if (client->swapped) {
#if XORG < 112
int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.addrLen, n);
swapl(&rep.userLen, n);
swapl(&rep.timeout, n);
swapl(&rep.opaqueId, n);
swapl(&rep.length, n);
#else
swaps(&rep.sequenceNumber);
swapl(&rep.addrLen);
swapl(&rep.userLen);
swapl(&rep.timeout);
swapl(&rep.opaqueId);
swapl(&rep.length);
#endif
}
WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep);
if (qcTimeout)
WriteToClient(client, strlen(qcAddress), qcAddress);
if (qcTimeout)
WriteToClient(client, strlen(qcUsername), qcUsername);
return (client->noClientException);
}
static int SProcVncExtGetQueryConnect(ClientPtr client)
{
REQUEST(xVncExtGetQueryConnectReq);
#if XORG < 112
register char n;
swaps(&stuff->length, n);
#else
swaps(&stuff->length);
#endif
REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
return ProcVncExtGetQueryConnect(client);
}
static int ProcVncExtApproveConnect(ClientPtr client)
{
REQUEST(xVncExtApproveConnectReq);
REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
vncApproveConnection(stuff->opaqueId, stuff->approve);
// Inform other clients of the event and tidy up
vncNotifyQueryConnect();
return (client->noClientException);
}
static int SProcVncExtApproveConnect(ClientPtr client)
{
REQUEST(xVncExtApproveConnectReq);
#if XORG < 112
register char n;
swaps(&stuff->length, n);
swapl(&stuff->opaqueId, n);
#else
swaps(&stuff->length);
swapl(&stuff->opaqueId);
#endif
REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
return ProcVncExtApproveConnect(client);
}
static int ProcVncExtDispatch(ClientPtr client)
{
REQUEST(xReq);
switch (stuff->data) {
case X_VncExtSetParam:
return ProcVncExtSetParam(client);
case X_VncExtGetParam:
return ProcVncExtGetParam(client);
case X_VncExtGetParamDesc:
return ProcVncExtGetParamDesc(client);
case X_VncExtListParams:
return ProcVncExtListParams(client);
case X_VncExtSelectInput:
return ProcVncExtSelectInput(client);
case X_VncExtConnect:
return ProcVncExtConnect(client);
case X_VncExtGetQueryConnect:
return ProcVncExtGetQueryConnect(client);
case X_VncExtApproveConnect:
return ProcVncExtApproveConnect(client);
default:
return BadRequest;
}
}
static int SProcVncExtDispatch(ClientPtr client)
{
REQUEST(xReq);
switch (stuff->data) {
case X_VncExtSetParam:
return SProcVncExtSetParam(client);
case X_VncExtGetParam:
return SProcVncExtGetParam(client);
case X_VncExtGetParamDesc:
return SProcVncExtGetParamDesc(client);
case X_VncExtListParams:
return SProcVncExtListParams(client);
case X_VncExtSelectInput:
return SProcVncExtSelectInput(client);
case X_VncExtConnect:
return SProcVncExtConnect(client);
case X_VncExtGetQueryConnect:
return SProcVncExtGetQueryConnect(client);
case X_VncExtApproveConnect:
return SProcVncExtApproveConnect(client);
default:
return BadRequest;
}
}
static void vncResetProc(ExtensionEntry* extEntry)
{
vncExtensionClose();
}
static void vncClientStateChange(CallbackListPtr * l, void * d, void * p)
{
ClientPtr client = ((NewClientInfoRec*)p)->client;
if (client->clientState == ClientStateGone) {
struct VncInputSelect** nextPtr = &vncInputSelectHead;
for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) {
if (cur->client == client) {
*nextPtr = cur->next;
free(cur);
continue;
}
nextPtr = &cur->next;
}
}
}