From d3d7c36f587355fb9e7aa6b33286f1263e6827d3 Mon Sep 17 00:00:00 2001
From: Serhii Hadzhilov <71632867+SerhiiGadzhilov@users.noreply.github.com>
Date: Fri, 11 Feb 2022 11:28:39 +0200
Subject: [PATCH] SYNERGY3-17 Stop on login screen (#7143)
* SYNERGY3-17 Stop on login screen
* SYNERGY3-17 Fix code smells
* SYNERGY3-17 Update ChangeLog
---
ChangeLog | 6 ++
cmake/Version.cmake | 2 +-
src/lib/ipc/Ipc.cpp | 7 +-
src/lib/ipc/Ipc.h | 6 ++
src/lib/ipc/IpcClientProxy.cpp | 16 +++++
src/lib/ipc/IpcClientProxy.h | 4 +-
src/lib/ipc/IpcSettingMessage.cpp | 38 ++++++++++
src/lib/ipc/IpcSettingMessage.h | 50 +++++++++++++
src/lib/platform/MSWindowsWatchdog.cpp | 71 +++++++++++++++----
src/lib/platform/MSWindowsWatchdog.h | 5 +-
src/lib/synergy/DaemonApp.cpp | 23 +++++-
.../unittests/ipc/IpcSettingMessageTests.cpp | 31 ++++++++
12 files changed, 236 insertions(+), 23 deletions(-)
create mode 100644 src/lib/ipc/IpcSettingMessage.cpp
create mode 100644 src/lib/ipc/IpcSettingMessage.h
create mode 100644 src/test/unittests/ipc/IpcSettingMessageTests.cpp
diff --git a/ChangeLog b/ChangeLog
index e231679ff..7ca713313 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+v1.14.4-snapshot
+===========
+Enhancements:
+- #7143 Add ability to stop synergy on the login screen
+===========
+
v1.14.3-snapshot
===========
Bug fixes:
diff --git a/cmake/Version.cmake b/cmake/Version.cmake
index d580ceee7..032d3cbed 100644
--- a/cmake/Version.cmake
+++ b/cmake/Version.cmake
@@ -6,7 +6,7 @@ cmake_minimum_required (VERSION 3.4)
set (SYNERGY_VERSION_MAJOR 1)
set (SYNERGY_VERSION_MINOR 14)
-set (SYNERGY_VERSION_PATCH 3)
+set (SYNERGY_VERSION_PATCH 4)
set (SYNERGY_VERSION_BUILD 1)
set (SYNERGY_VERSION_STAGE "snapshot")
diff --git a/src/lib/ipc/Ipc.cpp b/src/lib/ipc/Ipc.cpp
index c0667714c..7e5eeb565 100644
--- a/src/lib/ipc/Ipc.cpp
+++ b/src/lib/ipc/Ipc.cpp
@@ -19,6 +19,7 @@
#include "ipc/Ipc.h"
const char* kIpcMsgHello = "IHEL%1i";
-const char* kIpcMsgLogLine = "ILOG%s";
-const char* kIpcMsgCommand = "ICMD%s%1i";
-const char* kIpcMsgShutdown = "ISDN";
+const char* kIpcMsgLogLine = "ILOG%s";
+const char* kIpcMsgCommand = "ICMD%s%1i";
+const char* kIpcMsgShutdown = "ISDN";
+const char* kIpcMsgSetting = "SSET%s%s";
diff --git a/src/lib/ipc/Ipc.h b/src/lib/ipc/Ipc.h
index b4a4e201e..66161bfda 100644
--- a/src/lib/ipc/Ipc.h
+++ b/src/lib/ipc/Ipc.h
@@ -26,6 +26,7 @@ enum EIpcMessage {
kIpcLogLine,
kIpcCommand,
kIpcShutdown,
+ kIpcSetting
};
enum EIpcClientType {
@@ -50,3 +51,8 @@ extern const char* kIpcMsgCommand;
// shutdown: daemon -> node
// the daemon tells synergys/c to shut down gracefully.
extern const char* kIpcMsgShutdown;
+
+// set setting: gui -> daemon
+// $1 = setting name
+// $2 = setting value
+extern const char* kIpcMsgSetting;
diff --git a/src/lib/ipc/IpcClientProxy.cpp b/src/lib/ipc/IpcClientProxy.cpp
index bbebf9a88..c67d7d6c3 100644
--- a/src/lib/ipc/IpcClientProxy.cpp
+++ b/src/lib/ipc/IpcClientProxy.cpp
@@ -20,6 +20,7 @@
#include "ipc/Ipc.h"
#include "ipc/IpcMessage.h"
+#include "ipc/IpcSettingMessage.h"
#include "synergy/ProtocolUtil.h"
#include "io/IStream.h"
#include "arch/Arch.h"
@@ -117,6 +118,9 @@ IpcClientProxy::handleData(const Event&, void*)
else if (memcmp(code, kIpcMsgCommand, 4) == 0) {
m = parseCommand();
}
+ else if (memcmp(code, kIpcMsgSetting, 4) == 0) {
+ m = parseSetting();
+ }
else {
LOG((CLOG_ERR "invalid ipc message"));
disconnect();
@@ -184,6 +188,18 @@ IpcClientProxy::parseCommand()
return new IpcCommandMessage(command, elevate != 0);
}
+IpcSettingMessage*
+IpcClientProxy::parseSetting() const
+{
+ String name;
+ String value;
+
+ ProtocolUtil::readf(&m_stream, kIpcMsgSetting + 4, &name, &value);
+
+ // must be deleted by event handler.
+ return new IpcSettingMessage(name, value);
+}
+
void
IpcClientProxy::disconnect()
{
diff --git a/src/lib/ipc/IpcClientProxy.h b/src/lib/ipc/IpcClientProxy.h
index 6dae2c4ce..09691f171 100644
--- a/src/lib/ipc/IpcClientProxy.h
+++ b/src/lib/ipc/IpcClientProxy.h
@@ -26,6 +26,7 @@
namespace synergy { class IStream; }
class IpcMessage;
class IpcCommandMessage;
+class IpcSettingMessage;
class IpcHelloMessage;
class IEventQueue;
@@ -47,7 +48,8 @@ private:
void handleDisconnect(const Event&, void*);
void handleWriteError(const Event&, void*);
IpcHelloMessage* parseHello();
- IpcCommandMessage* parseCommand();
+ IpcCommandMessage* parseCommand();
+ IpcSettingMessage* parseSetting() const;
void disconnect();
private:
diff --git a/src/lib/ipc/IpcSettingMessage.cpp b/src/lib/ipc/IpcSettingMessage.cpp
new file mode 100644
index 000000000..a37aaa3e0
--- /dev/null
+++ b/src/lib/ipc/IpcSettingMessage.cpp
@@ -0,0 +1,38 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2012 Nick Bolton
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "IpcSettingMessage.h"
+
+IpcSettingMessage::IpcSettingMessage(const std::string& name, const std::string& value) :
+ IpcMessage(kIpcSetting),
+ m_name(name),
+ m_value(value)
+{
+
+}
+
+const std::string& IpcSettingMessage::getName() const
+{
+ return m_name;
+}
+
+const std::string& IpcSettingMessage::getValue() const
+{
+ return m_value;
+}
+
diff --git a/src/lib/ipc/IpcSettingMessage.h b/src/lib/ipc/IpcSettingMessage.h
new file mode 100644
index 000000000..ae82fc2ec
--- /dev/null
+++ b/src/lib/ipc/IpcSettingMessage.h
@@ -0,0 +1,50 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * Copyright (C) 2012 Nick Bolton
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include
+#include "IpcMessage.h"
+
+class IpcSettingMessage : public IpcMessage
+{
+public:
+ //!
+ //! \brief IpcSettingMessage constructor
+ //! \param name - setting name
+ //! \param value - setting value
+ //!
+ IpcSettingMessage(const std::string& name, const std::string& value);
+
+ //!
+ //! \brief getName is a getter for the setting name
+ //! \return setting name
+ //!
+ const std::string& getName() const;
+
+ //!
+ //! \brief getValue is a getter for the setting value
+ //! \return setting value
+ //!
+ const std::string& getValue() const;
+
+private:
+ std::string m_name;
+ std::string m_value;
+};
+
diff --git a/src/lib/platform/MSWindowsWatchdog.cpp b/src/lib/platform/MSWindowsWatchdog.cpp
index 96448d4d4..6c9750cf1 100644
--- a/src/lib/platform/MSWindowsWatchdog.cpp
+++ b/src/lib/platform/MSWindowsWatchdog.cpp
@@ -39,6 +39,42 @@
#define CURRENT_PROCESS_ID 0
#define MAXIMUM_WAIT_TIME 3
+
+namespace {
+std::string
+trimDesktopName(const std::string& nameFromTraces)
+{
+ std::string name;
+
+ for (const auto& symbol : nameFromTraces) {
+ if (std::isalpha(symbol)) {
+ name.push_back(symbol);
+ }
+ else {
+ break;
+ }
+ }
+
+ return name;
+}
+
+bool
+isDesktopRunnable(const std::string& desktopName)
+{
+ const std::string winlogon = "Winlogon";
+ bool isNotLoginScreen = std::strncmp(desktopName.c_str(),
+ winlogon.c_str(),
+ winlogon.length());
+
+ const auto setting = ARCH->setting("runOnLoginScreen");
+ bool runOnLoginScreen = (setting.empty() || setting == "true");
+
+ return (runOnLoginScreen || isNotLoginScreen);
+}
+
+}//namespace
+
+
enum {
kOutputBufferSize = 4096
};
@@ -315,17 +351,22 @@ MSWindowsWatchdog::startProcess()
getActiveDesktop(&sa);
- ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
- HANDLE userToken = getUserToken(&sa);
- m_elevateProcess = m_autoElevated ? m_autoElevated : m_elevateProcess;
- m_autoElevated = false;
+ if (!isDesktopRunnable(m_activeDesktop)) {
+ LOG((CLOG_INFO, "Starting on the login screen is disabled!"));
+ return;
+ }
- // patch by Jack Zhou and Henry Tung
- // set UIAccess to fix Windows 8 GUI interaction
- DWORD uiAccess = 1;
- SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD));
+ ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
+ HANDLE userToken = getUserToken(&sa);
+ m_elevateProcess = m_autoElevated ? m_autoElevated : m_elevateProcess;
+ m_autoElevated = false;
- createRet = startProcessAsUser(m_command, userToken, &sa);
+ // patch by Jack Zhou and Henry Tung
+ // set UIAccess to fix Windows 8 GUI interaction
+ DWORD uiAccess = 1;
+ SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD));
+
+ createRet = startProcessAsUser(m_command, userToken, &sa);
}
if (!createRet) {
@@ -636,7 +677,7 @@ MSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security)
ARCH->unlockMutex(m_mutex);
closeProcessHandles(pid);
}
-}
+}
void
MSWindowsWatchdog::testOutput(String buffer)
@@ -645,11 +686,11 @@ MSWindowsWatchdog::testOutput(String buffer)
size_t i = buffer.find(g_activeDesktop);
if (i != String::npos) {
size_t s = sizeof(g_activeDesktop);
- String defaultDesktop("Default");
- String sub = buffer.substr(i + s - 1, defaultDesktop.size());
- if (sub != defaultDesktop) {
- m_autoElevated = true;
- }
+ std::string defaultScreen = "Default";
+ m_activeDesktop = trimDesktopName(buffer.substr(i + s - 1));
+ m_autoElevated = std::strncmp(m_activeDesktop.c_str(),
+ defaultScreen.c_str(),
+ defaultScreen.length());
ARCH->lockMutex(m_mutex);
m_ready = true;
diff --git a/src/lib/platform/MSWindowsWatchdog.h b/src/lib/platform/MSWindowsWatchdog.h
index 6a1d38adf..2b9ad3d98 100644
--- a/src/lib/platform/MSWindowsWatchdog.h
+++ b/src/lib/platform/MSWindowsWatchdog.h
@@ -96,12 +96,13 @@ private:
ArchMutex m_mutex;
ArchCond m_condVar;
bool m_ready;
- bool m_foreground;
+ bool m_foreground;
+ std::string m_activeDesktop;
/// @brief Save the info of all process made
/// We will use this to track all processes we make and
/// kill off handels and children that we no longer need
- std::map m_children;
+ std::map m_children;
};
//! Relauncher error
diff --git a/src/lib/synergy/DaemonApp.cpp b/src/lib/synergy/DaemonApp.cpp
index 7d09fb311..8f6e4f518 100644
--- a/src/lib/synergy/DaemonApp.cpp
+++ b/src/lib/synergy/DaemonApp.cpp
@@ -27,6 +27,7 @@
#include "synergy/ClientArgs.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
+#include "ipc/IpcSettingMessage.h"
#include "ipc/IpcLogOutputter.h"
#include "net/SocketMultiplexer.h"
#include "arch/XArch.h"
@@ -58,6 +59,21 @@
using namespace std;
+namespace {
+void
+updateSetting(const IpcMessage& message)
+{
+ try {
+ auto setting = static_cast(message);
+ ARCH->setting(setting.getName(), setting.getValue());
+ }
+ catch (const XArch& e) {
+ LOG((CLOG_ERR "failed to save setting: %s", e.what()));
+ }
+}
+
+}//namespace
+
DaemonApp* DaemonApp::s_instance = NULL;
int
@@ -362,7 +378,7 @@ DaemonApp::handleIpcMessage(const Event& e, void*)
break;
}
- case kIpcHello:
+ case kIpcHello: {
IpcHelloMessage* hm = static_cast(m);
String type;
switch (hm->clientType()) {
@@ -380,5 +396,10 @@ DaemonApp::handleIpcMessage(const Event& e, void*)
m_ipcLogOutputter->notifyBuffer();
break;
+ }
+
+ case kIpcSetting:
+ updateSetting(*m);
+ break;
}
}
diff --git a/src/test/unittests/ipc/IpcSettingMessageTests.cpp b/src/test/unittests/ipc/IpcSettingMessageTests.cpp
new file mode 100644
index 000000000..7b42893f6
--- /dev/null
+++ b/src/test/unittests/ipc/IpcSettingMessageTests.cpp
@@ -0,0 +1,31 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2015-2022 Symless Ltd.
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#define TEST_ENV
+
+#include "ipc/IpcSettingMessage.h"
+#include "test/global/gtest.h"
+
+TEST(IpcSettingMessage, testIpcSettingMessage) {
+ const std::string expected_name = "test";
+ const std::string expected_value = "test_value";
+
+ IpcSettingMessage message("test", "test_value");
+
+ EXPECT_EQ(expected_name, message.getName());
+ EXPECT_EQ(expected_value, message.getValue());
+}