From 90947c1f7c5b345447a8b991e513a60c4f70fbdd Mon Sep 17 00:00:00 2001 From: Ulrich Sibiller Date: Mon, 26 Oct 2020 23:52:30 +0100 Subject: nxagent: add option -textclipboard textclipboard= in the options file --- nx-X11/programs/Xserver/hw/nxagent/Args.c | 19 ++ nx-X11/programs/Xserver/hw/nxagent/Clipboard.c | 228 ++++++++++++++++++++++- nx-X11/programs/Xserver/hw/nxagent/Options.c | 1 + nx-X11/programs/Xserver/hw/nxagent/Options.h | 7 + nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 | 13 ++ 5 files changed, 261 insertions(+), 7 deletions(-) diff --git a/nx-X11/programs/Xserver/hw/nxagent/Args.c b/nx-X11/programs/Xserver/hw/nxagent/Args.c index be13efacd..ea17e4813 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Args.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Args.c @@ -972,6 +972,12 @@ int ddxProcessArgument(int argc, char *argv[], int i) return 2; } + if (!strcmp(argv[i], "-textclipboard")) + { + nxagentChangeOption(TextClipboard, True); + return 1; + } + if (!strcmp(argv[i], "-bs")) { nxagentChangeOption(BackingStore, BackingStoreNever); @@ -1487,6 +1493,18 @@ static void nxagentParseSingleOption(char *name, char *value) } return; } + else if (!strcmp(name, "textclipboard")) + { + if (!strcmp(value, "0")) + { + nxagentChangeOption(TextClipboard, False); + } + else + { + nxagentChangeOption(TextClipboard, True); + } + return; + } else { #ifdef DEBUG @@ -2129,6 +2147,7 @@ void ddxUseMsg(void) ErrorF("-nokbreset don't reset keyboard device if the session is resumed\n"); ErrorF("-noxkblock always allow applications to change layout through XKEYBOARD\n"); ErrorF("-autograb enable autograb\n"); + ErrorF("-textclipboard limit clipboard data to text only\n"); ErrorF("-irlimit maximum image data rate to the encoder input in kB/s.\n"); ErrorF("-tile WxH maximum size of image tiles (minimum allowed: 32x32)\n"); ErrorF("-keystrokefile file file with keyboard shortcut definitions\n"); diff --git a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c index 28d56b758..fb2595e68 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c @@ -264,6 +264,7 @@ XFixesAgentInfoRec nxagentXFixesInfo = { -1, -1, -1, False }; extern Display *nxagentDisplay; +static Bool isTextTarget(XlibAtom target); static void setClientSelectionStage(int stage, int index); static void endTransfer(Bool success, int index); #define SELECTION_SUCCESS True @@ -562,6 +563,48 @@ static void sendSelectionNotifyEventToClient(ClientPtr client, sendEventToClient(client, &x); } +/* + * Check if target is a valid text content type target sent by the real X + * server, like .e.g XA_STRING or UTF8_STRING. + */ +static Bool isTextTarget(XlibAtom target) +{ + if (target == XA_STRING) + { + #ifdef DEBUG + fprintf(stderr, "%s: valid target [XA_STRING].\n", __func__); + #endif + return True; + } + else if (target == serverTEXT) + { + #ifdef DEBUG + fprintf(stderr, "%s: valid target [TEXT].\n", __func__); + #endif + return True; + } + else if (target == serverUTF8_STRING) + { + #ifdef DEBUG + fprintf(stderr, "%s: valid target [UTF8_STRING].\n", __func__); + #endif + return True; + } + else if (target == serverCOMPOUND_TEXT) + { + #ifdef DEBUG + fprintf(stderr, "%s: valid target [COMPOUND_TEXT].\n", __func__); + #endif + return True; + } + /* FIXME: add text/plain */ + + #ifdef DEBUG + fprintf(stderr, "%s: not a text target [%lu].\n", __func__, target); + #endif + return False; +} + static void initSelectionOwnerData(int index) { lastSelectionOwner[index].client = NullClient; @@ -806,7 +849,61 @@ void nxagentHandleSelectionRequestFromXServer(XEvent *X) return; } - if (X->xselectionrequest.target == serverTIMESTAMP) + if (X->xselectionrequest.target == serverTARGETS) + { + /* + * In TextClipboard mode answer with a predefined list of + * targets. This is just the previous implementation of handling + * the clipboard. + */ + if (nxagentOption(TextClipboard)) + { + /* + * the selection request target is TARGETS. The requestor is + * asking for a list of supported data formats. + * + * The selection does not matter here, we will return this for + * PRIMARY and CLIPBOARD. + * + * The list is aligned with the one in nxagentConvertSelection() + * and in isTextTarget(). + */ + + XlibAtom targets[] = {XA_STRING, serverUTF8_STRING, serverTEXT, serverCOMPOUND_TEXT, + serverTARGETS, serverTIMESTAMP}; + int numTargets = sizeof(targets) / sizeof(targets[0]); + + #ifdef DEBUG + fprintf(stderr, "%s: Sending %d available targets:\n", __func__, numTargets); + for (int i = 0; i < numTargets; i++) + { + fprintf(stderr, "%s: %ld %s\n", __func__, targets[i], NameForRemAtom(targets[i])); + } + fprintf(stderr, "\n"); + #endif + + /* + * pass on the requested list by setting the property provided + * by the requestor accordingly. + */ + XChangeProperty(nxagentDisplay, + X->xselectionrequest.requestor, + X->xselectionrequest.property, + XInternAtom(nxagentDisplay, "ATOM", 0), + 32, + PropModeReplace, + (unsigned char*)targets, + numTargets); + + replyRequestSelectionToXServer(X, True); + return; + } + else + { + /* do nothing, let TARGETS be passed on to the owner later */ + } + } + else if (X->xselectionrequest.target == serverTIMESTAMP) { /* * Section 2.6.2 of the ICCCM states: @@ -882,12 +979,28 @@ void nxagentHandleSelectionRequestFromXServer(XEvent *X) replyRequestSelectionToXServer(X, False); return; } - else + + if (nxagentOption(TextClipboard)) { - fprintf(stderr, "%s: target [%ld][%s].\n", __func__, X->xselectionrequest.target, - NameForRemAtom(X->xselectionrequest.target)); + if (!isTextTarget(X->xselectionrequest.target)) + { + #ifdef DEBUG + fprintf(stderr, "%s: denying request for non-text target [%ld][%s].\n", __func__, + X->xselectionrequest.target, NameForRemAtom(X->xselectionrequest.target)); + #endif + + replyRequestSelectionToXServer(X, False); + + return; + } + /* go on, target is acceptable */ } + #ifdef DEBUG + fprintf(stderr, "%s: target [%ld][%s].\n", __func__, X->xselectionrequest.target, + NameForRemAtom(X->xselectionrequest.target)); + #endif + /* * reaching this means the request is a normal, valid request. We * can process it now. @@ -967,12 +1080,34 @@ void nxagentHandleSelectionRequestFromXServer(XEvent *X) /* * Don't send the same window, some programs are clever and * verify cut and paste operations inside the same window and - * don't Notify at all. + * don't notify at all. * * x.u.selectionRequest.requestor = lastSelectionOwner[index].window; */ - x.u.selectionRequest.target = nxagentRemoteToLocalAtom(X->xselectionrequest.target); + /* + * if textclipboard is requested simply use the previous clipboard + * handling code + */ + if (nxagentOption(TextClipboard)) + { + /* by dimbor */ + if (X->xselectionrequest.target != XA_STRING) + { + lastServers[index].target = serverUTF8_STRING; + /* by dimbor (idea from zahvatov) */ + x.u.selectionRequest.target = clientUTF8_STRING; + } + else + { + x.u.selectionRequest.target = XA_STRING; + } + } + else + { + x.u.selectionRequest.target = nxagentRemoteToLocalAtom(X->xselectionrequest.target); + } + sendEventToClient(lastSelectionOwner[index].client, &x); #ifdef DEBUG @@ -2008,6 +2143,64 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, } } + /* + * The selection request target is TARGETS. The requestor is asking + * for a list of supported data formats. + */ + + if (target == clientTARGETS) + { + /* + * In TextClipboard mode answer with a predefined list that was used + * in in previous versions. + */ + if (nxagentOption(TextClipboard)) + { + /* + * The list is aligned with the one in + * nxagentHandleSelectionRequestFromXServer. + */ + Atom targets[] = {XA_STRING, + clientUTF8_STRING, +#if 0 + clientTEXT, + clientCOMPOUND_TEXT, +#endif + clientTARGETS, + clientTIMESTAMP}; + int numTargets = sizeof(targets) / sizeof(targets[0]); + + #ifdef DEBUG + fprintf(stderr, "%s: Sending %d available targets:\n", __func__, numTargets); + for (int i = 0; i < numTargets; i++) + { + fprintf(stderr, "%s: %d %s\n", __func__, targets[i], NameForIntAtom(targets[i])); + } + #endif + + ChangeWindowProperty(pWin, + property, + MakeAtom("ATOM", 4, 1), + sizeof(Atom)*8, + PropModeReplace, + numTargets, + targets, + 1); + + sendSelectionNotifyEventToClient(client, time, requestor, selection, + target, property); + + return 1; + } + else + { + /* + * do nothing - TARGETS will be handled like any other target + * and passed on to the owner on the remote side. + */ + } + } + /* * Section 2.6.2 of the ICCCM states: * "TIMESTAMP - To avoid some race conditions, it is important @@ -2018,7 +2211,7 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, * support conversion to TIMESTAMP, returning the timestamp they * used to obtain the selection." */ - if (target == clientTIMESTAMP) + else if (target == clientTIMESTAMP) { /* * "If the specified property is not None, the owner should place @@ -2087,6 +2280,27 @@ int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, return 1; } + /* in TextClipboard mode reject all non-text targets */ + if (nxagentOption(TextClipboard)) + { + if (!isTextTarget(translateLocalToRemoteTarget(target))) + { + #ifdef DEBUG + fprintf(stderr, "%s: denying request for non-text target [%d][%s].\n", __func__, + target, NameForIntAtom(target)); + #endif + + sendSelectionNotifyEventToClient(client, time, requestor, selection, target, None); + return 1; + } + /* go on, target is acceptable */ + } + + #ifdef DEBUG + fprintf(stderr, "%s: target [%d][%s].\n", __func__, target, + NameForIntAtom(target)); + #endif + if (lastClients[index].clientPtr == client) { if (GetTimeInMillis() - lastClients[index].reqTime < ACCUM_TIME) diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.c b/nx-X11/programs/Xserver/hw/nxagent/Options.c index be6e5d5e1..8e6249e4c 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Options.c +++ b/nx-X11/programs/Xserver/hw/nxagent/Options.c @@ -88,6 +88,7 @@ void nxagentInitOptions(void) nxagentOptions.BackingStore = BackingStoreUndefined; nxagentOptions.Clipboard = ClipboardBoth; + nxagentOptions.TextClipboard = False; nxagentOptions.SharedMemory = True; diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.h b/nx-X11/programs/Xserver/hw/nxagent/Options.h index a99f4aee2..d3c8c7150 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/Options.h +++ b/nx-X11/programs/Xserver/hw/nxagent/Options.h @@ -194,6 +194,13 @@ typedef struct _AgentOptions */ ClipboardMode Clipboard; + /* + * transfer TARGETS to remote side or answer with a limited + * hardcoded text target list + * Should be Bool but we'd have to include Xlib.h for that + */ + int TextClipboard; + /* * Enable agent to use the MITSHM extension in path from remote * proxy to the real X server. diff --git a/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 b/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 index 74349cda7..f373cb239 100644 --- a/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 +++ b/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 @@ -465,6 +465,10 @@ The session id. .B \-autograb enable autograb mode on \fBnxagent\fR startup. The autograb feature can be toggled via nxagent keystrokes .TP 8 +.B \-textclipboard +force text-only clipboard \fBnxagent\fR startup. See option file +option \fBtextclipboard=\fR for an explanation. +.TP 8 .B \-nxrealwindowprop set property NX_REAL_WINDOW for each X11 client inside \fBnxagent\fR, providing the window XID of the corresponding window object on the X @@ -721,6 +725,15 @@ Limit clipboard data exchange to work only in one direction: from nxagent to rea Disable any clipboard data exchange. Clipboard will still work inside the nxagent and on the real X server, but no data exchange will be possible. .RE .TP 8 +.B textclipboard= +enable (set to \fI1\fR) or disable (set to \fI0\fR) text-only +clipboard. Text-only clipboard is the old (<= 3.5.99.26) clipboard +behaviour where you could only copy and paste text strings (no +graphics, no rich text, ...). Using this mode been seen as a security feature +as it effectively prevents transferring dangerous binary data, +e.g. manipulated graphics by accident. On the other hand it's also +less comfortable. (default: disabled) +.TP 8 .B streaming= enable (set to \fI1\fR) or disable (set to \fI0\fR) streaming support for images, not fully implemented yet and thus non-functional. (default: disabled) .TP 8 -- cgit v1.2.3