Beispiel #1
0
void
MSWindowsWatchdog::startProcess()
{
	if (m_command.empty()) {
		throw XMSWindowsWatchdogError("cannot start process, command is empty");
	}

	m_commandChanged = false;

	if (m_processRunning) {
		LOG((CLOG_DEBUG "closing existing process to make way for new one"));
		shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20);
		m_processRunning = false;
	}

	m_session.updateActiveSession();

	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
	// http://synergy-project.org/spit/issues/details/3338/#c70
	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()));
	}
}
Beispiel #2
0
void
CMSWindowsRelauncher::shutdownExistingProcesses()
{
	// first we need to take a snapshot of the running processes
	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (snapshot == INVALID_HANDLE_VALUE) {
		LOG((CLOG_ERR "could not get process snapshot (error: %i)", 
			GetLastError()));
		return;
	}

	PROCESSENTRY32 entry;
	entry.dwSize = sizeof(PROCESSENTRY32);

	// get the first process, and if we can't do that then it's 
	// unlikely we can go any further
	BOOL gotEntry = Process32First(snapshot, &entry);
	if (!gotEntry) {
		LOG((CLOG_ERR "could not get first process entry (error: %i)", 
			GetLastError()));
		return;
	}

	// now just iterate until we can find winlogon.exe pid
	DWORD pid = 0;
	while(gotEntry) {

		// make sure we're not checking the system process
		if (entry.th32ProcessID != 0) {

			if (_stricmp(entry.szExeFile, "synergyc.exe") == 0 ||
				_stricmp(entry.szExeFile, "synergys.exe") == 0) {
				
				HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
				shutdownProcess(handle, entry.th32ProcessID, 10);
			}
		}

		// now move on to the next entry (if we're not at the end)
		gotEntry = Process32Next(snapshot, &entry);
		if (!gotEntry) {

			DWORD err = GetLastError();
			if (err != ERROR_NO_MORE_FILES) {

				// only worry about error if it's not the end of the snapshot
				LOG((CLOG_ERR "could not get subsiquent process entry (error: %i)", 
					GetLastError()));
				return;
			}
		}
	}

	CloseHandle(snapshot);
}
Beispiel #3
0
void
MSWindowsWatchdog::mainLoop(void*)
{
	shutdownExistingProcesses();

	SendSas sendSasFunc = NULL;
	HINSTANCE sasLib = LoadLibrary("sas.dll");
	if (sasLib) {
		LOG((CLOG_DEBUG "found sas.dll"));
		sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS");
	}

	SECURITY_ATTRIBUTES saAttr; 
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
	saAttr.bInheritHandle = TRUE; 
	saAttr.lpSecurityDescriptor = NULL; 

	if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) {
		throw XArch(new XArchEvalWindows());
	}

	ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));

	while (m_monitoring) {
		try {

			if (m_processRunning && getCommand().empty()) {
				LOG((CLOG_INFO "process started but command is empty, shutting down"));
				shutdownExistingProcesses();
				m_processRunning = false;
				continue;
			}

			if (m_processFailures != 0) {
				// increasing backoff period, maximum of 10 seconds.
				int timeout = (m_processFailures * 2) < 10 ? (m_processFailures * 2) : 10;
				LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, m_processFailures));
				ARCH->sleep(timeout);
			}
		
			if (!getCommand().empty() && ((m_processFailures != 0) || m_session.hasChanged() || m_commandChanged)) {
				startProcess();
			}

			if (m_processRunning && !isProcessActive()) {

				m_processFailures++;
				m_processRunning = false;
			
				LOG((CLOG_WARN "detected application not running, pid=%d",
					m_processInfo.dwProcessId));
			}

			if (sendSasFunc != NULL) {

				HANDLE sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS");
				if (sendSasEvent != NULL) {

					// use SendSAS event to wait for next session (timeout 1 second).
					if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0) {
						LOG((CLOG_DEBUG "calling SendSAS"));
						sendSasFunc(FALSE);
					}

					CloseHandle(sendSasEvent);
					continue;
				}
			}

			// if the sas event failed, wait by sleeping.
			ARCH->sleep(1);
		
		}
		catch (std::exception& e) {
			LOG((CLOG_ERR "failed to launch, error: %s", e.what()));
			m_processFailures++;
			m_processRunning = false;
			continue;
		}
		catch (...) {
			LOG((CLOG_ERR "failed to launch, unknown error."));
			m_processFailures++;
			m_processRunning = false;
			continue;
		}
	}

	if (m_processRunning) {
		LOG((CLOG_DEBUG "terminated running process on exit"));
		shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20);
	}
	
	LOG((CLOG_DEBUG "watchdog main thread finished"));
}
Beispiel #4
0
void
CMSWindowsRelauncher::mainLoop(void*)
{
	shutdownExistingProcesses();

	SendSas sendSasFunc = NULL;
	HINSTANCE sasLib = LoadLibrary("sas.dll");
	if (sasLib) {
		LOG((CLOG_DEBUG "found sas.dll"));
		sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS");
	}

	DWORD sessionId = -1;
	bool launched = false;

	SECURITY_ATTRIBUTES saAttr; 
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
	saAttr.bInheritHandle = TRUE; 
	saAttr.lpSecurityDescriptor = NULL; 

	if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) {
		throw XArch(new XArchEvalWindows());
	}

	PROCESS_INFORMATION pi;
	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

	int failures = 0;

	while (m_running) {

		HANDLE sendSasEvent = 0;
		if (sasLib && sendSasFunc) {
			// can't we just create one event? seems weird creating a new
			// event every second...
			sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS");
		}

		DWORD newSessionId = getSessionId();

		bool running = false;
		if (launched) {

			DWORD exitCode;
			GetExitCodeProcess(pi.hProcess, &exitCode);
			running = (exitCode == STILL_ACTIVE);

			if (!running) {
				failures++;
				LOG((CLOG_INFO "detected application not running, pid=%d, failures=%d", pi.dwProcessId, failures));
				
				// increasing backoff period, maximum of 10 seconds.
				int timeout = (failures * 2) < 10 ? (failures * 2) : 10;
				LOG((CLOG_DEBUG "waiting, backoff period is %d seconds", timeout));
				ARCH->sleep(timeout);
				
				// double check, in case process started after we waited.
				GetExitCodeProcess(pi.hProcess, &exitCode);
				running = (exitCode == STILL_ACTIVE);
			}
			else {
				// reset failures when running.
				failures = 0;
			}
		}

		// only enter here when id changes, and the session isn't -1, which
		// may mean that there is no active session.
		bool sessionChanged = ((newSessionId != sessionId) && (newSessionId != -1));

		// relaunch if it was running but has stopped unexpectedly.
		bool stoppedRunning = (launched && !running);

		if (stoppedRunning || sessionChanged || m_commandChanged) {
			
			m_commandChanged = false;

			if (launched) {
				LOG((CLOG_DEBUG "closing existing process to make way for new one"));
				shutdownProcess(pi.hProcess, pi.dwProcessId, 20);
				launched = false;
			}

			// ok, this is now the active session (forget the old one if any)
			sessionId = newSessionId;

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

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

				// 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";
				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;
				}
				else {

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

					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 (sendSasEvent) {
			// use SendSAS event to wait for next session.
			if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0 && sendSasFunc) {
				LOG((CLOG_DEBUG "calling SendSAS"));
				sendSasFunc(FALSE);
			}
			CloseHandle(sendSasEvent);
		}
		else {
			// check for session change every second.
			ARCH->sleep(1);
		}
	}

	if (launched) {
		LOG((CLOG_DEBUG "terminated running process on exit"));
		shutdownProcess(pi.hProcess, pi.dwProcessId, 20);
	}
	
	LOG((CLOG_DEBUG "relauncher main thread finished"));
}
void
CMSWindowsRelauncher::mainLoop(void*)
{
	SendSas sendSasFunc = NULL;
	HINSTANCE sasLib = LoadLibrary("sas.dll");
	if (sasLib) {
		LOG((CLOG_DEBUG "found sas.dll"));
		sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS");
	}

	DWORD sessionId = -1;
	bool launched = false;

	SECURITY_ATTRIBUTES saAttr; 
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
	saAttr.bInheritHandle = TRUE; 
	saAttr.lpSecurityDescriptor = NULL; 

	if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) {
		throw XArch(new XArchEvalWindows());
	}

	PROCESS_INFORMATION pi;
	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

	while (m_running) {

		HANDLE sendSasEvent = 0;
		if (sasLib && sendSasFunc) {
			// can't we just create one event? seems weird creating a new
			// event every second...
			sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS");
		}

		DWORD newSessionId = getSessionId();

		// only enter here when id changes, and the session isn't -1, which
		// may mean that there is no active session.
		if (((newSessionId != sessionId) && (newSessionId != -1)) || m_commandChanged) {
			
			m_commandChanged = false;

			if (launched) {
				LOG((CLOG_DEBUG "closing existing process to make way for new one"));
				shutdownProcess(pi, 10);
				launched = false;
			}

			// ok, this is now the active session (forget the old one if any)
			sessionId = newSessionId;

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

			if (userToken != 0) {
				LOG((CLOG_DEBUG "got user token to launch new process"));

				std::string cmd = command();
				if (cmd == "") {
					LOG((CLOG_WARN "nothing to launch, no command specified."));
					continue;
				}

				// 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";
				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;
				}
				else {

					DWORD creationFlags = 
						NORMAL_PRIORITY_CLASS |
						CREATE_NO_WINDOW |
						CREATE_UNICODE_ENVIRONMENT;

					// re-launch in current active user session
					BOOL createRet = CreateProcessAsUser(
						userToken, NULL, LPSTR(cmd.c_str()),
						&sa, NULL, TRUE, creationFlags,
						environment, NULL, &si, &pi);

					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 (sendSasEvent) {
			// use SendSAS event to wait for next session.
			if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0 && sendSasFunc) {
				LOG((CLOG_DEBUG "calling SendSAS"));
				sendSasFunc(FALSE);
			}
			CloseHandle(sendSasEvent);
		}
		else {
			// check for session change every second.
			ARCH->sleep(1);
		}
	}

	if (launched) {
		LOG((CLOG_DEBUG "terminated running process on exit"));
		shutdownProcess(pi, 10);
	}
}