diff --git a/tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch b/tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch new file mode 100644 index 0000000..141ef46 --- /dev/null +++ b/tigervnc-add-option-allowing-to-connect-only-user-owning-session.patch @@ -0,0 +1,219 @@ +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..dce1f6c 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,14 @@ 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.", ++ false); ++#endif + + XserverDesktop::XserverDesktop(int screenIndex_, + std::list listeners_, +@@ -168,11 +180,117 @@ 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; ++ ++ 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); ++ if (strcmp(display, serverDisplay.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_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..17df086 100644 +--- a/unix/xserver/hw/vnc/Xvnc.man ++++ b/unix/xserver/hw/vnc/Xvnc.man +@@ -204,6 +204,12 @@ 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. ++. ++.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/tigervnc.spec b/tigervnc.spec index acc89b3..60c8f79 100644 --- a/tigervnc.spec +++ b/tigervnc.spec @@ -5,7 +5,7 @@ Name: tigervnc Version: 1.14.0 -Release: 3%{?dist} +Release: 4%{?dist} Summary: A TigerVNC remote display system %global _hardened_build 1 @@ -23,7 +23,10 @@ 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 @@ -91,7 +94,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,6 +208,7 @@ 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 @@ -247,7 +257,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,11 +402,16 @@ fi %ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} %changelog +* 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 23 2024 Jan Grulich - 1.14.0-2 +* Tue Aug 20 2024 Jan Grulich - 1.14.0-2 - 1.14.0 Resolves: RHEL-45316 - Move old log to log.old if present