aboutsummaryrefslogtreecommitdiffstats
path: root/win/winvnc/VNCServerService.cxx
diff options
context:
space:
mode:
authorSamuel Mannehed <samuel@cendio.se>2014-02-07 14:53:24 +0000
committerSamuel Mannehed <samuel@cendio.se>2014-02-07 14:53:24 +0000
commit60c419320d2229ace017d1f599b6ab0a7b9e2927 (patch)
tree55eeba27730e7845b324ce748985712b2ae91070 /win/winvnc/VNCServerService.cxx
parentdc6af3740c36ec18e1c409096d6943951982d7ec (diff)
downloadtigervnc-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.cxx144
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);
}