123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
- // -=- WinVNC Version 4.0 Service-Mode implementation
-
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
-
- #include <winvnc/VNCServerService.h>
- #include <rfb/LogWriter.h>
- #include <rfb_win32/TsSessions.h>
- #include <rfb_win32/ModuleFileName.h>
- #include <windows.h>
- #include <wtsapi32.h>
- #include <tlhelp32.h>
-
- using namespace winvnc;
- using namespace rfb;
- using namespace win32;
-
- const TCHAR* winvnc::VNCServerService::Name = _T("TigerVNC");
-
- // SendSAS is not available until Windows 7, and missing from MinGW
- static HMODULE sasLibrary = NULL;
- typedef void WINAPI (*SendSAS_proto)(BOOL AsUser);
- static SendSAS_proto _SendSAS = NULL;
-
- VNCServerService::VNCServerService()
- : Service(Name)
- , stopServiceEvent(CreateEvent(0, FALSE, FALSE, 0))
- , sessionEvent(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNC"))
- , sessionEventCad(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNCCad")) {
- if (sasLibrary == NULL) {
- sasLibrary = LoadLibrary("sas.dll");
- if (sasLibrary != NULL)
- _SendSAS = (SendSAS_proto)GetProcAddress(sasLibrary, "SendSAS");
- }
- // - Set the service-mode logging defaults
- // These will be overridden by the Log option in the
- // registry, if present.
- logParams.setParam("*:EventLog:0,Connections:EventLog:100");
- }
-
-
- //////////////////////////////////////////////////////////////////////////////
-
- DWORD GetLogonPid(DWORD dwSessionId)
- {
- DWORD dwLogonPid = 0;
- HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if (hSnap != INVALID_HANDLE_VALUE)
- {
- PROCESSENTRY32 procEntry;
- procEntry.dwSize = sizeof procEntry;
-
- if (Process32First(hSnap, &procEntry)) do
- {
- DWORD dwLogonSessionId = 0;
- if (_stricmp(procEntry.szExeFile, "winlogon.exe") == 0 &&
- ProcessIdToSessionId(procEntry.th32ProcessID, &dwLogonSessionId) &&
- dwLogonSessionId == dwSessionId)
- {
- dwLogonPid = procEntry.th32ProcessID;
- break;
- }
- } while (Process32Next(hSnap, &procEntry));
- CloseHandle(hSnap);
- }
- return dwLogonPid;
- }
-
- //////////////////////////////////////////////////////////////////////////////
- BOOL GetSessionUserTokenWin(OUT LPHANDLE lphUserToken)
- {
- BOOL bResult = FALSE;
- ConsoleSessionId ID_session;
- DWORD Id = GetLogonPid(ID_session.id);
- if (HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Id))
- {
- bResult = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, lphUserToken);
- CloseHandle(hProcess);
- }
- return bResult;
- }
-
- //////////////////////////////////////////////////////////////////////////////
- // START the app as system
- HANDLE LaunchProcessWin(DWORD dwSessionId)
- {
- HANDLE hProcess = NULL;
- HANDLE hToken = NULL;
- if (GetSessionUserTokenWin(&hToken))
- {
- ModuleFileName filename;
- TCharArray cmdLine;
- cmdLine.format("\"%s\" -noconsole -service_run", filename.buf);
- STARTUPINFO si;
- ZeroMemory(&si, sizeof si);
- si.cb = sizeof si;
- si.dwFlags = STARTF_USESHOWWINDOW;
- PROCESS_INFORMATION pi;
- if (CreateProcessAsUser(hToken, NULL, cmdLine.buf, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
- {
- CloseHandle(pi.hThread);
- hProcess = pi.hProcess;
- }
- CloseHandle(hToken);
- }
- return hProcess;
- }
-
- DWORD VNCServerService::serviceMain(int argc, TCHAR* argv[])
- {
- ConsoleSessionId OlddwSessionId;
-
- HANDLE hProcess = NULL;
- //We use this event to notify the program that the session has changed
- //The program need to end so the service can restart the program in the correct session
- //wait_for_existing_process();
- HANDLE testevent[2] = { stopServiceEvent, sessionEventCad };
- setStatus(SERVICE_RUNNING);
- while (status.dwCurrentState == SERVICE_RUNNING)
- {
- DWORD dwEvent = WaitForMultipleObjects(2, testevent, FALSE, 1000);
- switch (dwEvent)
- {
- //stopServiceEvent, exit while loop
- case WAIT_OBJECT_0 + 0:
- setStatus(SERVICE_STOP_PENDING);
- break;
-
- //cad request
- case WAIT_OBJECT_0 + 1:
- if (_SendSAS != NULL)
- _SendSAS(FALSE);
- break;
-
- case WAIT_TIMEOUT:
- {
- ConsoleSessionId dwSessionId;
- if (OlddwSessionId.id != dwSessionId.id)
- {
- OlddwSessionId.id = dwSessionId.id;
- SetEvent(sessionEvent);
- }
- DWORD dwExitCode = 0;
- if (hProcess == NULL ||
- (GetExitCodeProcess(hProcess, &dwExitCode) &&
- dwExitCode != STILL_ACTIVE &&
- CloseHandle(hProcess)))
- {
- hProcess = LaunchProcessWin(dwSessionId.id);
- }
- }
- break;
- }
- }
-
- SetEvent(sessionEvent);
-
- if (hProcess)
- {
- WaitForSingleObject(hProcess, 15000);
- CloseHandle(hProcess);
- }
- return 0;
- }
-
- void VNCServerService::stop() {
- SetEvent(stopServiceEvent);
- SetEvent(sessionEvent);
- }
|