From 268f3a99bb8176d8949c57461f64bd97ff73659a Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Sat, 28 Jul 2012 02:59:20 +0000 Subject: [PATCH] added process elevation support to the relauncher, very experimental, has some bugs. --- src/gui/res/MainWindowBase.ui | 21 ++- src/gui/src/Ipc.cpp | 4 +- src/gui/src/Ipc.h | 2 + src/gui/src/IpcClient.cpp | 42 +++-- src/gui/src/IpcClient.h | 3 +- src/gui/src/MainWindow.cpp | 46 ++++- src/gui/src/MainWindow.h | 4 +- src/lib/ipc/CIpcClientProxy.cpp | 5 +- src/lib/ipc/CIpcMessage.cpp | 5 +- src/lib/ipc/CIpcMessage.h | 6 +- src/lib/ipc/Ipc.cpp | 2 +- src/lib/ipc/Ipc.h | 12 ++ src/lib/platform/CMSWindowsRelauncher.cpp | 217 ++++++++++++---------- src/lib/platform/CMSWindowsRelauncher.h | 9 +- src/lib/synergy/CDaemonApp.cpp | 16 +- src/test/integtests/CIpcTests.cpp | 2 +- 16 files changed, 246 insertions(+), 150 deletions(-) diff --git a/src/gui/res/MainWindowBase.ui b/src/gui/res/MainWindowBase.ui index 7cdd36e0..69e8af6d 100644 --- a/src/gui/res/MainWindowBase.ui +++ b/src/gui/res/MainWindowBase.ui @@ -27,14 +27,14 @@ - + &Start - + @@ -127,7 +127,7 @@ - + @@ -168,7 +168,7 @@ - + Log @@ -223,7 +223,7 @@ - :/res/icons/16x16/warning.png + :/res/icons/16x16/warning.png @@ -237,6 +237,13 @@ + + + + &Elevate + + + @@ -323,9 +330,7 @@ - - - + m_pButtonToggleStart diff --git a/src/gui/src/Ipc.cpp b/src/gui/src/Ipc.cpp index c7e45030..41a7be0b 100644 --- a/src/gui/src/Ipc.cpp +++ b/src/gui/src/Ipc.cpp @@ -15,9 +15,11 @@ * along with this program. If not, see . */ +// this class is a duplicate of /src/lib/ipc/Ipc.cpp + #include "Ipc.h" const char* kIpcMsgHello = "IHEL%1i"; const char* kIpcMsgLogLine = "ILOG%s"; -const char* kIpcMsgCommand = "ICMD%s"; +const char* kIpcMsgCommand = "ICMD%s%1i"; const char* kIpcMsgShutdown = "ISDN"; diff --git a/src/gui/src/Ipc.h b/src/gui/src/Ipc.h index 473699ef..a2324876 100644 --- a/src/gui/src/Ipc.h +++ b/src/gui/src/Ipc.h @@ -15,6 +15,8 @@ * along with this program. If not, see . */ +// this class is a duplicate of /src/lib/ipc/Ipc.h + #pragma once #define IPC_HOST "127.0.0.1" diff --git a/src/gui/src/IpcClient.cpp b/src/gui/src/IpcClient.cpp index dc305d50..5e230745 100644 --- a/src/gui/src/IpcClient.cpp +++ b/src/gui/src/IpcClient.cpp @@ -43,7 +43,7 @@ void IpcClient::connected() { char typeBuf[1]; typeBuf[0] = kIpcClientGui; - write(kIpcHello, 1, typeBuf); + sendHello(); infoMessage("connection established"); } @@ -89,30 +89,34 @@ void IpcClient::retryConnect() } } -void IpcClient::write(int code, int length, const char* data) +void IpcClient::sendHello() +{ + QDataStream stream(m_Socket); + stream.writeRawData(kIpcMsgHello, 4); + + char typeBuf[1]; + typeBuf[0] = kIpcClientGui; + stream.writeRawData(typeBuf, 1); +} + +void IpcClient::sendCommand(const QString& command, bool elevate) { QDataStream stream(m_Socket); - switch (code) { - case kIpcHello: - stream.writeRawData(kIpcMsgHello, 4); - stream.writeRawData(data, 1); - break; + stream.writeRawData(kIpcMsgCommand, 4); - case kIpcCommand: { - char lenBuf[4]; - intToBytes(length, lenBuf, 4); + std::string stdStringCommand = command.toStdString(); + const char* charCommand = stdStringCommand.c_str(); + int length = strlen(charCommand); - stream.writeRawData(kIpcMsgCommand, 4); - stream.writeRawData(lenBuf, 4); - stream.writeRawData(data, length); - break; - } + char lenBuf[4]; + intToBytes(length, lenBuf, 4); + stream.writeRawData(lenBuf, 4); + stream.writeRawData(charCommand, length); - default: - std::cerr << "message type not supported: " << code << std::endl; - break; - } + char elevateBuf[1]; + elevateBuf[0] = elevate ? 1 : 0; + stream.writeRawData(elevateBuf, 1); } void IpcClient::handleReadLogLine(const QString& text) diff --git a/src/gui/src/IpcClient.h b/src/gui/src/IpcClient.h index 7e232800..517e64b1 100644 --- a/src/gui/src/IpcClient.h +++ b/src/gui/src/IpcClient.h @@ -31,7 +31,8 @@ public: IpcClient(); virtual ~IpcClient(); - void write(int code, int length, const char* data); + void sendHello(); + void sendCommand(const QString& command, bool elevate); void connectToHost(); void disconnectFromHost(); diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index 0f7d668c..569e1a2e 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -64,7 +64,9 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) : m_pTrayIcon(NULL), m_pTrayIconMenu(NULL), m_alreadyHidden(false), - m_SetupWizard(NULL) + m_SetupWizard(NULL), + m_ElevateProcess(false), + m_SuppressElevateWarning(false) { setupUi(this); @@ -85,6 +87,9 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) : connect(&m_IpcClient, SIGNAL(errorMessage(const QString&)), this, SLOT(appendLogError(const QString&))); connect(&m_IpcClient, SIGNAL(infoMessage(const QString&)), this, SLOT(appendLogNote(const QString&))); m_IpcClient.connectToHost(); +#else + // elevate checkbox is only useful on ms windows. + m_pElevateCheckBox->hide(); #endif } @@ -133,13 +138,15 @@ void MainWindow::onModeChanged(bool firstRun, bool forceServiceApply) else { // cause the service to stop creating processes. - sendDaemonCommand("", false); + m_IpcClient.sendCommand("", false); } if ((appConfig().processMode() == Desktop) && !firstRun && appConfig().autoConnect()) { startSynergy(); } + + m_pElevateCheckBox->setEnabled(appConfig().processMode() == Service); } void MainWindow::refreshStartButton() @@ -221,6 +228,10 @@ void MainWindow::loadSettings() m_pLineEditConfigFile->setText(settings().value("configFile", QDir::homePath() + "/" + synergyConfigName).toString()); m_pGroupClient->setChecked(settings().value("groupClientChecked", true).toBool()); m_pLineEditHostname->setText(settings().value("serverHostname").toString()); + + m_SuppressElevateWarning = true; + m_pElevateCheckBox->setChecked(settings().value("elevateChecked", false).toBool()); + m_SuppressElevateWarning = false; } void MainWindow::initConnections() @@ -452,7 +463,7 @@ void MainWindow::startSynergy() if (serviceMode) { QString command(app + " " + args.join(" ")); - sendDaemonCommand(command, true); + m_IpcClient.sendCommand(command, m_ElevateProcess); } } @@ -702,14 +713,29 @@ void MainWindow::on_m_pButtonConfigureServer_clicked() dlg.exec(); } -void MainWindow::sendDaemonCommand(const QString& command, bool showErrors) -{ - std::string s = command.toStdString(); - const char* data = s.c_str(); - m_IpcClient.write(kIpcCommand, strlen(data), data); -} - void MainWindow::on_m_pActionWizard_triggered() { m_SetupWizard->show(); } + +void MainWindow::on_m_pElevateCheckBox_toggled(bool checked) +{ + if (checked && !m_SuppressElevateWarning) { + int r = QMessageBox::warning( + this, tr("Elevate Synergy"), + tr("Are you sure you want to elevate Synergy?\n\n" + "This allows Synergy to interact with elevated processes " + "and the UAC dialog, but can cause problems with non-elevated " + "processes. Elevate Synergy only if you really need to."), + QMessageBox::Yes | QMessageBox::No); + + if (r != QMessageBox::Yes) { + m_pElevateCheckBox->setChecked(false); + return; + } + } + + m_ElevateProcess = checked; + settings().setValue("elevateChecked", checked); + settings().sync(); +} diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index d1f4d321..5992feee 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -104,6 +104,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase void on_m_pActionAbout_triggered(); void on_m_pActionSettings_triggered(); void on_m_pActionWizard_triggered(); + void on_m_pElevateCheckBox_toggled(bool checked); void synergyFinished(int exitCode, QProcess::ExitStatus); void iconActivated(QSystemTrayIcon::ActivationReason reason); void startSynergy(); @@ -132,7 +133,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase bool clientArgs(QStringList& args, QString& app); bool serverArgs(QStringList& args, QString& app); void setStatus(const QString& status); - void sendDaemonCommand(const QString& command, bool showErrors); void sendIpcMessage(qIpcMessageType type, const char* buffer, bool showErrors); void onModeChanged(bool firstRun, bool forceServiceApply); @@ -149,6 +149,8 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase VersionChecker m_versionChecker; SetupWizard* m_SetupWizard; IpcClient m_IpcClient; + bool m_ElevateProcess; + bool m_SuppressElevateWarning; }; #endif diff --git a/src/lib/ipc/CIpcClientProxy.cpp b/src/lib/ipc/CIpcClientProxy.cpp index 96805eb6..2b199169 100644 --- a/src/lib/ipc/CIpcClientProxy.cpp +++ b/src/lib/ipc/CIpcClientProxy.cpp @@ -173,10 +173,11 @@ CIpcCommandMessage* CIpcClientProxy::parseCommand() { CString command; - CProtocolUtil::readf(&m_stream, kIpcMsgCommand + 4, &command); + UInt8 elevate; + CProtocolUtil::readf(&m_stream, kIpcMsgCommand + 4, &command, &elevate); // must be deleted by event handler. - return new CIpcCommandMessage(command); + return new CIpcCommandMessage(command, elevate != 0); } void diff --git a/src/lib/ipc/CIpcMessage.cpp b/src/lib/ipc/CIpcMessage.cpp index 03f58f74..ef34659b 100644 --- a/src/lib/ipc/CIpcMessage.cpp +++ b/src/lib/ipc/CIpcMessage.cpp @@ -56,9 +56,10 @@ CIpcLogLineMessage::~CIpcLogLineMessage() { } -CIpcCommandMessage::CIpcCommandMessage(const CString& command) : +CIpcCommandMessage::CIpcCommandMessage(const CString& command, bool elevate) : CIpcMessage(kIpcCommand), -m_command(command) +m_command(command), +m_elevate(elevate) { } diff --git a/src/lib/ipc/CIpcMessage.h b/src/lib/ipc/CIpcMessage.h index 23acb4f4..66f8c2cc 100644 --- a/src/lib/ipc/CIpcMessage.h +++ b/src/lib/ipc/CIpcMessage.h @@ -69,12 +69,16 @@ private: class CIpcCommandMessage : public CIpcMessage { public: - CIpcCommandMessage(const CString& command); + CIpcCommandMessage(const CString& command, bool elevate); virtual ~CIpcCommandMessage(); //! Gets the command. CString command() const { return m_command; } + //! Gets whether or not the process should be elevated on MS Windows. + bool elevate() const { return m_elevate; } + private: CString m_command; + bool m_elevate; }; diff --git a/src/lib/ipc/Ipc.cpp b/src/lib/ipc/Ipc.cpp index 7666e61c..a7ea138d 100644 --- a/src/lib/ipc/Ipc.cpp +++ b/src/lib/ipc/Ipc.cpp @@ -19,5 +19,5 @@ const char* kIpcMsgHello = "IHEL%1i"; const char* kIpcMsgLogLine = "ILOG%s"; -const char* kIpcMsgCommand = "ICMD%s"; +const char* kIpcMsgCommand = "ICMD%s%1i"; const char* kIpcMsgShutdown = "ISDN"; diff --git a/src/lib/ipc/Ipc.h b/src/lib/ipc/Ipc.h index 22212dce..c1233202 100644 --- a/src/lib/ipc/Ipc.h +++ b/src/lib/ipc/Ipc.h @@ -33,7 +33,19 @@ enum EIpcClientType { kIpcClientNode, }; +// handshake: node/gui -> daemon +// $1 = type, the client identifies it's self as gui or node (synergyc/s). extern const char* kIpcMsgHello; + +// log line: daemon -> gui +// $1 = aggregate log lines collected from synergys/c or the daemon itself. extern const char* kIpcMsgLogLine; + +// command: gui -> daemon +// $1 = command; the command for the daemon to launch, typically the full +// path to synergys/c. $2 = true when process must be elevated on ms windows. extern const char* kIpcMsgCommand; + +// shutdown: daemon -> node +// the daemon tells synergys/c to shut down gracefully. extern const char* kIpcMsgShutdown; diff --git a/src/lib/platform/CMSWindowsRelauncher.cpp b/src/lib/platform/CMSWindowsRelauncher.cpp index 29be85bc..f69fb62d 100644 --- a/src/lib/platform/CMSWindowsRelauncher.cpp +++ b/src/lib/platform/CMSWindowsRelauncher.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include enum { kOutputBufferSize = 4096 @@ -51,7 +53,8 @@ CMSWindowsRelauncher::CMSWindowsRelauncher( m_stdOutWrite(NULL), m_stdOutRead(NULL), m_ipcServer(ipcServer), - m_ipcLogOutputter(ipcLogOutputter) + m_ipcLogOutputter(ipcLogOutputter), + m_elevateProcess(false) { } @@ -90,7 +93,7 @@ CMSWindowsRelauncher::getSessionId() } BOOL -CMSWindowsRelauncher::winlogonInSession(DWORD sessionId, PHANDLE process) +CMSWindowsRelauncher::isProcessInSession(const char* name, DWORD sessionId, PHANDLE process) { // first we need to take a snapshot of the running processes HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); @@ -138,9 +141,8 @@ CMSWindowsRelauncher::winlogonInSession(DWORD sessionId, PHANDLE process) // store the names so we can record them for debug nameList.push_back(entry.szExeFile); - if (_stricmp(entry.szExeFile, "winlogon.exe") == 0) { + if (_stricmp(entry.szExeFile, name) == 0) { pid = entry.th32ProcessID; - break; } } } @@ -167,67 +169,97 @@ CMSWindowsRelauncher::winlogonInSession(DWORD sessionId, PHANDLE process) nameListJoin.append(", "); } - LOG((CLOG_DEBUG "checked processes while looking for winlogon.exe: %s", - nameListJoin.c_str())); + LOG((CLOG_DEBUG "processes in session %d: %s", + sessionId, nameListJoin.c_str())); CloseHandle(snapshot); if (pid) { // now get the process so we can get the process, with which // we'll use to get the process token. + LOG((CLOG_DEBUG "found %s in session %i", name, sessionId)); *process = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid); return true; } else { - LOG((CLOG_DEBUG "could not find winlogon.exe in session %i", sessionId)); + LOG((CLOG_DEBUG "could not find %s in session %i", name, sessionId)); return false; } } -// gets the current user (so we can launch under their session) -HANDLE -CMSWindowsRelauncher::getCurrentUserToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security) +HANDLE +CMSWindowsRelauncher::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security) { - HANDLE currentToken; - HANDLE winlogonProcess; + HANDLE sourceToken; - if (winlogonInSession(sessionId, &winlogonProcess)) { + BOOL tokenRet = OpenProcessToken( + process, + TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, + &sourceToken); - LOG((CLOG_DEBUG "session %i has winlogon.exe", sessionId)); - - // get the token, so we can re-launch with this token - // -- do we really need all these access bits? - BOOL tokenRet = OpenProcessToken( - winlogonProcess, - TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | - TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | - TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, - ¤tToken); - - if (!tokenRet) { - LOG((CLOG_ERR "could not open token (error: %i)", GetLastError())); - return 0; - } + if (!tokenRet) { + LOG((CLOG_ERR "could not open token, process handle: %d (error: %i)", process, GetLastError())); + return NULL; } - else { + + LOG((CLOG_ERR "got token %i, duplicating", sourceToken)); - LOG((CLOG_ERR "session %i does not have winlogon.exe " - "which is needed for re-launch", sessionId)); - return 0; - } - - HANDLE primaryToken; + HANDLE newToken; BOOL duplicateRet = DuplicateTokenEx( - currentToken, MAXIMUM_ALLOWED, security, - SecurityImpersonation, TokenPrimary, &primaryToken); + sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, + SecurityImpersonation, TokenPrimary, &newToken); if (!duplicateRet) { LOG((CLOG_ERR "could not duplicate token %i (error: %i)", - currentToken, GetLastError())); + sourceToken, GetLastError())); + return NULL; + } + + LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); + return newToken; +} + +// use either an elevated token (winlogon) or the user's session +// token (non-elevated). processes launched with a non-elevated token +// cannot interact with elevated processes. +HANDLE +CMSWindowsRelauncher::getUserToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security) +{ + if (m_elevateProcess) { + HANDLE process; + if (isProcessInSession("winlogon.exe", sessionId, &process)) { + return duplicateProcessToken(process, security); + } + else { + LOG((CLOG_ERR "could not find token in session %d", sessionId)); + return NULL; + } + } + else { + return getSessionToken(sessionId, security); + } +} + +HANDLE +CMSWindowsRelauncher::getSessionToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security) +{ + HANDLE sourceToken; + if (!WTSQueryUserToken(sessionId, &sourceToken)) { + LOG((CLOG_ERR "could not get token from session %d (error: %i)", sessionId, GetLastError())); return 0; } + + HANDLE newToken; + if (!DuplicateTokenEx( + sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, + SecurityImpersonation, TokenPrimary, &newToken)) { - return primaryToken; + LOG((CLOG_ERR "could not duplicate token (error: %i)", GetLastError())); + return 0; + } + + LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); + return newToken; } void @@ -319,67 +351,64 @@ CMSWindowsRelauncher::mainLoop(void*) SECURITY_ATTRIBUTES sa; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); - // get the token for the user in active session, which is the - // one receiving input from mouse and keyboard. - HANDLE userToken = getCurrentUserToken(sessionId, &sa); + HANDLE userToken = getUserToken(sessionId, &sa); + if (userToken == NULL) { + // HACK: trigger retry mechanism. + launched = true; + continue; + } - if (userToken != 0) { - LOG((CLOG_DEBUG "got user token to launch new process")); + std::string cmd = command(); + if (cmd == "") { + // this appears on first launch when the user hasn't configured + // anything yet, so don't show it as a warning, only show it as + // debug to devs to let them know why nothing happened. + LOG((CLOG_DEBUG "nothing to launch, no command specified.")); + continue; + } - std::string cmd = command(); - if (cmd == "") { - // this appears on first launch when the user hasn't configured - // anything yet, so don't show it as a warning, only show it as - // debug to devs to let them know why nothing happened. - LOG((CLOG_DEBUG "nothing to launch, no command specified.")); - continue; - } + // in case reusing process info struct + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); - // in case reusing process info struct - ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + STARTUPINFO si; + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.lpDesktop = "winsta0\\Default"; // TODO: maybe this should be \winlogon if we have logonui.exe? + si.hStdError = m_stdOutWrite; + si.hStdOutput = m_stdOutWrite; + si.dwFlags |= STARTF_USESTDHANDLES; - STARTUPINFO si; - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.lpDesktop = "winsta0\\default"; - si.hStdError = m_stdOutWrite; - si.hStdOutput = m_stdOutWrite; - si.dwFlags |= STARTF_USESTDHANDLES; + LPVOID environment; + BOOL blockRet = CreateEnvironmentBlock(&environment, userToken, FALSE); + if (!blockRet) { + LOG((CLOG_ERR "could not create environment block (error: %i)", + GetLastError())); + continue; + } - LPVOID environment; - BOOL blockRet = CreateEnvironmentBlock(&environment, userToken, FALSE); - if (!blockRet) { - LOG((CLOG_ERR "could not create environment block (error: %i)", - GetLastError())); - continue; - } - else { + DWORD creationFlags = + NORMAL_PRIORITY_CLASS | + CREATE_NO_WINDOW | + CREATE_UNICODE_ENVIRONMENT; - DWORD creationFlags = - NORMAL_PRIORITY_CLASS | - CREATE_NO_WINDOW | - CREATE_UNICODE_ENVIRONMENT; + // re-launch in current active user session + LOG((CLOG_INFO "starting new process")); + BOOL createRet = CreateProcessAsUser( + userToken, NULL, LPSTR(cmd.c_str()), + &sa, NULL, TRUE, creationFlags, + environment, NULL, &si, &pi); - // re-launch in current active user session - LOG((CLOG_INFO "starting new process")); - BOOL createRet = CreateProcessAsUser( - userToken, NULL, LPSTR(cmd.c_str()), - &sa, NULL, TRUE, creationFlags, - environment, NULL, &si, &pi); + DestroyEnvironmentBlock(environment); + CloseHandle(userToken); - DestroyEnvironmentBlock(environment); - CloseHandle(userToken); - - if (!createRet) { - LOG((CLOG_ERR "could not launch (error: %i)", GetLastError())); - continue; - } - else { - LOG((CLOG_DEBUG "launched in session %i (cmd: %s)", - sessionId, cmd.c_str())); - launched = true; - } - } + if (!createRet) { + LOG((CLOG_ERR "could not launch (error: %i)", GetLastError())); + continue; + } + else { + LOG((CLOG_DEBUG "launched in session %i (cmd: %s)", + sessionId, cmd.c_str())); + launched = true; } } @@ -406,11 +435,11 @@ CMSWindowsRelauncher::mainLoop(void*) } void -CMSWindowsRelauncher::command(const std::string& command) +CMSWindowsRelauncher::command(const std::string& command, bool elevate) { LOG((CLOG_INFO "service command updated")); - LOG((CLOG_DEBUG "new command: %s", command.c_str())); m_command = command; + m_elevateProcess = elevate; m_commandChanged = true; } diff --git a/src/lib/platform/CMSWindowsRelauncher.h b/src/lib/platform/CMSWindowsRelauncher.h index 1116c358..259ef945 100644 --- a/src/lib/platform/CMSWindowsRelauncher.h +++ b/src/lib/platform/CMSWindowsRelauncher.h @@ -35,17 +35,19 @@ public: virtual ~CMSWindowsRelauncher(); void startAsync(); std::string command() const; - void command(const std::string& command); + void command(const std::string& command, bool elevate); void stop(); private: void mainLoop(void*); - BOOL winlogonInSession(DWORD sessionId, PHANDLE process); + BOOL isProcessInSession(const char* name, DWORD sessionId, PHANDLE process); DWORD getSessionId(); - HANDLE getCurrentUserToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security); void outputLoop(void*); void shutdownProcess(HANDLE handle, DWORD pid, int timeout); void shutdownExistingProcesses(); + HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security); + HANDLE getSessionToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security); + HANDLE getUserToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security); private: CThread* m_thread; @@ -58,4 +60,5 @@ private: CThread* m_outputThread; CIpcServer& m_ipcServer; CIpcLogOutputter& m_ipcLogOutputter; + bool m_elevateProcess; }; diff --git a/src/lib/synergy/CDaemonApp.cpp b/src/lib/synergy/CDaemonApp.cpp index fb1dab39..b0a1757e 100644 --- a/src/lib/synergy/CDaemonApp.cpp +++ b/src/lib/synergy/CDaemonApp.cpp @@ -222,11 +222,12 @@ CDaemonApp::mainLoop(bool logToFile) CMSWindowsScreen::init(CArchMiscWindows::instanceWin32()); CGameDeviceInfo gameDevice; CScreen dummyScreen(new CMSWindowsScreen(false, true, gameDevice)); - - string command = ARCH->setting("Command"); + + CString command = ARCH->setting("Command"); + bool elevate = ARCH->setting("Elevate") == "1"; if (command != "") { LOG((CLOG_INFO "using last known command: %s", command.c_str())); - m_relauncher->command(command); + m_relauncher->command(command, elevate); } m_relauncher->startAsync(); @@ -295,7 +296,7 @@ CDaemonApp::handleIpcMessage(const CEvent& e, void*) case kIpcCommand: { CIpcCommandMessage* cm = static_cast(m); CString command = cm->command(); - LOG((CLOG_DEBUG "got new command: %s", command.c_str())); + LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); CString debugArg("--debug"); int debugArgPos = command.find(debugArg); @@ -319,16 +320,19 @@ CDaemonApp::handleIpcMessage(const CEvent& e, void*) // store command in system settings. this is used when the daemon // next starts. ARCH->setting("Command", command); + + // TODO: it would be nice to store bools/ints... + ARCH->setting("Elevate", CString(cm->elevate() ? "1" : "0")); } catch (XArch& e) { - LOG((CLOG_ERR "failed to save Command setting, %s", e.what().c_str())); + LOG((CLOG_ERR "failed to save settings, %s", e.what().c_str())); } #if SYSAPI_WIN32 // tell the relauncher about the new command. this causes the // relauncher to stop the existing command and start the new // command. - m_relauncher->command(command); + m_relauncher->command(command, cm->elevate()); #endif break; } diff --git a/src/test/integtests/CIpcTests.cpp b/src/test/integtests/CIpcTests.cpp index c3d5eaef..6b6c7772 100644 --- a/src/test/integtests/CIpcTests.cpp +++ b/src/test/integtests/CIpcTests.cpp @@ -181,7 +181,7 @@ CIpcTests::connectToServer_handleMessageReceived(const CEvent& e, void*) void CIpcTests::sendMessageToServer_handleClientConnected(const CEvent& e, void*) { - CIpcCommandMessage m("test"); + CIpcCommandMessage m("test", true); m_sendMessageToServer_client->send(m); }