mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2024-11-27 10:33:34 +01:00
184 lines
5.8 KiB
C++
184 lines
5.8 KiB
C++
/* 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
|
|
|
|
#include <winvnc/VNCServerService.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("KasmVNC");
|
|
|
|
// 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\\SessionEventKasmVNC"))
|
|
, sessionEventCad(CreateEvent(0, FALSE, FALSE, "Global\\SessionEventKasmVNCCad")) {
|
|
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);
|
|
}
|