diff options
author | Samuel Mannehed <samuel@cendio.se> | 2014-02-07 14:53:24 +0000 |
---|---|---|
committer | Samuel Mannehed <samuel@cendio.se> | 2014-02-07 14:53:24 +0000 |
commit | 60c419320d2229ace017d1f599b6ab0a7b9e2927 (patch) | |
tree | 55eeba27730e7845b324ce748985712b2ae91070 /win/winvnc/VNCServerService.cxx | |
parent | dc6af3740c36ec18e1c409096d6943951982d7ec (diff) | |
download | tigervnc-60c419320d2229ace017d1f599b6ab0a7b9e2927.tar.gz tigervnc-60c419320d2229ace017d1f599b6ab0a7b9e2927.zip |
Make WinVNC service mode work on Windows Vista and beyond.
Patch by Jochen Tucht, fixes bug 135.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@5158 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'win/winvnc/VNCServerService.cxx')
-rw-r--r-- | win/winvnc/VNCServerService.cxx | 144 |
1 files changed, 135 insertions, 9 deletions
diff --git a/win/winvnc/VNCServerService.cxx b/win/winvnc/VNCServerService.cxx index 2ef2ee08..1a2a8e93 100644 --- a/win/winvnc/VNCServerService.cxx +++ b/win/winvnc/VNCServerService.cxx @@ -20,6 +20,10 @@ #include <winvnc/VNCServerService.h> #include <rfb_win32/OSVersion.h> +#include <rfb_win32/TsSessions.h> +#include <rfb_win32/ModuleFileName.h> +#include <wtsapi32.h> +#include <tlhelp32.h> using namespace winvnc; using namespace rfb; @@ -27,9 +31,12 @@ using namespace win32; const TCHAR* winvnc::VNCServerService::Name = _T("WinVNC4"); - -VNCServerService::VNCServerService(VNCServerWin32& s) - : Service(Name), server(s) { +VNCServerService::VNCServerService() + : Service(Name) + , SendSas(_T("sas.dll"), "SendSAS") + , stopServiceEvent(CreateEvent(0, FALSE, FALSE, 0)) + , sessionEvent(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNC")) + , sessionEventCad(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNCCad")) { // - Set the service-mode logging defaults // These will be overridden by the Log option in the // registry, if present. @@ -40,13 +47,132 @@ VNCServerService::VNCServerService(VNCServerWin32& s) } -DWORD VNCServerService::serviceMain(int argc, TCHAR* argv[]) { - setStatus(SERVICE_RUNNING); - int result = server.run(); - setStatus(SERVICE_STOP_PENDING); - return result; +////////////////////////////////////////////////////////////////////////////// + +DWORD GetLogonPid(DWORD dwSessionId) +{ + DWORD dwLogonPid = 0; + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnap != INVALID_HANDLE_VALUE) + { + PROCESSENTRY32 procEntry; + procEntry.dwSize = sizeof procEntry; + + if (Process32First(hSnap, &procEntry)) do + { + DWORD dwLogonSessionId = 0; + if (_stricmp(procEntry.szExeFile, "winlogon.exe") == 0 && + ProcessIdToSessionId(procEntry.th32ProcessID, &dwLogonSessionId) && + dwLogonSessionId == dwSessionId) + { + dwLogonPid = procEntry.th32ProcessID; + break; + } + } while (Process32Next(hSnap, &procEntry)); + CloseHandle(hSnap); + } + return dwLogonPid; +} + +////////////////////////////////////////////////////////////////////////////// +BOOL GetSessionUserTokenWin(OUT LPHANDLE lphUserToken) +{ + BOOL bResult = FALSE; + ConsoleSessionId ID_session; + DWORD Id = GetLogonPid(ID_session.id); + if (HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Id)) + { + bResult = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, lphUserToken); + CloseHandle(hProcess); + } + return bResult; +} + +////////////////////////////////////////////////////////////////////////////// +// START the app as system +HANDLE LaunchProcessWin(DWORD dwSessionId) +{ + HANDLE hProcess = NULL; + HANDLE hToken = NULL; + if (GetSessionUserTokenWin(&hToken)) + { + ModuleFileName filename; + static const char cmdLineFmt[] = "\"%s\" -noconsole -service_run"; + TCharArray cmdLine(_tcslen(filename.buf) + sizeof(cmdLineFmt)/sizeof(cmdLineFmt[0])); + _stprintf(cmdLine.buf, cmdLineFmt, filename.buf); + STARTUPINFO si; + ZeroMemory(&si, sizeof si); + si.cb = sizeof si; + si.dwFlags = STARTF_USESHOWWINDOW; + PROCESS_INFORMATION pi; + if (CreateProcessAsUser(hToken, NULL, cmdLine.buf, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi)) + { + CloseHandle(pi.hThread); + hProcess = pi.hProcess; + } + CloseHandle(hToken); + } + return hProcess; +} + +DWORD VNCServerService::serviceMain(int argc, TCHAR* argv[]) +{ + ConsoleSessionId OlddwSessionId; + + HANDLE hProcess = NULL; + //We use this event to notify the program that the session has changed + //The program need to end so the service can restart the program in the correct session + //wait_for_existing_process(); + HANDLE testevent[2] = { stopServiceEvent, sessionEventCad }; + setStatus(SERVICE_RUNNING); + while (status.dwCurrentState == SERVICE_RUNNING) + { + DWORD dwEvent = WaitForMultipleObjects(2, testevent, FALSE, 1000); + switch (dwEvent) + { + //stopServiceEvent, exit while loop + case WAIT_OBJECT_0 + 0: + setStatus(SERVICE_STOP_PENDING); + break; + + //cad request + case WAIT_OBJECT_0 + 1: + if (SendSas.isValid()) + (*SendSas)(FALSE); + break; + + case WAIT_TIMEOUT: + { + ConsoleSessionId dwSessionId; + if (OlddwSessionId.id != dwSessionId.id) + { + OlddwSessionId.id = dwSessionId.id; + SetEvent(sessionEvent); + } + DWORD dwExitCode = 0; + if (hProcess == NULL || + (GetExitCodeProcess(hProcess, &dwExitCode) && + dwExitCode != STILL_ACTIVE && + CloseHandle(hProcess))) + { + hProcess = LaunchProcessWin(dwSessionId.id); + } + } + break; + } + } + + SetEvent(sessionEvent); + + if (hProcess) + { + WaitForSingleObject(hProcess, 15000); + CloseHandle(hProcess); + } + return 0; } void VNCServerService::stop() { - server.stop(); + SetEvent(stopServiceEvent); + SetEvent(sessionEvent); } |