Add option "ApproveLoggedUserOnly" allowing to connect only the user

owning the running session

Resolves: RHEL-34880
This commit is contained in:
Jan Grulich 2024-09-27 12:10:44 +02:00
parent b3a7f8a95f
commit 8ed86c60ec
2 changed files with 240 additions and 4 deletions

View File

@ -0,0 +1,219 @@
From 8ac9bf0c061666d89d345a3d7149e1ef9c771655 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
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 <pwd.h>
+# include <systemd/sd-login.h>
+#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<network::SocketListener*> 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<network::SocketListener*>* 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.

View File

@ -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 <jgrulich@redhat.com> - 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 <jgrulich@redhat.com> - 1.14.0-3
- Move old log to log.old if present (fix patch)
Resolves: RHEL-54294
* Tue Aug 23 2024 Jan Grulich <jgrulich@redhat.com> - 1.14.0-2
* Tue Aug 20 2024 Jan Grulich <jgrulich@redhat.com> - 1.14.0-2
- 1.14.0
Resolves: RHEL-45316
- Move old log to log.old if present