You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VNCServerService.cxx 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. // -=- WinVNC Version 4.0 Service-Mode implementation
  19. #ifdef HAVE_CONFIG_H
  20. #include <config.h>
  21. #endif
  22. #include <winvnc/VNCServerService.h>
  23. #include <rfb/LogWriter.h>
  24. #include <rfb_win32/TsSessions.h>
  25. #include <rfb_win32/ModuleFileName.h>
  26. #include <windows.h>
  27. #include <wtsapi32.h>
  28. #include <tlhelp32.h>
  29. using namespace winvnc;
  30. using namespace rfb;
  31. using namespace win32;
  32. const TCHAR* winvnc::VNCServerService::Name = _T("TigerVNC");
  33. // SendSAS is not available until Windows 7, and missing from MinGW
  34. static HMODULE sasLibrary = NULL;
  35. typedef void WINAPI (*SendSAS_proto)(BOOL AsUser);
  36. static SendSAS_proto _SendSAS = NULL;
  37. VNCServerService::VNCServerService()
  38. : Service(Name)
  39. , stopServiceEvent(CreateEvent(0, FALSE, FALSE, 0))
  40. , sessionEvent(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNC"))
  41. , sessionEventCad(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNCCad")) {
  42. if (sasLibrary == NULL) {
  43. sasLibrary = LoadLibrary("sas.dll");
  44. if (sasLibrary != NULL)
  45. _SendSAS = (SendSAS_proto)GetProcAddress(sasLibrary, "SendSAS");
  46. }
  47. // - Set the service-mode logging defaults
  48. // These will be overridden by the Log option in the
  49. // registry, if present.
  50. logParams.setParam("*:EventLog:0,Connections:EventLog:100");
  51. }
  52. //////////////////////////////////////////////////////////////////////////////
  53. DWORD GetLogonPid(DWORD dwSessionId)
  54. {
  55. DWORD dwLogonPid = 0;
  56. HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  57. if (hSnap != INVALID_HANDLE_VALUE)
  58. {
  59. PROCESSENTRY32 procEntry;
  60. procEntry.dwSize = sizeof procEntry;
  61. if (Process32First(hSnap, &procEntry)) do
  62. {
  63. DWORD dwLogonSessionId = 0;
  64. if (_stricmp(procEntry.szExeFile, "winlogon.exe") == 0 &&
  65. ProcessIdToSessionId(procEntry.th32ProcessID, &dwLogonSessionId) &&
  66. dwLogonSessionId == dwSessionId)
  67. {
  68. dwLogonPid = procEntry.th32ProcessID;
  69. break;
  70. }
  71. } while (Process32Next(hSnap, &procEntry));
  72. CloseHandle(hSnap);
  73. }
  74. return dwLogonPid;
  75. }
  76. //////////////////////////////////////////////////////////////////////////////
  77. BOOL GetSessionUserTokenWin(OUT LPHANDLE lphUserToken)
  78. {
  79. BOOL bResult = FALSE;
  80. ConsoleSessionId ID_session;
  81. DWORD Id = GetLogonPid(ID_session.id);
  82. if (HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Id))
  83. {
  84. bResult = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, lphUserToken);
  85. CloseHandle(hProcess);
  86. }
  87. return bResult;
  88. }
  89. //////////////////////////////////////////////////////////////////////////////
  90. // START the app as system
  91. HANDLE LaunchProcessWin(DWORD /*dwSessionId*/)
  92. {
  93. HANDLE hProcess = NULL;
  94. HANDLE hToken = NULL;
  95. if (GetSessionUserTokenWin(&hToken))
  96. {
  97. ModuleFileName filename;
  98. TCharArray cmdLine;
  99. cmdLine.format("\"%s\" -noconsole -service_run", filename.buf);
  100. STARTUPINFO si;
  101. ZeroMemory(&si, sizeof si);
  102. si.cb = sizeof si;
  103. si.dwFlags = STARTF_USESHOWWINDOW;
  104. PROCESS_INFORMATION pi;
  105. if (CreateProcessAsUser(hToken, NULL, cmdLine.buf, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
  106. {
  107. CloseHandle(pi.hThread);
  108. hProcess = pi.hProcess;
  109. }
  110. CloseHandle(hToken);
  111. }
  112. return hProcess;
  113. }
  114. DWORD VNCServerService::serviceMain(int /*argc*/, TCHAR* /*argv*/ [])
  115. {
  116. ConsoleSessionId OlddwSessionId;
  117. HANDLE hProcess = NULL;
  118. //We use this event to notify the program that the session has changed
  119. //The program need to end so the service can restart the program in the correct session
  120. //wait_for_existing_process();
  121. HANDLE testevent[2] = { stopServiceEvent, sessionEventCad };
  122. setStatus(SERVICE_RUNNING);
  123. while (status.dwCurrentState == SERVICE_RUNNING)
  124. {
  125. DWORD dwEvent = WaitForMultipleObjects(2, testevent, FALSE, 1000);
  126. switch (dwEvent)
  127. {
  128. //stopServiceEvent, exit while loop
  129. case WAIT_OBJECT_0 + 0:
  130. setStatus(SERVICE_STOP_PENDING);
  131. break;
  132. //cad request
  133. case WAIT_OBJECT_0 + 1:
  134. if (_SendSAS != NULL)
  135. _SendSAS(FALSE);
  136. break;
  137. case WAIT_TIMEOUT:
  138. {
  139. ConsoleSessionId dwSessionId;
  140. if (OlddwSessionId.id != dwSessionId.id)
  141. {
  142. OlddwSessionId.id = dwSessionId.id;
  143. SetEvent(sessionEvent);
  144. }
  145. DWORD dwExitCode = 0;
  146. if (hProcess == NULL ||
  147. (GetExitCodeProcess(hProcess, &dwExitCode) &&
  148. dwExitCode != STILL_ACTIVE &&
  149. CloseHandle(hProcess)))
  150. {
  151. hProcess = LaunchProcessWin(dwSessionId.id);
  152. }
  153. }
  154. break;
  155. }
  156. }
  157. SetEvent(sessionEvent);
  158. if (hProcess)
  159. {
  160. WaitForSingleObject(hProcess, 15000);
  161. CloseHandle(hProcess);
  162. }
  163. return 0;
  164. }
  165. void VNCServerService::stop() {
  166. SetEvent(stopServiceEvent);
  167. SetEvent(sessionEvent);
  168. }