SYNERGY3-17 Stop on login screen (#7143)

* SYNERGY3-17 Stop on login screen

* SYNERGY3-17 Fix code smells

* SYNERGY3-17 Update ChangeLog
This commit is contained in:
Serhii Hadzhilov 2022-02-11 11:28:39 +02:00 committed by GitHub
parent bf102d4601
commit d3d7c36f58
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 236 additions and 23 deletions

View file

@ -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:

View file

@ -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")

View file

@ -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";

View file

@ -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;

View file

@ -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()
{

View file

@ -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:

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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;
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#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;
};

View file

@ -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;

View file

@ -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<unsigned long, PROCESS_INFORMATION> m_children;
std::map<unsigned long, PROCESS_INFORMATION> m_children;
};
//! Relauncher error

View file

@ -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<const IpcSettingMessage&>(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<IpcHelloMessage*>(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;
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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());
}