diff --git a/.gitignore b/.gitignore index abe71a2..909656d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/tigervnc-1.14.0.tar.gz +SOURCES/tigervnc-1.14.1.tar.gz diff --git a/.tigervnc.metadata b/.tigervnc.metadata index 637f775..6633de2 100644 --- a/.tigervnc.metadata +++ b/.tigervnc.metadata @@ -1 +1 @@ -9e67944113159da85f42c24b43f40b842f23feb3 SOURCES/tigervnc-1.14.0.tar.gz +bc3c8bc9f454eb307011cd5965251f4a28040a25 SOURCES/tigervnc-1.14.1.tar.gz diff --git a/SOURCES/tigervnc-add-clipboard-support-to-x0vncserver.patch b/SOURCES/tigervnc-add-clipboard-support-to-x0vncserver.patch new file mode 100644 index 0000000..671b798 --- /dev/null +++ b/SOURCES/tigervnc-add-clipboard-support-to-x0vncserver.patch @@ -0,0 +1,543 @@ +From c23be952f50ba34c49134b6280ce503f154dc9bc Mon Sep 17 00:00:00 2001 +From: Gaurav Ujjwal +Date: Wed, 25 Sep 2024 21:21:26 +0530 +Subject: [PATCH] Add clipboard support to x0vncserver + +--- + unix/tx/TXWindow.cxx | 13 ++- + unix/tx/TXWindow.h | 3 +- + unix/x0vncserver/CMakeLists.txt | 1 + + unix/x0vncserver/XDesktop.cxx | 49 +++++++- + unix/x0vncserver/XDesktop.h | 13 ++- + unix/x0vncserver/XSelection.cxx | 195 +++++++++++++++++++++++++++++++ + unix/x0vncserver/XSelection.h | 58 +++++++++ + unix/x0vncserver/x0vncserver.cxx | 5 - + unix/x0vncserver/x0vncserver.man | 21 ++++ + 9 files changed, 344 insertions(+), 14 deletions(-) + create mode 100644 unix/x0vncserver/XSelection.cxx + create mode 100644 unix/x0vncserver/XSelection.h + +diff --git a/unix/tx/TXWindow.cxx b/unix/tx/TXWindow.cxx +index ee097e4..b10ed84 100644 +--- a/unix/tx/TXWindow.cxx ++++ b/unix/tx/TXWindow.cxx +@@ -36,7 +36,7 @@ std::list windows; + + Atom wmProtocols, wmDeleteWindow, wmTakeFocus; + Atom xaTIMESTAMP, xaTARGETS, xaSELECTION_TIME, xaSELECTION_STRING; +-Atom xaCLIPBOARD; ++Atom xaCLIPBOARD, xaUTF8_STRING, xaINCR; + unsigned long TXWindow::black, TXWindow::white; + unsigned long TXWindow::defaultFg, TXWindow::defaultBg; + unsigned long TXWindow::lightBg, TXWindow::darkBg; +@@ -65,6 +65,8 @@ void TXWindow::init(Display* dpy, const char* defaultWindowClass_) + xaSELECTION_TIME = XInternAtom(dpy, "SELECTION_TIME", False); + xaSELECTION_STRING = XInternAtom(dpy, "SELECTION_STRING", False); + xaCLIPBOARD = XInternAtom(dpy, "CLIPBOARD", False); ++ xaUTF8_STRING = XInternAtom(dpy, "UTF8_STRING", False); ++ xaINCR = XInternAtom(dpy, "INCR", False); + XColor cols[6]; + cols[0].red = cols[0].green = cols[0].blue = 0x0000; + cols[1].red = cols[1].green = cols[1].blue = 0xbbbb; +@@ -462,17 +464,18 @@ void TXWindow::handleXEvent(XEvent* ev) + } else { + se.property = ev->xselectionrequest.property; + if (se.target == xaTARGETS) { +- Atom targets[2]; ++ Atom targets[3]; + targets[0] = xaTIMESTAMP; + targets[1] = XA_STRING; ++ targets[2] = xaUTF8_STRING; + XChangeProperty(dpy, se.requestor, se.property, XA_ATOM, 32, +- PropModeReplace, (unsigned char*)targets, 2); ++ PropModeReplace, (unsigned char*)targets, 3); + } else if (se.target == xaTIMESTAMP) { + Time t = selectionOwnTime[se.selection]; + XChangeProperty(dpy, se.requestor, se.property, XA_INTEGER, 32, + PropModeReplace, (unsigned char*)&t, 1); +- } else if (se.target == XA_STRING) { +- if (!selectionRequest(se.requestor, se.selection, se.property)) ++ } else if (se.target == XA_STRING || se.target == xaUTF8_STRING) { ++ if (!selectionRequest(se.requestor, se.selection, se.target, se.property)) + se.property = None; + } else { + se.property = None; +diff --git a/unix/tx/TXWindow.h b/unix/tx/TXWindow.h +index 223c07a..32ae9a3 100644 +--- a/unix/tx/TXWindow.h ++++ b/unix/tx/TXWindow.h +@@ -155,6 +155,7 @@ public: + // returning true if successful, false otherwise. + virtual bool selectionRequest(Window /*requestor*/, + Atom /*selection*/, ++ Atom /*target*/, + Atom /*property*/) { return false;} + + // Static methods +@@ -224,6 +225,6 @@ private: + + extern Atom wmProtocols, wmDeleteWindow, wmTakeFocus; + extern Atom xaTIMESTAMP, xaTARGETS, xaSELECTION_TIME, xaSELECTION_STRING; +-extern Atom xaCLIPBOARD; ++extern Atom xaCLIPBOARD, xaUTF8_STRING, xaINCR; + + #endif +diff --git a/unix/x0vncserver/CMakeLists.txt b/unix/x0vncserver/CMakeLists.txt +index 5ce9577..9d6d213 100644 +--- a/unix/x0vncserver/CMakeLists.txt ++++ b/unix/x0vncserver/CMakeLists.txt +@@ -11,6 +11,7 @@ add_executable(x0vncserver + XPixelBuffer.cxx + XDesktop.cxx + RandrGlue.c ++ XSelection.cxx + ../vncconfig/QueryConnectDialog.cxx + ) + +diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx +index 1e52987..db5b6ae 100644 +--- a/unix/x0vncserver/XDesktop.cxx ++++ b/unix/x0vncserver/XDesktop.cxx +@@ -43,6 +43,7 @@ + #endif + #ifdef HAVE_XFIXES + #include ++#include + #endif + #ifdef HAVE_XRANDR + #include +@@ -81,7 +82,7 @@ static const char * ledNames[XDESKTOP_N_LEDS] = { + + XDesktop::XDesktop(Display* dpy_, Geometry *geometry_) + : dpy(dpy_), geometry(geometry_), pb(0), server(0), +- queryConnectDialog(0), queryConnectSock(0), ++ queryConnectDialog(0), queryConnectSock(0), selection(dpy_, this), + oldButtonMask(0), haveXtest(false), haveDamage(false), + maxButtons(0), running(false), ledMasks(), ledState(0), + codeMap(0), codeMapLen(0) +@@ -179,10 +180,15 @@ XDesktop::XDesktop(Display* dpy_, Geometry *geometry_) + if (XFixesQueryExtension(dpy, &xfixesEventBase, &xfixesErrorBase)) { + XFixesSelectCursorInput(dpy, DefaultRootWindow(dpy), + XFixesDisplayCursorNotifyMask); ++ ++ XFixesSelectSelectionInput(dpy, DefaultRootWindow(dpy), XA_PRIMARY, ++ XFixesSetSelectionOwnerNotifyMask); ++ XFixesSelectSelectionInput(dpy, DefaultRootWindow(dpy), xaCLIPBOARD, ++ XFixesSetSelectionOwnerNotifyMask); + } else { + #endif + vlog.info("XFIXES extension not present"); +- vlog.info("Will not be able to display cursors"); ++ vlog.info("Will not be able to display cursors or monitor clipboard"); + #ifdef HAVE_XFIXES + } + #endif +@@ -892,6 +898,20 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) { + return false; + + return setCursor(); ++ } ++ else if (ev->type == xfixesEventBase + XFixesSelectionNotify) { ++ XFixesSelectionNotifyEvent* sev = (XFixesSelectionNotifyEvent*)ev; ++ ++ if (!running) ++ return true; ++ ++ if (sev->subtype != XFixesSetSelectionOwnerNotify) ++ return false; ++ ++ selection.handleSelectionOwnerChange(sev->owner, sev->selection, ++ sev->timestamp); ++ ++ return true; + #endif + #ifdef HAVE_XRANDR + } else if (ev->type == Expose) { +@@ -1039,3 +1059,28 @@ bool XDesktop::setCursor() + return true; + } + #endif ++ ++// X selection availability changed, let VNC clients know ++void XDesktop::handleXSelectionAnnounce(bool available) { ++ server->announceClipboard(available); ++} ++ ++// A VNC client wants data, send request to selection owner ++void XDesktop::handleClipboardRequest() { ++ selection.requestSelectionData(); ++} ++ ++// Data is available, send it to clients ++void XDesktop::handleXSelectionData(const char* data) { ++ server->sendClipboardData(data); ++} ++ ++// When a client says it has clipboard data, request it ++void XDesktop::handleClipboardAnnounce(bool available) { ++ if(available) server->requestClipboard(); ++} ++ ++// Client has sent the data ++void XDesktop::handleClipboardData(const char* data) { ++ if (data) selection.handleClientClipboardData(data); ++} +diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h +index 4777a65..bc8d2a9 100644 +--- a/unix/x0vncserver/XDesktop.h ++++ b/unix/x0vncserver/XDesktop.h +@@ -32,6 +32,8 @@ + + #include + ++#include "XSelection.h" ++ + class Geometry; + class XPixelBuffer; + +@@ -46,7 +48,8 @@ struct AddedKeySym + + class XDesktop : public rfb::SDesktop, + public TXGlobalEventHandler, +- public QueryResultCallback ++ public QueryResultCallback, ++ public XSelectionHandler + { + public: + XDesktop(Display* dpy_, Geometry *geometry); +@@ -65,6 +68,13 @@ public: + virtual void clientCutText(const char* str); + virtual unsigned int setScreenLayout(int fb_width, int fb_height, + const rfb::ScreenSet& layout); ++ void handleClipboardRequest() override; ++ void handleClipboardAnnounce(bool available) override; ++ void handleClipboardData(const char* data) override; ++ ++ // -=- XSelectionHandler interface ++ void handleXSelectionAnnounce(bool available) override; ++ void handleXSelectionData(const char* data) override; + + // -=- TXGlobalEventHandler interface + virtual bool handleGlobalEvent(XEvent* ev); +@@ -80,6 +90,7 @@ protected: + rfb::VNCServer* server; + QueryConnectDialog* queryConnectDialog; + network::Socket* queryConnectSock; ++ XSelection selection; + int oldButtonMask; + bool haveXtest; + bool haveDamage; +diff --git a/unix/x0vncserver/XSelection.cxx b/unix/x0vncserver/XSelection.cxx +new file mode 100644 +index 0000000..72dd537 +--- /dev/null ++++ b/unix/x0vncserver/XSelection.cxx +@@ -0,0 +1,195 @@ ++/* Copyright (C) 2024 Gaurav Ujjwal. All Rights Reserved. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++ ++rfb::BoolParameter setPrimary("SetPrimary", ++ "Set the PRIMARY as well as the CLIPBOARD selection", ++ true); ++rfb::BoolParameter sendPrimary("SendPrimary", ++ "Send the PRIMARY as well as the CLIPBOARD selection", ++ true); ++ ++static rfb::LogWriter vlog("XSelection"); ++ ++XSelection::XSelection(Display* dpy_, XSelectionHandler* handler_) ++ : TXWindow(dpy_, 1, 1, nullptr), handler(handler_), announcedSelection(None) ++{ ++ probeProperty = XInternAtom(dpy, "TigerVNC_ProbeProperty", False); ++ transferProperty = XInternAtom(dpy, "TigerVNC_TransferProperty", False); ++ timestampProperty = XInternAtom(dpy, "TigerVNC_TimestampProperty", False); ++ setName("TigerVNC Clipboard (x0vncserver)"); ++ addEventMask(PropertyChangeMask); // Required for PropertyNotify events ++} ++ ++static Bool PropertyEventMatcher(Display* /* dpy */, XEvent* ev, XPointer prop) ++{ ++ if (ev->type == PropertyNotify && ev->xproperty.atom == *((Atom*)prop)) ++ return True; ++ else ++ return False; ++} ++ ++Time XSelection::getXServerTime() ++{ ++ XEvent ev; ++ uint8_t data = 0; ++ ++ // Trigger a PropertyNotify event to extract server time ++ XChangeProperty(dpy, win(), timestampProperty, XA_STRING, 8, PropModeReplace, ++ &data, sizeof(data)); ++ XIfEvent(dpy, &ev, &PropertyEventMatcher, (XPointer)×tampProperty); ++ return ev.xproperty.time; ++} ++ ++// Takes ownership of selections, backed by given data. ++void XSelection::handleClientClipboardData(const char* data) ++{ ++ vlog.debug("Received client clipboard data, taking selection ownership"); ++ ++ Time time = getXServerTime(); ++ ownSelection(xaCLIPBOARD, time); ++ if (!selectionOwner(xaCLIPBOARD)) ++ vlog.error("Unable to own CLIPBOARD selection"); ++ ++ if (setPrimary) { ++ ownSelection(XA_PRIMARY, time); ++ if (!selectionOwner(XA_PRIMARY)) ++ vlog.error("Unable to own PRIMARY selection"); ++ } ++ ++ if (selectionOwner(xaCLIPBOARD) || selectionOwner(XA_PRIMARY)) ++ clientData = data; ++} ++ ++// We own the selection and another X app has asked for data ++bool XSelection::selectionRequest(Window requestor, Atom selection, Atom target, ++ Atom property) ++{ ++ if (clientData.empty() || requestor == win() || !selectionOwner(selection)) ++ return false; ++ ++ if (target == XA_STRING) { ++ std::string latin1 = rfb::utf8ToLatin1(clientData.data(), clientData.length()); ++ XChangeProperty(dpy, requestor, property, XA_STRING, 8, PropModeReplace, ++ (unsigned char*)latin1.data(), latin1.length()); ++ return true; ++ } ++ ++ if (target == xaUTF8_STRING) { ++ XChangeProperty(dpy, requestor, property, xaUTF8_STRING, 8, PropModeReplace, ++ (unsigned char*)clientData.data(), clientData.length()); ++ return true; ++ } ++ ++ return false; ++} ++ ++// Selection-owner change implies a change in selection data. ++void XSelection::handleSelectionOwnerChange(Window owner, Atom selection, Time time) ++{ ++ if (selection != XA_PRIMARY && selection != xaCLIPBOARD) ++ return; ++ if (selection == XA_PRIMARY && !sendPrimary) ++ return; ++ ++ if (selection == announcedSelection) ++ announceSelection(None); ++ ++ if (owner == None || owner == win()) ++ return; ++ ++ if (!selectionOwner(XA_PRIMARY) && !selectionOwner(xaCLIPBOARD)) ++ clientData = ""; ++ ++ XConvertSelection(dpy, selection, xaTARGETS, probeProperty, win(), time); ++} ++ ++void XSelection::announceSelection(Atom selection) ++{ ++ announcedSelection = selection; ++ handler->handleXSelectionAnnounce(selection != None); ++} ++ ++void XSelection::requestSelectionData() ++{ ++ if (announcedSelection != None) ++ XConvertSelection(dpy, announcedSelection, xaTARGETS, transferProperty, win(), ++ CurrentTime); ++} ++ ++// Some information about selection is received from current owner ++void XSelection::selectionNotify(XSelectionEvent* ev, Atom type, int format, ++ int nitems, void* data) ++{ ++ if (!ev || !data || type == None) ++ return; ++ ++ if (ev->target == xaTARGETS) { ++ if (format != 32 || type != XA_ATOM) ++ return; ++ ++ Atom* targets = (Atom*)data; ++ bool utf8Supported = false; ++ bool stringSupported = false; ++ ++ for (int i = 0; i < nitems; i++) { ++ if (targets[i] == xaUTF8_STRING) ++ utf8Supported = true; ++ else if (targets[i] == XA_STRING) ++ stringSupported = true; ++ } ++ ++ if (ev->property == probeProperty) { ++ // Only probing for now, will issue real request when client asks for data ++ if (stringSupported || utf8Supported) ++ announceSelection(ev->selection); ++ return; ++ } ++ ++ // Prefer UTF-8 if available ++ if (utf8Supported) ++ XConvertSelection(dpy, ev->selection, xaUTF8_STRING, transferProperty, win(), ++ ev->time); ++ else if (stringSupported) ++ XConvertSelection(dpy, ev->selection, XA_STRING, transferProperty, win(), ++ ev->time); ++ } else if (ev->target == xaUTF8_STRING || ev->target == XA_STRING) { ++ if (type == xaINCR) { ++ // Incremental transfer is not supported ++ vlog.debug("Selected data is too big!"); ++ return; ++ } ++ ++ if (format != 8) ++ return; ++ ++ if (type == xaUTF8_STRING) { ++ std::string result = rfb::convertLF((char*)data, nitems); ++ handler->handleXSelectionData(result.c_str()); ++ } else if (type == XA_STRING) { ++ std::string result = rfb::convertLF((char*)data, nitems); ++ result = rfb::latin1ToUTF8(result.data(), result.length()); ++ handler->handleXSelectionData(result.c_str()); ++ } ++ } ++} +\ No newline at end of file +diff --git a/unix/x0vncserver/XSelection.h b/unix/x0vncserver/XSelection.h +new file mode 100644 +index 0000000..fbe1f29 +--- /dev/null ++++ b/unix/x0vncserver/XSelection.h +@@ -0,0 +1,58 @@ ++/* Copyright (C) 2024 Gaurav Ujjwal. All Rights Reserved. ++ * ++ * 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 __XSELECTION_H__ ++#define __XSELECTION_H__ ++ ++#include ++#include ++ ++class XSelectionHandler ++{ ++public: ++ virtual void handleXSelectionAnnounce(bool available) = 0; ++ virtual void handleXSelectionData(const char* data) = 0; ++}; ++ ++class XSelection : TXWindow ++{ ++public: ++ XSelection(Display* dpy_, XSelectionHandler* handler_); ++ ++ void handleSelectionOwnerChange(Window owner, Atom selection, Time time); ++ void requestSelectionData(); ++ void handleClientClipboardData(const char* data); ++ ++private: ++ XSelectionHandler* handler; ++ Atom probeProperty; ++ Atom transferProperty; ++ Atom timestampProperty; ++ Atom announcedSelection; ++ std::string clientData; // Always in UTF-8 ++ ++ Time getXServerTime(); ++ void announceSelection(Atom selection); ++ ++ bool selectionRequest(Window requestor, Atom selection, Atom target, ++ Atom property) override; ++ void selectionNotify(XSelectionEvent* ev, Atom type, int format, int nitems, ++ void* data) override; ++}; ++ ++#endif +diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx +index d2999e2..b31450b 100644 +--- a/unix/x0vncserver/x0vncserver.cxx ++++ b/unix/x0vncserver/x0vncserver.cxx +@@ -281,11 +281,6 @@ int main(int argc, char** argv) + + Configuration::enableServerParams(); + +- // FIXME: We don't support clipboard yet +- Configuration::removeParam("AcceptCutText"); +- Configuration::removeParam("SendCutText"); +- Configuration::removeParam("MaxCutText"); +- + // Assume different defaults when socket activated + if (hasSystemdListeners()) + rfbport.setParam(-1); +diff --git a/unix/x0vncserver/x0vncserver.man b/unix/x0vncserver/x0vncserver.man +index 347e50e..5bc8807 100644 +--- a/unix/x0vncserver/x0vncserver.man ++++ b/unix/x0vncserver/x0vncserver.man +@@ -222,6 +222,27 @@ Accept pointer movement and button events from clients. Default is on. + Accept requests to resize the size of the desktop. Default is on. + . + .TP ++.B \-AcceptCutText ++Accept clipboard updates from clients. Default is on. ++. ++.TP ++.B \-SetPrimary ++Set the PRIMARY as well as the CLIPBOARD selection. Default is on. ++. ++.TP ++.B \-MaxCutText \fIbytes\fP ++The maximum permitted size of an incoming clipboard update. ++Default is \fB262144\fP. ++. ++.TP ++.B \-SendCutText ++Send clipboard changes to clients. Default is on. ++. ++.TP ++.B \-SendPrimary ++Send the PRIMARY as well as the CLIPBOARD selection to clients. Default is on. ++. ++.TP + .B \-RemapKeys \fImapping + Sets up a keyboard mapping. + .I mapping diff --git a/SOURCES/tigervnc-add-missing-coma-in-default-security-type-list.patch b/SOURCES/tigervnc-add-missing-coma-in-default-security-type-list.patch deleted file mode 100644 index cb426b6..0000000 --- a/SOURCES/tigervnc-add-missing-coma-in-default-security-type-list.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 4f6a3521874da5a67fd746389cfa9b6199eb3582 Mon Sep 17 00:00:00 2001 -From: Pierre Ossman -Date: Mon, 29 Jul 2024 16:16:08 +0200 -Subject: [PATCH] Add missing comma in default security type list - -Otherwise it merges with the next entry, removing both of them from the -default list. ---- - common/rfb/SecurityClient.cxx | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/common/rfb/SecurityClient.cxx b/common/rfb/SecurityClient.cxx -index 12860662f..63e0cadc0 100644 ---- a/common/rfb/SecurityClient.cxx -+++ b/common/rfb/SecurityClient.cxx -@@ -60,7 +60,7 @@ StringParameter SecurityClient::secTypes - "X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone," - #endif - #ifdef HAVE_NETTLE -- "RA2,RA2_256,RA2ne,RA2ne_256,DH,MSLogonII" -+ "RA2,RA2_256,RA2ne,RA2ne_256,DH,MSLogonII," - #endif - "VncAuth,None", - ConfViewer); diff --git a/SOURCES/tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch b/SOURCES/tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch new file mode 100644 index 0000000..4f8a3c2 --- /dev/null +++ b/SOURCES/tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch @@ -0,0 +1,238 @@ +From 8ac9bf0c061666d89d345a3d7149e1ef9c771655 Mon Sep 17 00:00:00 2001 +From: Jan Grulich +Date: Mon, 29 Jul 2024 14:31:14 +0200 +Subject: [PATCH] Add option allowing to connect only the user owning the + running session + +Checks, whether the user who is trying to authenticate is already logged +into the running session in order to allow or reject the connection. +This is expected to be used with 'plain' security type in combination +with 'PlainUsers=*' option allowing everyone to connect to the session. +--- + common/rfb/VNCServerST.cxx | 7 -- + unix/xserver/hw/vnc/XserverDesktop.cc | 120 +++++++++++++++++++++++++- + unix/xserver/hw/vnc/XserverDesktop.h | 7 ++ + 3 files changed, 126 insertions(+), 8 deletions(-) + +diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx +index 3831812..736a563 100644 +--- a/common/rfb/VNCServerST.cxx ++++ b/common/rfb/VNCServerST.cxx +@@ -696,13 +696,6 @@ void VNCServerST::queryConnection(VNCSConnectionST* client, + return; + } + +- // - Are we configured to do queries? +- if (!rfb::Server::queryConnect && +- !client->getSock()->requiresQuery()) { +- approveConnection(client->getSock(), true, NULL); +- return; +- } +- + // - Does the client have the right to bypass the query? + if (client->accessCheck(AccessNoQuery)) + { +diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc +index d4ee16b..fe86d36 100644 +--- a/unix/xserver/hw/vnc/XserverDesktop.cc ++++ b/unix/xserver/hw/vnc/XserverDesktop.cc +@@ -52,6 +52,11 @@ + #include "XorgGlue.h" + #include "vncInput.h" + ++#if HAVE_SYSTEMD_DAEMON ++# include ++# include ++#endif ++ + extern "C" { + void vncSetGlueContext(int screenIndex); + void vncPresentMscEvent(uint64_t id, uint64_t msc); +@@ -71,7 +76,15 @@ IntParameter queryConnectTimeout("QueryConnectTimeout", + "Accept Connection dialog before " + "rejecting the connection", + 10); +- ++#ifdef HAVE_SYSTEMD_DAEMON ++BoolParameter approveLoggedUserOnly ++("ApproveLoggedUserOnly", ++ "Approve only the user who is currently logged into the session." ++ "This is expected to be combined with 'plain' security type and with " ++ "'PlainUsers=*' option allowing everyone to connect to the session." ++ "Default is off.", ++ false); ++#endif + + XserverDesktop::XserverDesktop(int screenIndex_, + std::list listeners_, +@@ -168,11 +181,134 @@ void XserverDesktop::init(rfb::VNCServer* vs) + // ready state + } + ++#ifdef HAVE_SYSTEMD_DAEMON ++bool XserverDesktop::checkUserLogged(const char* userName) ++{ ++ bool ret = false; ++ bool noUserSession = true; ++ int res; ++ char **sessions; ++ ++ res = sd_get_sessions(&sessions); ++ if (res < 0) { ++ vlog.debug("logind: failed to get sessions"); ++ return false; ++ } ++ ++ if (sessions != nullptr && sessions[0] != nullptr) { ++ for (int i = 0; sessions[i]; i++) { ++ uid_t uid; ++ char *clazz; ++ char *display; ++ char *type; ++ char *state; ++ ++ res = sd_session_get_type(sessions[i], &type); ++ if (res < 0) { ++ vlog.debug("logind: failed to determine session type"); ++ break; ++ } ++ ++ if (strcmp(type, "x11") != 0) { ++ free(type); ++ continue; ++ } ++ free(type); ++ ++ res = sd_session_get_display(sessions[i], &display); ++ if (res < 0) { ++ vlog.debug("logind: failed to determine display of session"); ++ break; ++ } ++ ++ std::string serverDisplay = ":" + std::to_string(screenIndex); ++ std::string serverDisplayIPv4 = "127.0.0.1:" + std::to_string(screenIndex); ++ std::string serverDisplayIPv6 = "::1:" + std::to_string(screenIndex); ++ if ((strcmp(display, serverDisplay.c_str()) != 0) && ++ (strcmp(display, serverDisplayIPv4.c_str()) != 0) && ++ (strcmp(display, serverDisplayIPv6.c_str()) != 0)) { ++ free(display); ++ continue; ++ } ++ free(display); ++ ++ res = sd_session_get_class(sessions[i], &clazz); ++ if (res < 0) { ++ vlog.debug("logind: failed to determine session class"); ++ break; ++ } ++ ++ res = sd_session_get_state(sessions[i], &state); ++ if (res < 0) { ++ vlog.debug("logind: failed to determine session state"); ++ break; ++ } ++ ++ if (strcmp(state, "closing") == 0) { ++ free(state); ++ continue; ++ } ++ free(state); ++ ++ res = sd_session_get_uid(sessions[i], &uid); ++ if (res < 0) { ++ vlog.debug("logind: failed to determine user id of session"); ++ break; ++ } ++ ++ if (uid != 0 && strcmp(clazz, "user") == 0) { ++ noUserSession = false; ++ } ++ free(clazz); ++ ++ struct passwd *pw = getpwnam(userName); ++ if (!pw) { ++ vlog.debug("logind: user not found"); ++ break; ++ } ++ ++ if (uid == pw->pw_uid) { ++ ret = true; ++ break; ++ } ++ } ++ } ++ ++ if (sessions) { ++ for (int i = 0; sessions[i]; i ++) { ++ free(sessions[i]); ++ } ++ ++ free (sessions); ++ } ++ ++ // If we didn't find a matching user, we can still allow the user ++ // to log in if there is no user session yet. ++ return !ret ? noUserSession : ret; ++} ++#endif ++ + void XserverDesktop::queryConnection(network::Socket* sock, + const char* userName) + { + int count; + ++#ifdef HAVE_SYSTEMD_DAEMON ++ // - Only owner of the session can be approved ++ if (approveLoggedUserOnly && !checkUserLogged(userName)) { ++ server->approveConnection(sock, false, ++ "The user is not owner of the running session"); ++ return; ++ } ++#endif ++ ++ // - Are we configured to do queries? ++ if (!rfb::Server::queryConnect && ++ !sock->requiresQuery()) { ++ server->approveConnection(sock, true, nullptr); ++ return; ++ } ++ + if (queryConnectTimer.isStarted()) { + server->approveConnection(sock, false, "Another connection is currently being queried."); + return; +diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h +index e604295..aed188e 100644 +--- a/unix/xserver/hw/vnc/XserverDesktop.h ++++ b/unix/xserver/hw/vnc/XserverDesktop.h +@@ -108,6 +108,13 @@ public: + virtual void grabRegion(const rfb::Region& r); + + protected: ++#ifdef HAVE_SYSTEMD_DAEMON ++ // - Check whether user is logged into a session ++ // Returns true if user is already logged or there is no ++ // user session at all. ++ bool checkUserLogged(const char* userName); ++#endif ++ + bool handleListenerEvent(int fd, + std::list* sockets, + rfb::VNCServer* sockserv); +diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man +index b9c429f..e4822f6 100644 +--- a/unix/xserver/hw/vnc/Xvnc.man ++++ b/unix/xserver/hw/vnc/Xvnc.man +@@ -204,6 +204,13 @@ to allow any user to authenticate using this security type. Specify \fB%u\fP + to allow the user of the server process. Default is to deny all users. + . + .TP ++.B \-ApproveLoggedUserOnly ++Approve only the user who is currently logged into the session. ++This is expected to be combined with "Plain" security type and with ++"PlainUsers=*" option allowing everyone to connect to the session. ++Default is off. ++. ++.TP + .B \-pam_service \fIname\fP, \-PAMService \fIname\fP + PAM service name to use when authentication users using any of the "Plain" + security types. Default is \fBvnc\fP. diff --git a/SOURCES/tigervnc-avoid-invalid-xfree-for-xclasshint.patch b/SOURCES/tigervnc-avoid-invalid-xfree-for-xclasshint.patch new file mode 100644 index 0000000..bf43d09 --- /dev/null +++ b/SOURCES/tigervnc-avoid-invalid-xfree-for-xclasshint.patch @@ -0,0 +1,24 @@ +From 6c8387018b130eb4ef69ea377e9154ba04f0fd50 Mon Sep 17 00:00:00 2001 +From: Pierre Ossman +Date: Tue, 22 Oct 2024 09:58:27 +0200 +Subject: [PATCH] Avoid invalid XFree for XClassHint + +It seems XGetClassHint() doesn't set the pointers to NULL if there is no +name, so we need to make sure it is cleared beforehand. Otherwise we can +get an invalid pointer given to XFree(). +--- + unix/tx/TXWindow.cxx | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/unix/tx/TXWindow.cxx b/unix/tx/TXWindow.cxx +index b6a29d679..639c13827 100644 +--- a/unix/tx/TXWindow.cxx ++++ b/unix/tx/TXWindow.cxx +@@ -313,6 +313,7 @@ void TXWindow::toplevel(const char* name, TXDeleteWindowCallback* dwc_, + void TXWindow::setName(const char* name) + { + XClassHint classHint; ++ memset(&classHint, 0, sizeof(classHint)); + XGetClassHint(dpy, win(), &classHint); + XFree(classHint.res_name); + classHint.res_name = (char*)name; diff --git a/SOURCES/tigervnc-correctly-handle-zrle-cursors.patch b/SOURCES/tigervnc-correctly-handle-zrle-cursors.patch deleted file mode 100644 index 1b17302..0000000 --- a/SOURCES/tigervnc-correctly-handle-zrle-cursors.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 6d9017eeb364491cf2acdf1c7e61aee8dd198527 Mon Sep 17 00:00:00 2001 -From: Pierre Ossman -Date: Fri, 30 Aug 2024 16:15:09 +0200 -Subject: [PATCH] Correctly handle ZRLE cursors - -Cursor data has a depth of 32 bits and hence cannot use CPIXELs. - -This is a regression from baca73d. ---- - common/rfb/ZRLEDecoder.cxx | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx -index 474fd6ca1..e274a697a 100644 ---- a/common/rfb/ZRLEDecoder.cxx -+++ b/common/rfb/ZRLEDecoder.cxx -@@ -125,10 +125,10 @@ void ZRLEDecoder::zrleDecode(const Rect& r, rdr::InStream* is, - Pixel maxPixel = pf.pixelFromRGB((uint16_t)-1, (uint16_t)-1, (uint16_t)-1); - bool fitsInLS3Bytes = maxPixel < (1<<24); - bool fitsInMS3Bytes = (maxPixel & 0xff) == 0; -- bool isLowCPixel = (sizeof(T) == 4) && -+ bool isLowCPixel = (sizeof(T) == 4) && (pf.depth <= 24) && - ((fitsInLS3Bytes && pf.isLittleEndian()) || - (fitsInMS3Bytes && pf.isBigEndian())); -- bool isHighCPixel = (sizeof(T) == 4) && -+ bool isHighCPixel = (sizeof(T) == 4) && (pf.depth <= 24) && - ((fitsInLS3Bytes && pf.isBigEndian()) || - (fitsInMS3Bytes && pf.isLittleEndian())); - diff --git a/SOURCES/tigervnc-do-proper-toplevel-window-setup-for-selection-window.patch b/SOURCES/tigervnc-do-proper-toplevel-window-setup-for-selection-window.patch new file mode 100644 index 0000000..edc285e --- /dev/null +++ b/SOURCES/tigervnc-do-proper-toplevel-window-setup-for-selection-window.patch @@ -0,0 +1,22 @@ +From 9e15952d02e01b8e19e7459bcabcd47dc63a1726 Mon Sep 17 00:00:00 2001 +From: Pierre Ossman +Date: Tue, 22 Oct 2024 09:59:30 +0200 +Subject: [PATCH] Do proper top level window setup for selection window + +--- + unix/x0vncserver/XSelection.cxx | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/unix/x0vncserver/XSelection.cxx b/unix/x0vncserver/XSelection.cxx +index 72dd537f4..c724d2ac4 100644 +--- a/unix/x0vncserver/XSelection.cxx ++++ b/unix/x0vncserver/XSelection.cxx +@@ -37,7 +37,7 @@ XSelection::XSelection(Display* dpy_, XSelectionHandler* handler_) + probeProperty = XInternAtom(dpy, "TigerVNC_ProbeProperty", False); + transferProperty = XInternAtom(dpy, "TigerVNC_TransferProperty", False); + timestampProperty = XInternAtom(dpy, "TigerVNC_TimestampProperty", False); +- setName("TigerVNC Clipboard (x0vncserver)"); ++ toplevel("TigerVNC Clipboard (x0vncserver)"); + addEventMask(PropertyChangeMask); // Required for PropertyNotify events + } + diff --git a/SOURCES/tigervnc-handle-existing-config-directory-in-vncpasswd.patch b/SOURCES/tigervnc-handle-existing-config-directory-in-vncpasswd.patch deleted file mode 100644 index ea431f8..0000000 --- a/SOURCES/tigervnc-handle-existing-config-directory-in-vncpasswd.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 445e0230cf4e939dcc59caf5d5f001c2f7b04da6 Mon Sep 17 00:00:00 2001 -From: Pierre Ossman -Date: Thu, 15 Aug 2024 14:24:42 +0200 -Subject: [PATCH] Handle existing config directory in vncpasswd - -This fixes commit a79c33d. ---- - unix/vncpasswd/vncpasswd.cxx | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx -index 6666955f1..9f794e129 100644 ---- a/unix/vncpasswd/vncpasswd.cxx -+++ b/unix/vncpasswd/vncpasswd.cxx -@@ -213,8 +213,10 @@ int main(int argc, char** argv) - exit(1); - } - if (os::mkdir_p(configDir, 0777) == -1) { -- fprintf(stderr, "Could not create VNC config directory: %s\n", strerror(errno)); -- exit(1); -+ if (errno != EEXIST) { -+ fprintf(stderr, "Could not create VNC config directory: %s\n", strerror(errno)); -+ exit(1); -+ } - } - snprintf(fname, sizeof(fname), "%s/passwd", configDir); - } diff --git a/SOURCES/tigervnc-vncsession-move-existing-log-to-log-old-if-present.patch b/SOURCES/tigervnc-vncsession-move-existing-log-to-log-old-if-present.patch index e69de29..9a1ae26 100644 --- a/SOURCES/tigervnc-vncsession-move-existing-log-to-log-old-if-present.patch +++ b/SOURCES/tigervnc-vncsession-move-existing-log-to-log-old-if-present.patch @@ -0,0 +1,94 @@ +From e26bc65b92d1e43570619deadf20b965e0952fef Mon Sep 17 00:00:00 2001 +From: Pat Riehecky +Date: Wed, 31 Jul 2024 14:43:46 -0500 +Subject: [PATCH] vncsession: Move existing log to log.old if present + +--- + unix/vncserver/vncsession.c | 47 ++++++++++++++++++++++++++++--------- + 1 file changed, 36 insertions(+), 11 deletions(-) + +diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c +index 98a0432aa..a10e0789e 100644 +--- a/unix/vncserver/vncsession.c ++++ b/unix/vncserver/vncsession.c +@@ -393,8 +393,9 @@ redir_stdio(const char *homedir, const char *display, char **envp) + int fd; + long hostlen; + char* hostname = NULL, *xdgstate; +- char logfile[PATH_MAX], legacy[PATH_MAX]; ++ char logdir[PATH_MAX], logfile[PATH_MAX], logfile_old[PATH_MAX], legacy[PATH_MAX]; + struct stat st; ++ size_t fmt_len; + + fd = open("/dev/null", O_RDONLY); + if (fd == -1) { +@@ -408,15 +409,24 @@ redir_stdio(const char *homedir, const char *display, char **envp) + close(fd); + + xdgstate = getenvp("XDG_STATE_HOME", envp); +- if (xdgstate != NULL && xdgstate[0] == '/') +- snprintf(logfile, sizeof(logfile), "%s/tigervnc", xdgstate); +- else +- snprintf(logfile, sizeof(logfile), "%s/.local/state/tigervnc", homedir); ++ if (xdgstate != NULL && xdgstate[0] == '/') { ++ fmt_len = snprintf(logdir, sizeof(logdir), "%s/tigervnc", xdgstate); ++ if (fmt_len >= sizeof(logdir)) { ++ syslog(LOG_CRIT, "Log dir path too long"); ++ _exit(EX_OSERR); ++ } ++ } else { ++ fmt_len = snprintf(logdir, sizeof(logdir), "%s/.local/state/tigervnc", homedir); ++ if (fmt_len >= sizeof(logdir)) { ++ syslog(LOG_CRIT, "Log dir path too long"); ++ _exit(EX_OSERR); ++ } ++ } + + snprintf(legacy, sizeof(legacy), "%s/.vnc", homedir); +- if (stat(logfile, &st) != 0 && stat(legacy, &st) == 0) { ++ if (stat(logdir, &st) != 0 && stat(legacy, &st) == 0) { + syslog(LOG_WARNING, "~/.vnc is deprecated, please consult 'man vncsession' for paths to migrate to."); +- strcpy(logfile, legacy); ++ strcpy(logdir, legacy); + + #ifdef HAVE_SELINUX + /* this is only needed to handle historical type changes for the legacy dir */ +@@ -431,9 +441,9 @@ redir_stdio(const char *homedir, const char *display, char **envp) + #endif + } + +- if (mkdir_p(logfile, 0755) == -1) { ++ if (mkdir_p(logdir, 0755) == -1) { + if (errno != EEXIST) { +- syslog(LOG_CRIT, "Failure creating \"%s\": %s", logfile, strerror(errno)); ++ syslog(LOG_CRIT, "Failure creating \"%s\": %s", logdir, strerror(errno)); + _exit(EX_OSERR); + } + } +@@ -450,9 +460,24 @@ redir_stdio(const char *homedir, const char *display, char **envp) + _exit(EX_OSERR); + } + +- snprintf(logfile + strlen(logfile), sizeof(logfile) - strlen(logfile), "/%s%s.log", +- hostname, display); ++ fmt_len = snprintf(logfile, sizeof(logfile), "/%s/%s%s.log", logdir, hostname, display); ++ if (fmt_len >= sizeof(logfile)) { ++ syslog(LOG_CRIT, "Log path too long"); ++ _exit(EX_OSERR); ++ } ++ fmt_len = snprintf(logfile_old, sizeof(logfile_old), "/%s/%s%s.log.old", logdir, hostname, display); ++ if (fmt_len >= sizeof(logfile)) { ++ syslog(LOG_CRIT, "Log.old path too long"); ++ _exit(EX_OSERR); ++ } + free(hostname); ++ ++ if (stat(logfile, &st) == 0) { ++ if (rename(logfile, logfile_old) != 0) { ++ syslog(LOG_CRIT, "Failure renaming log file \"%s\" to \"%s\": %s", logfile, logfile_old, strerror(errno)); ++ _exit(EX_OSERR); ++ } ++ } + fd = open(logfile, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd == -1) { + syslog(LOG_CRIT, "Failure creating log file \"%s\": %s", logfile, strerror(errno)); diff --git a/SOURCES/tigervnc-vncsession-use-bin-sh-when-shell-not-set.patch b/SOURCES/tigervnc-vncsession-use-bin-sh-when-shell-not-set.patch deleted file mode 100644 index 3f46c73..0000000 --- a/SOURCES/tigervnc-vncsession-use-bin-sh-when-shell-not-set.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 4db34f73d461b973867ddaf18bf690219229cd7a Mon Sep 17 00:00:00 2001 -From: Carlos Santos -Date: Thu, 25 Jul 2024 18:39:59 -0300 -Subject: [PATCH] vncsession: use /bin/sh if the user shell is not set - -An empty shell field in the password file is valid, although not common. -Use /bin/sh in this case, as documented in the passwd(5) man page, since -the vncserver script requires a non-empty SHELL environment variable. - -Fixes issue #1786. - -Signed-off-by: Carlos Santos ---- - unix/vncserver/vncsession.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c -index 1ee096c7c..98a0432aa 100644 ---- a/unix/vncserver/vncsession.c -+++ b/unix/vncserver/vncsession.c -@@ -545,7 +545,7 @@ run_script(const char *username, const char *display, char **envp) - - // Set up some basic environment for the script - setenv("HOME", pwent->pw_dir, 1); -- setenv("SHELL", pwent->pw_shell, 1); -+ setenv("SHELL", *pwent->pw_shell != '\0' ? pwent->pw_shell : "/bin/sh", 1); - setenv("LOGNAME", pwent->pw_name, 1); - setenv("USER", pwent->pw_name, 1); - setenv("USERNAME", pwent->pw_name, 1); diff --git a/SPECS/tigervnc.spec b/SPECS/tigervnc.spec index 9befb89..c06dfbe 100644 --- a/SPECS/tigervnc.spec +++ b/SPECS/tigervnc.spec @@ -4,8 +4,8 @@ %global modulename vncsession Name: tigervnc -Version: 1.14.0 -Release: 2%{?dist} +Version: 1.14.1 +Release: 4%{?dist} Summary: A TigerVNC remote display system %global _hardened_build 1 @@ -23,14 +23,16 @@ Source5: vncserver # Downstream patches Patch1: tigervnc-use-gnome-as-default-session.patch +# https://github.com/TigerVNC/tigervnc/pull/1425 Patch2: tigervnc-vncsession-restore-script-systemd-service.patch +# https://github.com/TigerVNC/tigervnc/pull/1792 +Patch3: tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch # Upstream patches -Patch50: tigervnc-vncsession-use-bin-sh-when-shell-not-set.patch -Patch51: tigervnc-add-missing-coma-in-default-security-type-list.patch -Patch52: tigervnc-vncsession-move-existing-log-to-log-old-if-present.patch -Patch53: tigervnc-handle-existing-config-directory-in-vncpasswd.patch -Patch54: tigervnc-correctly-handle-zrle-cursors.patch +Patch50: tigervnc-vncsession-move-existing-log-to-log-old-if-present.patch +Patch51: tigervnc-add-clipboard-support-to-x0vncserver.patch +Patch52: tigervnc-do-proper-toplevel-window-setup-for-selection-window.patch +Patch53: tigervnc-avoid-invalid-xfree-for-xclasshint.patch # Upstreamable patches Patch80: tigervnc-dont-get-pointer-position-for-floating-device.patch @@ -91,7 +93,13 @@ BuildRequires: xorg-x11-util-macros BuildRequires: xorg-x11-xtrans-devel # SELinux -BuildRequires: libselinux-devel, selinux-policy-devel, systemd +BuildRequires: libselinux-devel +BuildRequires: selinux-policy-devel + +# For RHEL-34880 +BuildRequires: pkgconfig(dbus-1) >= 1.0 +BuildRequires: pkgconfig(libsystemd) >= 209 +BuildRequires: pkgconfig(libudev) >= 143 Requires(post): coreutils Requires(postun):coreutils @@ -199,13 +207,13 @@ popd # Tigervnc patches %patch -P1 -p1 -b .use-gnome-as-default-session %patch -P2 -p1 -b .vncsession-restore-script-systemd-service +%patch -P3 -p1 -b .add-option-allowing-to-connect-only-user-owning-session # Upstream patches -%patch -P50 -p1 -b .vncsession-use-bin-sh-when-shell-not-set -%patch -P51 -p1 -b .add-missing-coma-in-default-security-type-list -%patch -P52 -p1 -b .vncsession-move-existing-log-to-log-old-if-present -%patch -P53 -p1 -b .handle-existing-config-directory-in-vncpasswd -%patch -P54 -p1 -b .correctly-handle-zrle-cursors.patch +%patch -P50 -p1 -b .vncsession-move-existing-log-to-log-old-if-present +%patch -P51 -p1 -b .add-clipboard-support-to-x0vncserver +%patch -P52 -p1 -b .do-proper-toplevel-window-setup-for-selection-window +%patch -P53 -p1 -b .avoid-invalid-xfree-for-xclasshint # Upstreamable patches %patch -P80 -p1 -b .dont-get-pointer-position-for-floating-device @@ -247,7 +255,9 @@ autoreconf -fiv --disable-config-udev \ --without-dtrace \ --disable-devel-docs \ - --disable-selective-werror + --disable-selective-werror \ + --enable-systemd-logind \ + --enable-config-udev make %{?_smp_mflags} popd @@ -390,7 +400,40 @@ fi %ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} %changelog -* Tue Jul 23 2024 Jan Grulich - 1.14.0-2 +* Tue Jan 21 2025 Jan Grulich - 1.14.1-4 +- Fix crash in clipboard support in x0vncserver + Resolves: RHEL-74216 + +* Thu Jan 16 2025 Jan Grulich - 1.14.1-3 +- Add clipboard support to x0vncserver + Resolves: RHEL-74216 + +* Thu Oct 31 2024 Jan Grulich - 1.14.1-2 +- Fix CVE-2024-9632: xorg-x11-server: heap-based buffer overflow privilege escalation vulnerability + Resolves: RHEL-62001 + +* Wed Oct 23 2024 Jan Grulich - 1.14.1-1 +- 1.14.1 + Resolves: RHEL-45316 + +* Mon Oct 07 2024 Jan Grulich - 1.14.0-6 +- Make "ApproveLoggedUserOnly" to ignore "closing" sessions + Resolves: RHEL-34880 + +* Fri Oct 04 2024 Jan Grulich - 1.14.0-5 +- Fix "ApproveLoggedUserOnly" option not working in some setups + Resolves: RHEL-34880 + +* Fri Sep 27 2024 Jan Grulich - 1.14.0-4 +- Add option "ApproveLoggedUserOnly" allowing to connect only the user + owning the running session + Resolves: RHEL-34880 + +* Wed Sep 04 2024 Jan Grulich - 1.14.0-3 +- Move old log to log.old if present (fix patch) + Resolves: RHEL-54294 + +* Tue Aug 20 2024 Jan Grulich - 1.14.0-2 - 1.14.0 Resolves: RHEL-45316 - Move old log to log.old if present