From 319fdcb0c6d770e4b83694ae9d124b0899c57cf0 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Wed, 11 Jun 2025 12:20:00 +0000 Subject: [PATCH] Import from CS git --- ...-to-connect-only-user-owning-session.patch | 265 ++++++++++++++++++ ...sswords-longer-than-eight-characters.patch | 14 + ...rint-xvnc-banner-before-parsing-args.patch | 47 ++++ SPECS/tigervnc.spec | 36 ++- 4 files changed, 360 insertions(+), 2 deletions(-) create mode 100644 SOURCES/tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch create mode 100644 SOURCES/tigervnc-allow-use-of-passwords-longer-than-eight-characters.patch create mode 100644 SOURCES/tigervnc-dont-print-xvnc-banner-before-parsing-args.patch 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..371c700 --- /dev/null +++ b/SOURCES/tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch @@ -0,0 +1,265 @@ +From 69b0fd6d77ea5968bd815188ee2bda3d282ebc60 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/x0vncserver/XDesktop.cxx | 8 ++ + unix/xserver/hw/vnc/XserverDesktop.cc | 137 ++++++++++++++++++++++++++ + unix/xserver/hw/vnc/XserverDesktop.h | 7 ++ + unix/xserver/hw/vnc/Xvnc.man | 7 ++ + 5 files changed, 159 insertions(+), 7 deletions(-) + +diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx +index b99d33b..aa8d53e 100644 +--- a/common/rfb/VNCServerST.cxx ++++ b/common/rfb/VNCServerST.cxx +@@ -682,13 +682,6 @@ void VNCServerST::queryConnection(VNCSConnectionST* client, + return; + } + +- // - Are we configured to do queries? +- if (!rfb::Server::queryConnect && +- !client->getSock()->requiresQuery()) { +- approveConnection(client->getSock(), true, nullptr); +- return; +- } +- + // - Does the client have the right to bypass the query? + if (client->accessCheck(AccessNoQuery)) + { +diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx +index b43e3f7..3d00e23 100644 +--- a/unix/x0vncserver/XDesktop.cxx ++++ b/unix/x0vncserver/XDesktop.cxx +@@ -31,6 +31,7 @@ + #include + + #include ++#include + + #include + +@@ -320,6 +321,13 @@ void XDesktop::queryConnection(network::Socket* sock, + { + assert(isRunning()); + ++ // - Are we configured to do queries? ++ if (!rfb::Server::queryConnect && ++ !sock->requiresQuery()) { ++ server->approveConnection(sock, true, nullptr); ++ return; ++ } ++ + // Someone already querying? + if (queryConnectSock) { + std::list sockets; +diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc +index 260ed3a..c8741f6 100644 +--- a/unix/xserver/hw/vnc/XserverDesktop.cc ++++ b/unix/xserver/hw/vnc/XserverDesktop.cc +@@ -51,6 +51,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,6 +76,15 @@ IntParameter queryConnectTimeout("QueryConnectTimeout", + "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_, +@@ -164,11 +178,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 8c543db..8d6bde4 100644 +--- a/unix/xserver/hw/vnc/XserverDesktop.h ++++ b/unix/xserver/hw/vnc/XserverDesktop.h +@@ -108,6 +108,13 @@ public: + void grabRegion(const rfb::Region& r) override; + + 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 d6b1664..24384df 100644 +--- a/unix/xserver/hw/vnc/Xvnc.man ++++ b/unix/xserver/hw/vnc/Xvnc.man +@@ -200,6 +200,13 @@ Never treat incoming connections as shared, regardless of the client-specified + setting. Default is off. + . + .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-allow-use-of-passwords-longer-than-eight-characters.patch b/SOURCES/tigervnc-allow-use-of-passwords-longer-than-eight-characters.patch new file mode 100644 index 0000000..108a3c0 --- /dev/null +++ b/SOURCES/tigervnc-allow-use-of-passwords-longer-than-eight-characters.patch @@ -0,0 +1,14 @@ +diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx +index 466aa1a2..197d60dc 100644 +--- a/unix/vncpasswd/vncpasswd.cxx ++++ b/unix/vncpasswd/vncpasswd.cxx +@@ -147,8 +147,7 @@ static std::vector readpassword() { + } + + if (first.size() > 8) { +- fprintf(stderr,"Password should not be greater than 8 characters\nBecause only 8 valid characters are used - try again\n"); +- continue; ++ fprintf(stderr,"Password should not be greater than 8 characters\nBecause only 8 valid characters are used\n"); + } + + #ifdef HAVE_PWQUALITY diff --git a/SOURCES/tigervnc-dont-print-xvnc-banner-before-parsing-args.patch b/SOURCES/tigervnc-dont-print-xvnc-banner-before-parsing-args.patch new file mode 100644 index 0000000..5d7ec9f --- /dev/null +++ b/SOURCES/tigervnc-dont-print-xvnc-banner-before-parsing-args.patch @@ -0,0 +1,47 @@ +From 1f1aaca09a1f9919f5169caea9c396b14c2af765 Mon Sep 17 00:00:00 2001 +From: Pierre Ossman +Date: Tue, 8 Apr 2025 14:41:04 +0200 +Subject: [PATCH] Don't print Xvnc banner before parsing args + +If we'll be running in inetd mode, then stdout and stderr will be a +client socket and not an appropriate place for logging. + +Mimic what Xorg does instead. +--- + unix/xserver/hw/vnc/xvnc.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c +index ddb249937..a13168c47 100644 +--- a/unix/xserver/hw/vnc/xvnc.c ++++ b/unix/xserver/hw/vnc/xvnc.c +@@ -446,7 +446,7 @@ ddxProcessArgument(int argc, char *argv[], int i) + } + + if (!strcmp(argv[i], "-showconfig") || !strcmp(argv[i], "-version")) { +- /* Already shown at start */ ++ vncPrintBanner(); + exit(0); + } + +@@ -1171,8 +1171,11 @@ InitOutput(ScreenInfo * scrInfo, int argc, char **argv) + int i; + int NumFormats = 0; + +- if (serverGeneration == 1) ++ if (serverGeneration == 1) { ++ vncPrintBanner(); ++ + LoadExtensionList(vncExtensions, ARRAY_SIZE(vncExtensions), TRUE); ++ } + + #if XORG_AT_LEAST(1, 20, 0) + xorgGlxCreateVendor(); +@@ -1266,7 +1269,5 @@ vncClientGone(int fd) + int + main(int argc, char *argv[], char *envp[]) + { +- vncPrintBanner(); +- + return dix_main(argc, argv, envp); + } diff --git a/SPECS/tigervnc.spec b/SPECS/tigervnc.spec index ca9e6f9..8c5ca81 100644 --- a/SPECS/tigervnc.spec +++ b/SPECS/tigervnc.spec @@ -5,7 +5,7 @@ Name: tigervnc Version: 1.15.0 -Release: 1%{?dist} +Release: 5%{?dist} Summary: A TigerVNC remote display system %global _hardened_build 1 @@ -26,10 +26,15 @@ Patch1: tigervnc-use-gnome-as-default-session.patch # https://github.com/TigerVNC/tigervnc/pull/1425 Patch2: tigervnc-vncsession-restore-script-systemd-service.patch Patch3: tigervnc-dont-install-appstream-metadata-file.patch +# Only warn about passwords longer than 8 characters, but allow them to be used as in the past +Patch4: tigervnc-allow-use-of-passwords-longer-than-eight-characters.patch +# https://github.com/TigerVNC/tigervnc/pull/1792 +Patch5: tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch # Upstream patches Patch50: tigervnc-add-selinux-policy-rules-allowing-create-dirs-under-root-dir.patch Patch51: tigervnc-add-selinux-policy-rules-allowing-access-to-proc-sys-fs-nr-open.patch +Patch52: tigervnc-dont-print-xvnc-banner-before-parsing-args.patch # Upstreamable patches @@ -102,6 +107,11 @@ BuildRequires: xorg-x11-xtrans-devel BuildRequires: libselinux-devel BuildRequires: selinux-policy-devel +# For RHEL-91104 +BuildRequires: pkgconfig(dbus-1) >= 1.0 +BuildRequires: pkgconfig(libsystemd) >= 209 +BuildRequires: pkgconfig(libudev) >= 143 + Requires(post): coreutils Requires(postun):coreutils @@ -225,10 +235,13 @@ popd %patch -P1 -p1 -b .use-gnome-as-default-session %patch -P2 -p1 -b .vncsession-restore-script-systemd-service %patch -P3 -p1 -b .dont-install-appstream-metadata-file.patch +%patch -P4 -p1 -b .allow-use-of-passwords-longer-than-eight-characters +%patch -P5 -p1 -b .add-option-allowing-to-connect-only-user-owning-session # Upstream patches %patch -P50 -p1 -b .add-selinux-policy-rules-allowing-create-dirs-under-root-dir %patch -P51 -p1 -b .add-selinux-policy-rules-allowing-access-to-proc-sys-fs-nr-open +%patch -P52 -p1 -b .dont-print-xvnc-banner-before-parsing-args # Upstreamable patches @@ -257,7 +270,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 @@ -382,6 +397,23 @@ fi %ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} %changelog +* Tue May 27 2025 Jan Grulich - 1.15.0-5 +- Fix broken authentication with x0vncserver + Resolves: RHEL-93729 + +* Thu May 15 2025 Jan Grulich - 1.15.0-4 +- Add option "ApproveLoggedUserOnly" allowing to connect only the user + owning the running session + Resolves: RHEL-91104 + +* Wed Apr 30 2025 Jan Grulich - 1.15.0-3 +- Only warn about 8 characters limit, but let it proceed + Resolves: RHEL-89430 + +* Wed Apr 16 2025 Jan Grulich - 1.15.0-2 +- Fix inetd mode not working + Resolves: RHEL-86513 + * Wed Feb 26 2025 Jan Grulich - 1.15.0-1 - 1.15.0 Resolves: RHEL-79161