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.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. #include <winvnc/VNCServerService.h>
  20. #include <rfb/LogWriter.h>
  21. #include <rfb_win32/TsSessions.h>
  22. #include <rfb_win32/ModuleFileName.h>
  23. #include <windows.h>
  24. #include <wtsapi32.h>
  25. #include <tlhelp32.h>
  26. using namespace winvnc;
  27. using namespace rfb;
  28. using namespace win32;
  29. const TCHAR* winvnc::VNCServerService::Name = _T("TigerVNC");
  30. // SendSAS is not available until Windows 7, and missing from MinGW
  31. static HMODULE sasLibrary = NULL;
  32. typedef void WINAPI (*SendSAS_proto)(BOOL AsUser);
  33. static SendSAS_proto _SendSAS = NULL;
  34. VNCServerService::VNCServerService()
  35. : Service(Name)
  36. , stopServiceEvent(CreateEvent(0, FALSE, FALSE, 0))
  37. , sessionEvent(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNC"))
  38. , sessionEventCad(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNCCad")) {
  39. if (sasLibrary == NULL) {
  40. sasLibrary = LoadLibrary("sas.dll");
  41. if (sasLibrary != NULL)
  42. _SendSAS = (SendSAS_proto)GetProcAddress(sasLibrary, "SendSAS");
  43. }
  44. // - Set the service-mode logging defaults
  45. // These will be overridden by the Log option in the
  46. // registry, if present.
  47. logParams.setParam("*:EventLog:0,Connections:EventLog:100");
  48. }
  49. //////////////////////////////////////////////////////////////////////////////
  50. DWORD GetLogonPid(DWORD dwSessionId)
  51. {
  52. DWORD dwLogonPid = 0;
  53. HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  54. if (hSnap != INVALID_HANDLE_VALUE)
  55. {
  56. PROCESSENTRY32 procEntry;
  57. procEntry.dwSize = sizeof procEntry;
  58. if (Process32First(hSnap, &procEntry)) do
  59. {
  60. DWORD dwLogonSessionId = 0;
  61. if (_stricmp(procEntry.szExeFile, "winlogon.exe") == 0 &&
  62. ProcessIdToSessionId(procEntry.th32ProcessID, &dwLogonSessionId) &&
  63. dwLogonSessionId == dwSessionId)
  64. {
  65. dwLogonPid = procEntry.th32ProcessID;
  66. break;
  67. }
  68. } while (Process32Next(hSnap, &procEntry));
  69. CloseHandle(hSnap);
  70. }
  71. return dwLogonPid;
  72. }
  73. //////////////////////////////////////////////////////////////////////////////
  74. BOOL GetSessionUserTokenWin(OUT LPHANDLE lphUserToken)
  75. {
  76. BOOL bResult = FALSE;
  77. ConsoleSessionId ID_session;
  78. DWORD Id = GetLogonPid(ID_session.id);
  79. if (HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Id))
  80. {
  81. bResult = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, lphUserToken);
  82. CloseHandle(hProcess);
  83. }
  84. return bResult;
  85. }
  86. //////////////////////////////////////////////////////////////////////////////
  87. // START the app as system
  88. HANDLE LaunchProcessWin(DWORD dwSessionId)
  89. {
  90. HANDLE hProcess = NULL;
  91. HANDLE hToken = NULL;
  92. if (GetSessionUserTokenWin(&hToken))
  93. {
  94. ModuleFileName filename;
  95. TCharArray cmdLine;
  96. cmdLine.format("\"%s\" -noconsole -service_run", filename.buf);
  97. STARTUPINFO si;
  98. ZeroMemory(&si, sizeof si);
  99. si.cb = sizeof si;
  100. si.dwFlags = STARTF_USESHOWWINDOW;
  101. PROCESS_INFORMATION pi;
  102. if (CreateProcessAsUser(hToken, NULL, cmdLine.buf, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
  103. {
  104. CloseHandle(pi.hThread);
  105. hProcess = pi.hProcess;
  106. }
  107. CloseHandle(hToken);
  108. }
  109. return hProcess;
  110. }
  111. DWORD VNCServerService::serviceMain(int argc, TCHAR* argv[])
  112. {
  113. ConsoleSessionId OlddwSessionId;
  114. HANDLE hProcess = NULL;
  115. //We use this event to notify the program that the session has changed
  116. //The program need to end so the service can restart the program in the correct session
  117. //wait_for_existing_process();
  118. HANDLE testevent[2] = { stopServiceEvent, sessionEventCad };
  119. setStatus(SERVICE_RUNNING);
  120. while (status.dwCurrentState == SERVICE_RUNNING)
  121. {
  122. DWORD dwEvent = WaitForMultipleObjects(2, testevent, FALSE, 1000);
  123. switch (dwEvent)
  124. {
  125. //stopServiceEvent, exit while loop
  126. case WAIT_OBJECT_0 + 0:
  127. setStatus(SERVICE_STOP_PENDING);
  128. break;
  129. //cad request
  130. case WAIT_OBJECT_0 + 1:
  131. if (_SendSAS != NULL)
  132. _SendSAS(FALSE);
  133. break;
  134. case WAIT_TIMEOUT:
  135. {
  136. ConsoleSessionId dwSessionId;
  137. if (OlddwSessionId.id != dwSessionId.id)
  138. {
  139. OlddwSessionId.id = dwSessionId.id;
  140. SetEvent(sessionEvent);
  141. }
  142. DWORD dwExitCode = 0;
  143. if (hProcess == NULL ||
  144. (GetExitCodeProcess(hProcess, &dwExitCode) &&
  145. dwExitCode != STILL_ACTIVE &&
  146. CloseHandle(hProcess)))
  147. {
  148. hProcess = LaunchProcessWin(dwSessionId.id);
  149. }
  150. }
  151. break;
  152. }
  153. }
  154. SetEvent(sessionEvent);
  155. if (hProcess)
  156. {
  157. WaitForSingleObject(hProcess, 15000);
  158. CloseHandle(hProcess);
  159. }
  160. return 0;
  161. }
  162. void VNCServerService::stop() {
  163. SetEvent(stopServiceEvent);
  164. SetEvent(sessionEvent);
  165. }