#6383 Use CreateProcess when in foreground mode
This commit is contained in:
parent
568a008037
commit
026b1f0de1
|
@ -49,7 +49,8 @@ const char g_activeDesktop[] = {"activeDesktop:"};
|
||||||
MSWindowsWatchdog::MSWindowsWatchdog(
|
MSWindowsWatchdog::MSWindowsWatchdog(
|
||||||
bool autoDetectCommand,
|
bool autoDetectCommand,
|
||||||
IpcServer& ipcServer,
|
IpcServer& ipcServer,
|
||||||
IpcLogOutputter& ipcLogOutputter) :
|
IpcLogOutputter& ipcLogOutputter,
|
||||||
|
bool foreground) :
|
||||||
m_thread(NULL),
|
m_thread(NULL),
|
||||||
m_autoDetectCommand(autoDetectCommand),
|
m_autoDetectCommand(autoDetectCommand),
|
||||||
m_monitoring(true),
|
m_monitoring(true),
|
||||||
|
@ -63,7 +64,8 @@ MSWindowsWatchdog::MSWindowsWatchdog(
|
||||||
m_processRunning(false),
|
m_processRunning(false),
|
||||||
m_fileLogOutputter(NULL),
|
m_fileLogOutputter(NULL),
|
||||||
m_autoElevated(false),
|
m_autoElevated(false),
|
||||||
m_ready(false)
|
m_ready(false),
|
||||||
|
m_foreground(foreground)
|
||||||
{
|
{
|
||||||
m_mutex = ARCH->newMutex();
|
m_mutex = ARCH->newMutex();
|
||||||
m_condVar = ARCH->newCondVar();
|
m_condVar = ARCH->newCondVar();
|
||||||
|
@ -105,104 +107,118 @@ MSWindowsWatchdog::stop()
|
||||||
HANDLE
|
HANDLE
|
||||||
MSWindowsWatchdog::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security)
|
MSWindowsWatchdog::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security)
|
||||||
{
|
{
|
||||||
HANDLE sourceToken;
|
HANDLE sourceToken;
|
||||||
|
|
||||||
BOOL tokenRet = OpenProcessToken(
|
BOOL tokenRet = OpenProcessToken(
|
||||||
process,
|
process,
|
||||||
TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS,
|
TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS,
|
||||||
&sourceToken);
|
&sourceToken);
|
||||||
|
|
||||||
if (!tokenRet) {
|
if (!tokenRet) {
|
||||||
LOG((CLOG_ERR "could not open token, process handle: %d", process));
|
LOG((CLOG_ERR "could not open token, process handle: %d", process));
|
||||||
throw XArch(new XArchEvalWindows());
|
throw XArch(new XArchEvalWindows());
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken));
|
|
||||||
|
|
||||||
HANDLE newToken;
|
LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken));
|
||||||
BOOL duplicateRet = DuplicateTokenEx(
|
|
||||||
sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security,
|
|
||||||
SecurityImpersonation, TokenPrimary, &newToken);
|
|
||||||
|
|
||||||
if (!duplicateRet) {
|
HANDLE newToken;
|
||||||
LOG((CLOG_ERR "could not duplicate token %i", sourceToken));
|
BOOL duplicateRet = DuplicateTokenEx(
|
||||||
throw XArch(new XArchEvalWindows());
|
sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security,
|
||||||
}
|
SecurityImpersonation, TokenPrimary, &newToken);
|
||||||
|
|
||||||
LOG((CLOG_DEBUG "duplicated, new token: %i", newToken));
|
if (!duplicateRet) {
|
||||||
return newToken;
|
LOG((CLOG_ERR "could not duplicate token %i", sourceToken));
|
||||||
|
throw XArch(new XArchEvalWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG((CLOG_DEBUG "duplicated, new token: %i", newToken));
|
||||||
|
return newToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE
|
HANDLE
|
||||||
MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security)
|
MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security)
|
||||||
{
|
{
|
||||||
// always elevate if we are at the vista/7 login screen. we could also
|
// always elevate if we are at the vista/7 login screen. we could also
|
||||||
// elevate for the uac dialog (consent.exe) but this would be pointless,
|
// elevate for the uac dialog (consent.exe) but this would be pointless,
|
||||||
// since synergy would re-launch as non-elevated after the desk switch,
|
// since synergy would re-launch as non-elevated after the desk switch,
|
||||||
// and so would be unusable with the new elevated process taking focus.
|
// and so would be unusable with the new elevated process taking focus.
|
||||||
if (m_elevateProcess
|
if (m_elevateProcess
|
||||||
|| m_autoElevated
|
|| m_autoElevated
|
||||||
|| m_session.isProcessInSession("logonui.exe", NULL)) {
|
|| m_session.isProcessInSession("logonui.exe", NULL)) {
|
||||||
|
|
||||||
LOG((CLOG_DEBUG "getting elevated token, %s",
|
|
||||||
(m_elevateProcess ? "elevation required" : "at login screen")));
|
|
||||||
|
|
||||||
HANDLE process;
|
|
||||||
if (!m_session.isProcessInSession("winlogon.exe", &process)) {
|
|
||||||
throw XMSWindowsWatchdogError("cannot get user token without winlogon.exe");
|
|
||||||
}
|
|
||||||
|
|
||||||
return duplicateProcessToken(process, security);
|
LOG((CLOG_DEBUG "getting elevated token, %s",
|
||||||
}
|
(m_elevateProcess ? "elevation required" : "at login screen")));
|
||||||
else {
|
|
||||||
LOG((CLOG_DEBUG "getting non-elevated token"));
|
HANDLE process;
|
||||||
return m_session.getUserToken(security);
|
if (!m_session.isProcessInSession("winlogon.exe", &process)) {
|
||||||
}
|
throw XMSWindowsWatchdogError("cannot get user token without winlogon.exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
return duplicateProcessToken(process, security);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG((CLOG_DEBUG "getting non-elevated token"));
|
||||||
|
return m_session.getUserToken(security);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSWindowsWatchdog::mainLoop(void*)
|
MSWindowsWatchdog::mainLoop(void*)
|
||||||
{
|
{
|
||||||
shutdownExistingProcesses();
|
shutdownExistingProcesses();
|
||||||
|
|
||||||
SendSas sendSasFunc = NULL;
|
SendSas sendSasFunc = NULL;
|
||||||
HINSTANCE sasLib = LoadLibrary("sas.dll");
|
HINSTANCE sasLib = LoadLibrary("sas.dll");
|
||||||
if (sasLib) {
|
if (sasLib) {
|
||||||
LOG((CLOG_DEBUG "found sas.dll"));
|
LOG((CLOG_DEBUG "found sas.dll"));
|
||||||
sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS");
|
sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECURITY_ATTRIBUTES saAttr;
|
SECURITY_ATTRIBUTES saAttr;
|
||||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
saAttr.bInheritHandle = TRUE;
|
saAttr.bInheritHandle = TRUE;
|
||||||
saAttr.lpSecurityDescriptor = NULL;
|
saAttr.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) {
|
if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) {
|
||||||
throw XArch(new XArchEvalWindows());
|
throw XArch(new XArchEvalWindows());
|
||||||
}
|
}
|
||||||
|
|
||||||
ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));
|
ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));
|
||||||
|
|
||||||
while (m_monitoring) {
|
while (m_monitoring) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (m_processRunning && getCommand().empty()) {
|
if (m_processRunning && getCommand().empty()) {
|
||||||
LOG((CLOG_INFO "process started but command is empty, shutting down"));
|
LOG((CLOG_INFO "process started but command is empty, shutting down"));
|
||||||
shutdownExistingProcesses();
|
shutdownExistingProcesses();
|
||||||
m_processRunning = false;
|
m_processRunning = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_processFailures != 0) {
|
if (m_processFailures != 0) {
|
||||||
// increasing backoff period, maximum of 10 seconds.
|
// increasing backoff period, maximum of 10 seconds.
|
||||||
int timeout = (m_processFailures * 2) < 10 ? (m_processFailures * 2) : 10;
|
int timeout = (m_processFailures * 2) < 10 ? (m_processFailures * 2) : 10;
|
||||||
LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, m_processFailures));
|
LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, m_processFailures));
|
||||||
ARCH->sleep(timeout);
|
ARCH->sleep(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getCommand().empty() && ((m_processFailures != 0) || m_session.hasChanged() || m_commandChanged)) {
|
if (!getCommand().empty()) {
|
||||||
startProcess();
|
bool startNeeded = false;
|
||||||
}
|
|
||||||
|
if (m_processFailures != 0) {
|
||||||
|
startNeeded = true;
|
||||||
|
}
|
||||||
|
else if (!m_foreground && m_session.hasChanged()) {
|
||||||
|
startNeeded = true;
|
||||||
|
}
|
||||||
|
else if (m_commandChanged) {
|
||||||
|
startNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startNeeded) {
|
||||||
|
startProcess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_processRunning && !isProcessActive()) {
|
if (m_processRunning && !isProcessActive()) {
|
||||||
|
|
||||||
|
@ -284,28 +300,35 @@ MSWindowsWatchdog::startProcess()
|
||||||
m_processRunning = false;
|
m_processRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_session.updateActiveSession();
|
BOOL createRet;
|
||||||
|
if (m_foreground) {
|
||||||
|
LOG((CLOG_DEBUG "starting command in foreground"));
|
||||||
|
createRet = startProcessInForeground(m_command);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG((CLOG_DEBUG "starting command as session user"));
|
||||||
|
m_session.updateActiveSession();
|
||||||
|
|
||||||
SECURITY_ATTRIBUTES sa;
|
SECURITY_ATTRIBUTES sa;
|
||||||
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
|
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
|
||||||
|
|
||||||
getActiveDesktop(&sa);
|
getActiveDesktop(&sa);
|
||||||
|
|
||||||
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
|
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
|
||||||
HANDLE userToken = getUserToken(&sa);
|
HANDLE userToken = getUserToken(&sa);
|
||||||
m_elevateProcess = m_autoElevated ? m_autoElevated : m_elevateProcess;
|
m_elevateProcess = m_autoElevated ? m_autoElevated : m_elevateProcess;
|
||||||
m_autoElevated = false;
|
m_autoElevated = false;
|
||||||
|
|
||||||
// patch by Jack Zhou and Henry Tung
|
// patch by Jack Zhou and Henry Tung
|
||||||
// set UIAccess to fix Windows 8 GUI interaction
|
// set UIAccess to fix Windows 8 GUI interaction
|
||||||
// http://symless.com/spit/issues/details/3338/#c70
|
DWORD uiAccess = 1;
|
||||||
DWORD uiAccess = 1;
|
SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD));
|
||||||
SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD));
|
|
||||||
|
|
||||||
BOOL createRet = doStartProcess(m_command, userToken, &sa);
|
createRet = startProcessAsUser(m_command, userToken, &sa);
|
||||||
|
}
|
||||||
|
|
||||||
if (!createRet) {
|
if (!createRet) {
|
||||||
LOG((CLOG_ERR "could not launch"));
|
LOG((CLOG_ERR "could not launch command"));
|
||||||
DWORD exitCode = 0;
|
DWORD exitCode = 0;
|
||||||
GetExitCodeProcess(m_processInfo.hProcess, &exitCode);
|
GetExitCodeProcess(m_processInfo.hProcess, &exitCode);
|
||||||
LOG((CLOG_ERR "exit code: %d", exitCode));
|
LOG((CLOG_ERR "exit code: %d", exitCode));
|
||||||
|
@ -329,7 +352,21 @@ MSWindowsWatchdog::startProcess()
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
MSWindowsWatchdog::doStartProcess(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa)
|
MSWindowsWatchdog::startProcessInForeground(String& command)
|
||||||
|
{
|
||||||
|
// clear, as we're reusing process info struct
|
||||||
|
ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));
|
||||||
|
|
||||||
|
STARTUPINFO startupInfo;
|
||||||
|
ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
|
||||||
|
|
||||||
|
return CreateProcess(
|
||||||
|
NULL, LPSTR(command.c_str()), NULL, NULL,
|
||||||
|
FALSE, 0, NULL, NULL, &startupInfo, &m_processInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
MSWindowsWatchdog::startProcessAsUser(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa)
|
||||||
{
|
{
|
||||||
// clear, as we're reusing process info struct
|
// clear, as we're reusing process info struct
|
||||||
ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));
|
ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));
|
||||||
|
@ -542,7 +579,7 @@ MSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security)
|
||||||
HANDLE userToken = getUserToken(security);
|
HANDLE userToken = getUserToken(security);
|
||||||
m_elevateProcess = elevateProcess;
|
m_elevateProcess = elevateProcess;
|
||||||
|
|
||||||
BOOL createRet = doStartProcess(syntoolCommand, userToken, security);
|
BOOL createRet = startProcessAsUser(syntoolCommand, userToken, security);
|
||||||
|
|
||||||
if (!createRet) {
|
if (!createRet) {
|
||||||
DWORD rc = GetLastError();
|
DWORD rc = GetLastError();
|
||||||
|
|
|
@ -37,7 +37,8 @@ public:
|
||||||
MSWindowsWatchdog(
|
MSWindowsWatchdog(
|
||||||
bool autoDetectCommand,
|
bool autoDetectCommand,
|
||||||
IpcServer& ipcServer,
|
IpcServer& ipcServer,
|
||||||
IpcLogOutputter& ipcLogOutputter);
|
IpcLogOutputter& ipcLogOutputter,
|
||||||
|
bool foreground);
|
||||||
virtual ~MSWindowsWatchdog();
|
virtual ~MSWindowsWatchdog();
|
||||||
|
|
||||||
void startAsync();
|
void startAsync();
|
||||||
|
@ -55,7 +56,8 @@ private:
|
||||||
HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security);
|
HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security);
|
||||||
HANDLE getUserToken(LPSECURITY_ATTRIBUTES security);
|
HANDLE getUserToken(LPSECURITY_ATTRIBUTES security);
|
||||||
void startProcess();
|
void startProcess();
|
||||||
BOOL doStartProcess(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa);
|
BOOL startProcessAsUser(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa);
|
||||||
|
BOOL startProcessInForeground(String& command);
|
||||||
void sendSas();
|
void sendSas();
|
||||||
void getActiveDesktop(LPSECURITY_ATTRIBUTES security);
|
void getActiveDesktop(LPSECURITY_ATTRIBUTES security);
|
||||||
void testOutput(String buffer);
|
void testOutput(String buffer);
|
||||||
|
@ -81,6 +83,7 @@ private:
|
||||||
ArchMutex m_mutex;
|
ArchMutex m_mutex;
|
||||||
ArchCond m_condVar;
|
ArchCond m_condVar;
|
||||||
bool m_ready;
|
bool m_ready;
|
||||||
|
bool m_foreground;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Relauncher error
|
//! Relauncher error
|
||||||
|
|
|
@ -155,7 +155,7 @@ DaemonApp::run(int argc, char** argv)
|
||||||
if (foreground) {
|
if (foreground) {
|
||||||
// run process in foreground instead of daemonizing.
|
// run process in foreground instead of daemonizing.
|
||||||
// useful for debugging.
|
// useful for debugging.
|
||||||
mainLoop(false);
|
mainLoop(false, foreground);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
@ -192,7 +192,7 @@ DaemonApp::run(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DaemonApp::mainLoop(bool logToFile)
|
DaemonApp::mainLoop(bool logToFile, bool foreground)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -215,7 +215,7 @@ DaemonApp::mainLoop(bool logToFile)
|
||||||
CLOG->insert(m_ipcLogOutputter);
|
CLOG->insert(m_ipcLogOutputter);
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
m_watchdog = new MSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter);
|
m_watchdog = new MSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter, foreground);
|
||||||
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
|
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
DaemonApp();
|
DaemonApp();
|
||||||
virtual ~DaemonApp();
|
virtual ~DaemonApp();
|
||||||
int run(int argc, char** argv);
|
int run(int argc, char** argv);
|
||||||
void mainLoop(bool logToFile);
|
void mainLoop(bool logToFile, bool foreground = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void daemonize();
|
void daemonize();
|
||||||
|
|
Loading…
Reference in New Issue