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