Auto elevate for Windows UAC and screen lock #4130
This commit is contained in:
parent
4d3fd14ada
commit
d2191b6b93
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "base/String.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <Tlhelp32.h>
|
||||
|
@ -40,6 +42,8 @@ public:
|
|||
|
||||
void updateActiveSession();
|
||||
|
||||
CString getActiveDesktopName();
|
||||
|
||||
private:
|
||||
BOOL nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "platform/MSWindowsSession.h"
|
||||
#include "synergy/XSynergy.h"
|
||||
#include "arch/IArchMultithread.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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 <iostream>
|
||||
#include <sstream>
|
||||
|
||||
//#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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "synergy/ToolArgs.h"
|
||||
|
||||
CToolArgs::CToolArgs() :
|
||||
m_printActiveDesktopName(false)
|
||||
{
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/String.h"
|
||||
|
||||
class CToolArgs {
|
||||
public:
|
||||
CToolArgs();
|
||||
|
||||
public:
|
||||
bool m_printActiveDesktopName;
|
||||
};
|
Loading…
Reference in New Issue