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