You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			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);
 | 
						|
}
 |