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()); +}