blob: 481df217182f576b6674d56d7797798cd12a89de [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>
22#include <rfb_win32/OSVersion.h>
Samuel Mannehed60c41932014-02-07 14:53:24 +000023#include <rfb_win32/TsSessions.h>
24#include <rfb_win32/ModuleFileName.h>
25#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
32const TCHAR* winvnc::VNCServerService::Name = _T("WinVNC4");
33
Samuel Mannehed60c41932014-02-07 14:53:24 +000034VNCServerService::VNCServerService()
35 : Service(Name)
36 , SendSas(_T("sas.dll"), "SendSAS")
37 , stopServiceEvent(CreateEvent(0, FALSE, FALSE, 0))
38 , sessionEvent(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNC"))
39 , sessionEventCad(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNCCad")) {
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000040 // - Set the service-mode logging defaults
41 // These will be overridden by the Log option in the
42 // registry, if present.
43 if (osVersion.isPlatformNT)
44 logParams.setParam("*:EventLog:0,Connections:EventLog:100");
45 else
46 logParams.setParam("*:file:0,Connections:file:100");
47}
48
49
Samuel Mannehed60c41932014-02-07 14:53:24 +000050//////////////////////////////////////////////////////////////////////////////
51
52DWORD GetLogonPid(DWORD dwSessionId)
53{
54 DWORD dwLogonPid = 0;
55 HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
56 if (hSnap != INVALID_HANDLE_VALUE)
57 {
58 PROCESSENTRY32 procEntry;
59 procEntry.dwSize = sizeof procEntry;
60
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//////////////////////////////////////////////////////////////////////////////
78BOOL GetSessionUserTokenWin(OUT LPHANDLE lphUserToken)
79{
80 BOOL bResult = FALSE;
81 ConsoleSessionId ID_session;
82 DWORD Id = GetLogonPid(ID_session.id);
83 if (HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Id))
84 {
85 bResult = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, lphUserToken);
86 CloseHandle(hProcess);
87 }
88 return bResult;
89}
90
91//////////////////////////////////////////////////////////////////////////////
92// START the app as system
93HANDLE LaunchProcessWin(DWORD dwSessionId)
94{
95 HANDLE hProcess = NULL;
96 HANDLE hToken = NULL;
97 if (GetSessionUserTokenWin(&hToken))
98 {
99 ModuleFileName filename;
Pierre Ossmanba6fbfe2015-03-03 16:41:29 +0100100 TCharArray cmdLine;
101 cmdLine.format("\"%s\" -noconsole -service_run", filename.buf);
Samuel Mannehed60c41932014-02-07 14:53:24 +0000102 STARTUPINFO si;
103 ZeroMemory(&si, sizeof si);
104 si.cb = sizeof si;
105 si.dwFlags = STARTF_USESHOWWINDOW;
106 PROCESS_INFORMATION pi;
107 if (CreateProcessAsUser(hToken, NULL, cmdLine.buf, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
108 {
109 CloseHandle(pi.hThread);
110 hProcess = pi.hProcess;
111 }
112 CloseHandle(hToken);
113 }
114 return hProcess;
115}
116
117DWORD VNCServerService::serviceMain(int argc, TCHAR* argv[])
118{
119 ConsoleSessionId OlddwSessionId;
120
121 HANDLE hProcess = NULL;
122 //We use this event to notify the program that the session has changed
123 //The program need to end so the service can restart the program in the correct session
124 //wait_for_existing_process();
125 HANDLE testevent[2] = { stopServiceEvent, sessionEventCad };
126 setStatus(SERVICE_RUNNING);
127 while (status.dwCurrentState == SERVICE_RUNNING)
128 {
129 DWORD dwEvent = WaitForMultipleObjects(2, testevent, FALSE, 1000);
130 switch (dwEvent)
131 {
132 //stopServiceEvent, exit while loop
133 case WAIT_OBJECT_0 + 0:
134 setStatus(SERVICE_STOP_PENDING);
135 break;
136
137 //cad request
138 case WAIT_OBJECT_0 + 1:
139 if (SendSas.isValid())
140 (*SendSas)(FALSE);
141 break;
142
143 case WAIT_TIMEOUT:
144 {
145 ConsoleSessionId dwSessionId;
146 if (OlddwSessionId.id != dwSessionId.id)
147 {
148 OlddwSessionId.id = dwSessionId.id;
149 SetEvent(sessionEvent);
150 }
151 DWORD dwExitCode = 0;
152 if (hProcess == NULL ||
153 (GetExitCodeProcess(hProcess, &dwExitCode) &&
154 dwExitCode != STILL_ACTIVE &&
155 CloseHandle(hProcess)))
156 {
157 hProcess = LaunchProcessWin(dwSessionId.id);
158 }
159 }
160 break;
161 }
162 }
163
164 SetEvent(sessionEvent);
165
166 if (hProcess)
167 {
168 WaitForSingleObject(hProcess, 15000);
169 CloseHandle(hProcess);
170 }
171 return 0;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000172}
173
174void VNCServerService::stop() {
Samuel Mannehed60c41932014-02-07 14:53:24 +0000175 SetEvent(stopServiceEvent);
176 SetEvent(sessionEvent);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000177}