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