diff --git a/src/lib/platform/MSWindowsSession.cpp b/src/lib/platform/MSWindowsSession.cpp index b9001a8d..a902bf16 100644 --- a/src/lib/platform/MSWindowsSession.cpp +++ b/src/lib/platform/MSWindowsSession.cpp @@ -171,3 +171,21 @@ CMSWindowsSession::nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry) return gotEntry; } + +CString +CMSWindowsSession::getActiveDesktopName() +{ + CString result; + + HDESK hd = OpenInputDesktop(0, TRUE, GENERIC_READ); + if (hd != NULL) { + DWORD size; + GetUserObjectInformation(hd, UOI_NAME, NULL, 0, &size); + TCHAR* name = (TCHAR*)alloca(size + sizeof(TCHAR)); + GetUserObjectInformation(hd, UOI_NAME, name, size, &size); + result = name; + CloseDesktop(hd); + } + + return result; +} diff --git a/src/lib/platform/MSWindowsSession.h b/src/lib/platform/MSWindowsSession.h index d30ce0b4..b4f21243 100644 --- a/src/lib/platform/MSWindowsSession.h +++ b/src/lib/platform/MSWindowsSession.h @@ -17,6 +17,8 @@ #pragma once +#include "base/String.h" + #define WIN32_LEAN_AND_MEAN #include #include @@ -40,6 +42,8 @@ public: void updateActiveSession(); + CString getActiveDesktopName(); + private: BOOL nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry); diff --git a/src/lib/platform/MSWindowsWatchdog.cpp b/src/lib/platform/MSWindowsWatchdog.cpp index 0dc020f2..8bf98b3c 100644 --- a/src/lib/platform/MSWindowsWatchdog.cpp +++ b/src/lib/platform/MSWindowsWatchdog.cpp @@ -43,6 +43,8 @@ enum { typedef VOID (WINAPI *SendSas)(BOOL asUser); +const char g_activeDesktop[] = {"activeDesktop:"}; + CMSWindowsWatchdog::CMSWindowsWatchdog( bool autoDetectCommand, CIpcServer& ipcServer, @@ -58,12 +60,23 @@ CMSWindowsWatchdog::CMSWindowsWatchdog( m_elevateProcess(false), m_processFailures(0), m_processRunning(false), - m_fileLogOutputter(NULL) + m_fileLogOutputter(NULL), + m_autoElevated(false), + m_ready(false) { + m_mutex = ARCH->newMutex(); + m_condVar = ARCH->newCondVar(); } CMSWindowsWatchdog::~CMSWindowsWatchdog() { + if (m_condVar != NULL) { + ARCH->closeCondVar(m_condVar); + } + + if (m_mutex != NULL) { + ARCH->closeMutex(m_mutex); + } } void @@ -126,7 +139,9 @@ CMSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security) // elevate for the uac dialog (consent.exe) but this would be pointless, // since synergy would re-launch as non-elevated after the desk switch, // and so would be unusable with the new elevated process taking focus. - if (m_elevateProcess || m_session.isProcessInSession("logonui.exe", NULL)) { + if (m_elevateProcess + || m_autoElevated + || m_session.isProcessInSession("logonui.exe", NULL)) { LOG((CLOG_DEBUG "getting elevated token, %s", (m_elevateProcess ? "elevation required" : "at login screen"))); @@ -273,7 +288,11 @@ CMSWindowsWatchdog::startProcess() SECURITY_ATTRIBUTES sa; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + getActiveDesktop(&sa); + + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); HANDLE userToken = getUserToken(&sa); + m_autoElevated = false; // patch by Jack Zhou and Henry Tung // set UIAccess to fix Windows 8 GUI interaction @@ -281,6 +300,33 @@ CMSWindowsWatchdog::startProcess() DWORD uiAccess = 1; SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD)); + BOOL createRet = doStartProcess(m_command, userToken, &sa); + + if (!createRet) { + LOG((CLOG_ERR "could not launch")); + DWORD exitCode = 0; + GetExitCodeProcess(m_processInfo.hProcess, &exitCode); + LOG((CLOG_ERR "exit code: %d", exitCode)); + throw XArch(new XArchEvalWindows); + } + else { + // wait for program to fail. + ARCH->sleep(1); + if (!isProcessActive()) { + throw XMSWindowsWatchdogError("process immediately stopped"); + } + + m_processRunning = true; + m_processFailures = 0; + + LOG((CLOG_DEBUG "started process, session=%i, command=%s", + m_session.getActiveSessionId(), m_command.c_str())); + } +} + +BOOL +CMSWindowsWatchdog::doStartProcess(CString& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa) +{ // clear, as we're reusing process info struct ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); @@ -307,30 +353,14 @@ CMSWindowsWatchdog::startProcess() // re-launch in current active user session LOG((CLOG_INFO "starting new process")); BOOL createRet = CreateProcessAsUser( - userToken, NULL, LPSTR(m_command.c_str()), - &sa, NULL, TRUE, creationFlags, + userToken, NULL, LPSTR(command.c_str()), + sa, NULL, TRUE, creationFlags, environment, NULL, &si, &m_processInfo); DestroyEnvironmentBlock(environment); CloseHandle(userToken); - if (!createRet) { - LOG((CLOG_ERR "could not launch")); - throw XArch(new XArchEvalWindows); - } - else { - // wait for program to fail. - ARCH->sleep(1); - if (!isProcessActive()) { - throw XMSWindowsWatchdogError("process immediately stopped"); - } - - m_processRunning = true; - m_processFailures = 0; - - LOG((CLOG_DEBUG "started process, session=%i, command=%s", - m_session.getActiveSessionId(), m_command.c_str())); - } + return createRet; } void @@ -388,6 +418,8 @@ CMSWindowsWatchdog::outputLoop(void*) else { buffer[bytesRead] = '\0'; + testOutput(buffer); + // send process output over IPC to GUI, and force it to be sent // which bypasses the ipc logging anti-recursion mechanism. m_ipcLogOutputter.write(kINFO, buffer, true); @@ -492,3 +524,57 @@ CMSWindowsWatchdog::shutdownExistingProcesses() CloseHandle(snapshot); m_processRunning = false; } + +void +CMSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security) +{ + CString installedDir = ARCH->getInstalledDirectory(); + if (!installedDir.empty()) { + CString syntoolCommand; + syntoolCommand.append("\"").append(installedDir).append("\\").append("syntool").append("\""); + syntoolCommand.append(" --get-active-desktop"); + + m_session.updateActiveSession(); + bool elevateProcess = m_elevateProcess; + m_elevateProcess = true; + HANDLE userToken = getUserToken(security); + m_elevateProcess = elevateProcess; + + BOOL createRet = doStartProcess(syntoolCommand, userToken, security); + + if (!createRet) { + DWORD rc = GetLastError(); + RevertToSelf(); + } + else { + LOG((CLOG_DEBUG "launched syntool to check active desktop")); + } + + ARCH->lockMutex(m_mutex); + while (!m_ready) { + ARCH->waitCondVar(m_condVar, m_mutex, 1.0); + } + m_ready = false; + ARCH->unlockMutex(m_mutex); + } +} + +void +CMSWindowsWatchdog::testOutput(CString buffer) +{ + // HACK: check standard output seems hacky. + size_t i = buffer.find(g_activeDesktop); + if (i != CString::npos) { + size_t s = sizeof(g_activeDesktop); + CString defaultDesktop("Default"); + CString sub = buffer.substr(s - 1, defaultDesktop.size()); + if (sub != defaultDesktop) { + m_autoElevated = true; + } + + ARCH->lockMutex(m_mutex); + m_ready = true; + ARCH->broadcastCondVar(m_condVar); + ARCH->unlockMutex(m_mutex); + } +} diff --git a/src/lib/platform/MSWindowsWatchdog.h b/src/lib/platform/MSWindowsWatchdog.h index 9dd60285..4d2b1166 100644 --- a/src/lib/platform/MSWindowsWatchdog.h +++ b/src/lib/platform/MSWindowsWatchdog.h @@ -20,6 +20,7 @@ #include "platform/MSWindowsSession.h" #include "synergy/XSynergy.h" +#include "arch/IArchMultithread.h" #define WIN32_LEAN_AND_MEAN #include @@ -54,7 +55,10 @@ private: HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security); HANDLE getUserToken(LPSECURITY_ATTRIBUTES security); void startProcess(); + BOOL doStartProcess(CString& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa); void sendSas(); + void getActiveDesktop(LPSECURITY_ATTRIBUTES security); + void testOutput(CString buffer); private: CThread* m_thread; @@ -73,6 +77,10 @@ private: int m_processFailures; bool m_processRunning; CFileLogOutputter* m_fileLogOutputter; + bool m_autoElevated; + CArchMutex m_mutex; + CArchCond m_condVar; + bool m_ready; }; //! Relauncher error diff --git a/src/lib/synergy/App.cpp b/src/lib/synergy/App.cpp index 7f7d4305..bbfc20cd 100644 --- a/src/lib/synergy/App.cpp +++ b/src/lib/synergy/App.cpp @@ -244,3 +244,80 @@ CApp::runEventsLoop(void*) #endif } + +// +// CMinimalApp +// + +CMinimalApp::CMinimalApp() : + CApp(NULL, NULL, new CArgsBase()) +{ + setEvents(m_events); +} + +CMinimalApp::~CMinimalApp() +{ +} + +int +CMinimalApp::standardStartup(int argc, char** argv) +{ + return 0; +} + +int +CMinimalApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) +{ + return 0; +} + +void +CMinimalApp::startNode() +{ +} + +int +CMinimalApp::mainLoop() +{ + return 0; +} + +int +CMinimalApp::foregroundStartup(int argc, char** argv) +{ + return 0; +} + +CScreen* +CMinimalApp::createScreen() +{ + return NULL; +} + +void +CMinimalApp::loadConfig() +{ +} + +bool +CMinimalApp::loadConfig(const CString& pathname) +{ + return false; +} + +const char* +CMinimalApp::daemonInfo() const +{ + return ""; +} + +const char* +CMinimalApp::daemonName() const +{ + return ""; +} + +void +CMinimalApp::parseArgs(int argc, const char* const* argv) +{ +} diff --git a/src/lib/synergy/App.h b/src/lib/synergy/App.h index e389aa23..6f7f28c0 100644 --- a/src/lib/synergy/App.h +++ b/src/lib/synergy/App.h @@ -18,10 +18,12 @@ #pragma once -#include "common/common.h" -#include "base/String.h" -#include "synergy/IApp.h" #include "ipc/IpcClient.h" +#include "synergy/IApp.h" +#include "base/String.h" +#include "base/Log.h" +#include "base/EventQueue.h" +#include "common/common.h" #if SYSAPI_WIN32 #include "synergy/win32/AppUtilWindows.h" @@ -96,6 +98,8 @@ public: void setSocketMultiplexer(CSocketMultiplexer* sm) { m_socketMultiplexer = sm; } CSocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; } + void setEvents(CEventQueue& events) { m_events = &events; } + private: void handleIpcMessage(const CEvent&, void*); @@ -118,6 +122,30 @@ private: CSocketMultiplexer* m_socketMultiplexer; }; +class CMinimalApp : public CApp { +public: + CMinimalApp(); + virtual ~CMinimalApp(); + + // IApp overrides + virtual int standardStartup(int argc, char** argv); + virtual int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup); + virtual void startNode(); + virtual int mainLoop(); + virtual int foregroundStartup(int argc, char** argv); + virtual CScreen* createScreen(); + virtual void loadConfig(); + virtual bool loadConfig(const CString& pathname); + virtual const char* daemonInfo() const; + virtual const char* daemonName() const; + virtual void parseArgs(int argc, const char* const* argv); + +private: + CArch m_arch; + CLog m_log; + CEventQueue m_events; +}; + #if WINAPI_MSWINDOWS #define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_) #else diff --git a/src/lib/synergy/ArgParser.cpp b/src/lib/synergy/ArgParser.cpp index c7ae05f3..3b8ff6f3 100644 --- a/src/lib/synergy/ArgParser.cpp +++ b/src/lib/synergy/ArgParser.cpp @@ -20,6 +20,7 @@ #include "synergy/App.h" #include "synergy/ServerArgs.h" #include "synergy/ClientArgs.h" +#include "synergy/ToolArgs.h" #include "synergy/ArgsBase.h" #include "base/Log.h" @@ -155,6 +156,23 @@ CArgParser::parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* c #endif } + +bool +CArgParser::parseToolArgs(CToolArgs& args, int argc, const char* const* argv) +{ + for (int i = 1; i < argc; ++i) { + if (isArg(i, argc, argv, NULL, "--get-active-desktop", 0)) { + args.m_printActiveDesktopName = true; + return true; + } + else { + return false; + } + } + + return false; +} + bool CArgParser::parseGenericArgs(int argc, const char* const* argv, int& i) { diff --git a/src/lib/synergy/ArgParser.h b/src/lib/synergy/ArgParser.h index a9cc04eb..0fc56546 100644 --- a/src/lib/synergy/ArgParser.h +++ b/src/lib/synergy/ArgParser.h @@ -34,6 +34,7 @@ public: bool parseServerArgs(CServerArgs& args, int argc, const char* const* argv); bool parseClientArgs(CClientArgs& args, int argc, const char* const* argv); bool parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* const* argv, int& i); + bool parseToolArgs(CToolArgs& args, int argc, const char* const* argv); bool parseGenericArgs(int argc, const char* const* argv, int& i); void setArgsBase(CArgsBase& argsBase) { m_argsBase = &argsBase; } diff --git a/src/lib/synergy/ToolApp.cpp b/src/lib/synergy/ToolApp.cpp index 83ee58c2..03035c61 100644 --- a/src/lib/synergy/ToolApp.cpp +++ b/src/lib/synergy/ToolApp.cpp @@ -16,14 +16,18 @@ */ #include "synergy/ToolApp.h" + +#include "synergy/ArgParser.h" #include "arch/Arch.h" +#include "base/Log.h" #include "base/String.h" #include #include - -//#define PREMIUM_AUTH_URL "http://localhost/synergy/premium/json/auth/" -#define PREMIUM_AUTH_URL "https://synergy-project.org/premium/json/auth/" + +#if SYSAPI_WIN32 +#include "platform/MSWindowsSession.h" +#endif enum { kErrorOk, @@ -41,43 +45,43 @@ CToolApp::run(int argc, char** argv) } try { - for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "--premium-auth") == 0) { - premiumAuth(); - return kErrorOk; + CArgParser argParser(this); + bool result = argParser.parseToolArgs(m_args, argc, argv); + + if (!result) { + m_bye(kExitArgs); + } + + if (m_args.m_printActiveDesktopName) { +#if SYSAPI_WIN32 + CMSWindowsSession session; + CString name = session.getActiveDesktopName(); + if (name.empty()) { + LOG((CLOG_CRIT "failed to get active desktop name")); + return kExitFailed; } else { - std::cerr << "unknown arg: " << argv[i] << std::endl; - return kErrorArgs; + std::cout << "activeDesktop:" << name.c_str() << std::endl; } +#endif + } + else { + throw XSynergy("Nothing to do"); } } catch (std::exception& e) { - std::cerr << e.what() << std::endl; - return kErrorException; + LOG((CLOG_CRIT "An error occurred: %s\n", e.what())); + return kExitFailed; } catch (...) { - std::cerr << "unknown error" << std::endl; - return kErrorUnknown; + LOG((CLOG_CRIT "An unknown error occurred.\n")); + return kExitFailed; } return kErrorOk; } void -CToolApp::premiumAuth() +CToolApp::help() { - CString credentials; - std::cin >> credentials; - - size_t separator = credentials.find(':'); - CString email = credentials.substr(0, separator); - CString password = credentials.substr(separator + 1, credentials.length()); - - std::stringstream ss; - ss << PREMIUM_AUTH_URL; - ss << "?email=" << ARCH->internet().urlEncode(email); - ss << "&password=" << password; - - std::cout << ARCH->internet().get(ss.str()) << std::endl; } diff --git a/src/lib/synergy/ToolApp.h b/src/lib/synergy/ToolApp.h index a28b74f7..ebca6798 100644 --- a/src/lib/synergy/ToolApp.h +++ b/src/lib/synergy/ToolApp.h @@ -17,12 +17,15 @@ #pragma once +#include "synergy/App.h" +#include "synergy/ToolArgs.h" #include "common/basic_types.h" -class CToolApp { +class CToolApp : public CMinimalApp +{ public: UInt32 run(int argc, char** argv); - + void help(); private: - void premiumAuth(); + CToolArgs m_args; }; diff --git a/src/lib/synergy/ToolArgs.cpp b/src/lib/synergy/ToolArgs.cpp new file mode 100644 index 00000000..006a1dfb --- /dev/null +++ b/src/lib/synergy/ToolArgs.cpp @@ -0,0 +1,23 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2014 Synergy Si, Inc. + * + * 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 COPYING 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 "synergy/ToolArgs.h" + +CToolArgs::CToolArgs() : + m_printActiveDesktopName(false) +{ +} diff --git a/src/lib/synergy/ToolArgs.h b/src/lib/synergy/ToolArgs.h new file mode 100644 index 00000000..ca0a9ce0 --- /dev/null +++ b/src/lib/synergy/ToolArgs.h @@ -0,0 +1,28 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2014 Synergy Si, Inc. + * + * 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 COPYING 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 "base/String.h" + +class CToolArgs { +public: + CToolArgs(); + +public: + bool m_printActiveDesktopName; +};