Skip to content

Commit

Permalink
Add option allowing to connect only the user owning the running session
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
grulja committed Oct 4, 2024
1 parent 2fe9dca commit 4011f01
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 8 deletions.
7 changes: 0 additions & 7 deletions common/rfb/VNCServerST.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -680,13 +680,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))
{
Expand Down
125 changes: 124 additions & 1 deletion unix/xserver/hw/vnc/XserverDesktop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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<network::SocketListener*> listeners_,
Expand Down Expand Up @@ -165,11 +178,121 @@ 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);
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_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;
Expand Down
7 changes: 7 additions & 0 deletions unix/xserver/hw/vnc/XserverDesktop.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
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<network::SocketListener*>* sockets,
rfb::VNCServer* sockserv);
Expand Down
7 changes: 7 additions & 0 deletions unix/xserver/hw/vnc/Xvnc.man
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 4011f01

Please sign in to comment.