From 0c83a86bc858a3bc9fbc5d56238436553162c7a0 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Tue, 13 Oct 2020 13:38:18 +0300 Subject: [PATCH] Dynamically apply permissions --- common/rfb/VNCSConnectionST.cxx | 18 ++++++++++- common/rfb/VNCSConnectionST.h | 6 ++++ common/rfb/VNCServerST.cxx | 54 +++++++++++++++++++++++++++++++++ common/rfb/VNCServerST.h | 2 ++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index 9b31d6c..c8af424 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -59,7 +59,7 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, losslessTimer(this), kbdLogTimer(this), server(server_), updates(false), updateRenderedCursor(false), removeRenderedCursor(false), continuousUpdates(false), encodeManager(this, &server_->encCache), - pointerEventTime(0), + needsPermCheck(false), pointerEventTime(0), clientHasCursor(false), accessRights(AccessDefault), startTime(time(0)) { @@ -1126,6 +1126,22 @@ void VNCSConnectionST::writeFramebufferUpdate() if (isCongested()) return; + // Check for permission changes? + if (needsPermCheck) { + needsPermCheck = false; + + bool write, owner, ret; + ret = getPerms(write, owner); + if (!ret) { + close("User was deleted"); + return; + } else if (!write) { + accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents)); + } else { + accessRights |= AccessPtrEvents | AccessKeyEvents; + } + } + // Updates often consists of many small writes, and in continuous // mode, we will also have small fence messages around the update. We // need to aggregate these in order to not clog up TCP's congestion diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index 6c9f3ee..a0c1025 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -102,6 +102,10 @@ namespace rfb { // or because the current cursor position has not been set by this client. bool needRenderedCursor(); + void recheckPerms() { + needsPermCheck = true; + } + network::Socket* getSock() { return sock; } void add_changed(const Region& region) { updates.add_changed(region); } void add_changed_all() { updates.add_changed(server->pb->getRect()); } @@ -190,6 +194,7 @@ namespace rfb { bool write, owner; if (!getPerms(write, owner) || !write) accessRights = (accessRights & ~(AccessPtrEvents | AccessKeyEvents)); + needsPermCheck = false; } // Timer callbacks @@ -259,6 +264,7 @@ namespace rfb { char user[32]; char kasmpasswdpath[4096]; + bool needsPermCheck; time_t lastEventTime; time_t pointerEventTime; diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 0577ec0..1ac8597 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -63,6 +63,11 @@ #include +#include +#include +#include +#include + using namespace rfb; static LogWriter slog("VNCServerST"); @@ -73,6 +78,9 @@ EncCache VNCServerST::encCache; // -=- VNCServerST Implementation // +static char kasmpasswdpath[4096]; +extern rfb::StringParameter basicauth; + // -=- Constructors/Destructor VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) @@ -87,6 +95,26 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) { lastUserInputTime = lastDisconnectTime = time(0); slog.debug("creating single-threaded server %s", name.buf); + + kasmpasswdpath[0] = '\0'; + wordexp_t wexp; + if (!wordexp(rfb::Server::kasmPasswordFile, &wexp, WRDE_NOCMD)) + strncpy(kasmpasswdpath, wexp.we_wordv[0], 4096); + kasmpasswdpath[4095] = '\0'; + wordfree(&wexp); + + if (kasmpasswdpath[0] && access(kasmpasswdpath, R_OK) == 0) { + // Set up a watch on the password file + inotifyfd = inotify_init(); + if (inotifyfd < 0) + slog.error("Failed to init inotify"); + + int flags = fcntl(inotifyfd, F_GETFL, 0); + fcntl(inotifyfd, F_SETFL, flags | O_NONBLOCK); + + if (inotify_add_watch(inotifyfd, kasmpasswdpath, IN_CLOSE_WRITE | IN_DELETE_SELF) < 0) + slog.error("Failed to set watch"); + } } VNCServerST::~VNCServerST() @@ -659,8 +687,34 @@ void VNCServerST::writeUpdate() encCache.clear(); encCache.enabled = clients.size() > 1; + // Check if the password file was updated + bool permcheck = false; + if (inotifyfd >= 0) { + char buf[256]; + int ret = read(inotifyfd, buf, 256); + int pos = 0; + while (ret > 0) { + const struct inotify_event * const ev = (struct inotify_event *) &buf[pos]; + + if (ev->mask & IN_IGNORED) { + // file was deleted, set new watch + if (inotify_add_watch(inotifyfd, kasmpasswdpath, IN_CLOSE_WRITE | IN_DELETE_SELF) < 0) + slog.error("Failed to set watch"); + } + + permcheck = true; + + ret -= sizeof(struct inotify_event) - ev->len; + pos += sizeof(struct inotify_event) - ev->len; + } + } + for (ci = clients.begin(); ci != clients.end(); ci = ci_next) { ci_next = ci; ci_next++; + + if (permcheck) + (*ci)->recheckPerms(); + (*ci)->add_copied(ui.copied, ui.copy_delta); (*ci)->add_copypassed(ui.copypassed); (*ci)->add_changed(ui.changed); diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index 7eaf896..ef6e3e0 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -249,6 +249,8 @@ namespace rfb { bool disableclients; Timer frameTimer; + + int inotifyfd; }; };