blob: 1a2a8e93aaac3aa5bf469d4786ce394e0f8a48eb [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;
100 static const char cmdLineFmt[] = "\"%s\" -noconsole -service_run";
101 TCharArray cmdLine(_tcslen(filename.buf) + sizeof(cmdLineFmt)/sizeof(cmdLineFmt[0]));
102 _stprintf(cmdLine.buf, cmdLineFmt, filename.buf);
103 STARTUPINFO si;
104 ZeroMemory(&si, sizeof si);
105 si.cb = sizeof si;
106 si.dwFlags = STARTF_USESHOWWINDOW;
107 PROCESS_INFORMATION pi;
108 if (CreateProcessAsUser(hToken, NULL, cmdLine.buf, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
109 {
110 CloseHandle(pi.hThread);
111 hProcess = pi.hProcess;
112 }
113 CloseHandle(hToken);
114 }
115 return hProcess;
116}
117
118DWORD VNCServerService::serviceMain(int argc, TCHAR* argv[])
119{
120 ConsoleSessionId OlddwSessionId;
121
122 HANDLE hProcess = NULL;
123 //We use this event to notify the program that the session has changed
124 //The program need to end so the service can restart the program in the correct session
125 //wait_for_existing_process();
126 HANDLE testevent[2] = { stopServiceEvent, sessionEventCad };
127 setStatus(SERVICE_RUNNING);
128 while (status.dwCurrentState == SERVICE_RUNNING)
129 {
130 DWORD dwEvent = WaitForMultipleObjects(2, testevent, FALSE, 1000);
131 switch (dwEvent)
132 {
133 //stopServiceEvent, exit while loop
134 case WAIT_OBJECT_0 + 0:
135 setStatus(SERVICE_STOP_PENDING);
136 break;
137
138 //cad request
139 case WAIT_OBJECT_0 + 1:
140 if (SendSas.isValid())
141 (*SendSas)(FALSE);
142 break;
143
144 case WAIT_TIMEOUT:
145 {
146 ConsoleSessionId dwSessionId;
147 if (OlddwSessionId.id != dwSessionId.id)
148 {
149 OlddwSessionId.id = dwSessionId.id;
150 SetEvent(sessionEvent);
151 }
152 DWORD dwExitCode = 0;
153 if (hProcess == NULL ||
154 (GetExitCodeProcess(hProcess, &dwExitCode) &&
155 dwExitCode != STILL_ACTIVE &&
156 CloseHandle(hProcess)))
157 {
158 hProcess = LaunchProcessWin(dwSessionId.id);
159 }
160 }
161 break;
162 }
163 }
164
165 SetEvent(sessionEvent);
166
167 if (hProcess)
168 {
169 WaitForSingleObject(hProcess, 15000);
170 CloseHandle(hProcess);
171 }
172 return 0;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000173}
174
175void VNCServerService::stop() {
Samuel Mannehed60c41932014-02-07 14:53:24 +0000176 SetEvent(stopServiceEvent);
177 SetEvent(sessionEvent);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000178}