Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2960 lines
80 KiB

/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name:
sessmgr.cpp
Abstract:
ATL wizard generated code.
Author:
HueiWang 2/17/2000
--*/
// Note: Proxy/Stub Information
// To build a separate proxy/stub DLL,
// run nmake -f sessmgrps.mk in the project directory.
#include "stdafx.h"
#include "resource.h"
#include <initguid.h>
#include <process.h>
#include <tchar.h>
#include "sessmgr.h"
#include "sessmgr_i.c"
#include <stdio.h>
//#include <new.h>
#include "global.h"
#include "HelpSess.h"
#include "HelpMgr.h"
#include "helper.h"
#include "helpacc.h"
#include <rdshost.h>
#include "policy.h"
#include "remotedesktoputils.h"
#define SETUPLOGFILE_NAME _TEXT("sessmgr.setup.log")
#define SESSMGR_SERVICE 0
#define SESSMGR_REGSERVER 1
#define SESSMGR_UNREGSERVER 2
#define SESSMGR_SP1UPGRADE 3
BEGIN_OBJECT_MAP(ObjectMap)
//OBJECT_ENTRY(CLSID_RemoteDesktopHelpSession, CRemoteDesktopHelpSession)
OBJECT_ENTRY(CLSID_RemoteDesktopHelpSessionMgr, CRemoteDesktopHelpSessionMgr)
END_OBJECT_MAP()
CServiceModule _Module;
HANDLE g_hTSCertificateChanged = NULL;
HANDLE g_hWaitTSCertificateChanged = NULL;
HKEY g_hTSCertificateRegKey = NULL;
VOID CALLBACK
TSCertChangeCallback(
PVOID pContext,
BOOLEAN bTimerOrWaitFired
)
/*++
Callback for TS certificate registry change from threadpool function.
--*/
{
MYASSERT( FALSE == bTimerOrWaitFired );
// Our wait is forever so can't be timeout.
if( FALSE == bTimerOrWaitFired )
{
PostThreadMessage(
_Module.dwThreadID,
WM_LOADTSPUBLICKEY,
0,
0
);
}
else
{
DebugPrintf(
_TEXT("TSCertChangeCallback does not expect timeout...\n") );
MYASSERT(FALSE);
}
}
DWORD
LoadTermSrvSecurityBlob()
/*++
Function to load TS machine specific identification blob, for now
we use TS public key.
--*/
{
DWORD dwStatus;
PBYTE pbTSPublicKey = NULL;
DWORD cbTSPublicKey = 0;
DWORD dwType;
DWORD cbData;
BOOL bSuccess;
BOOL bUsesX509PublicKey = FALSE;
if( NULL == g_hTSCertificateRegKey )
{
MYASSERT(FALSE);
dwStatus = ERROR_INTERNAL_ERROR;
goto CLEANUPANDEXIT;
}
//
// Make sure TS certificate is there before
// we directly load public key from LSA
//
dwStatus = RegQueryValueEx(
g_hTSCertificateRegKey,
REGVALUE_TSX509_CERT,
NULL,
&dwType,
NULL,
&cbData
);
if( ERROR_SUCCESS == dwStatus )
{
DebugPrintf(
_TEXT("TermSrv X509 certificate found, trying to load TS X509 public key\n")
);
cbTSPublicKey = 0;
//
// Current TLSAPI does not support retrival of
// X509 certificate public key and TS cert is in
// special format not standard x509 cert chain.
//
dwStatus = LsCsp_RetrieveSecret(
LSA_TSX509_CERT_PUBLIC_KEY_NAME,
NULL,
&cbTSPublicKey
);
if( LICENSE_STATUS_OK != dwStatus &&
LICENSE_STATUS_INSUFFICIENT_BUFFER != dwStatus )
{
MYASSERT( FALSE );
goto CLEANUPANDEXIT;
}
pbTSPublicKey = (PBYTE)LocalAlloc( LPTR, cbTSPublicKey );
if( NULL == pbTSPublicKey )
{
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
dwStatus = LsCsp_RetrieveSecret(
LSA_TSX509_CERT_PUBLIC_KEY_NAME,
pbTSPublicKey,
&cbTSPublicKey
);
//
// Critical error, We have certificate in registry
// but don't have public key in LSA
//
MYASSERT( LICENSE_STATUS_OK == dwStatus );
if( LICENSE_STATUS_OK != dwStatus )
{
DebugPrintf(
_TEXT("TermSrv X509 certificate found but can't load X509 public key\n")
);
goto CLEANUPANDEXIT;
}
bUsesX509PublicKey = TRUE;
}
else
{
DebugPrintf(
_TEXT("TermSrv X509 certificate not found\n")
);
//
// Load pre-define TS public key
//
dwStatus = LsCsp_GetServerData(
LsCspInfo_PublicKey,
pbTSPublicKey,
&cbTSPublicKey
);
// expecting insufficient buffer
if( LICENSE_STATUS_INSUFFICIENT_BUFFER != dwStatus &&
LICENSE_STATUS_OK != dwStatus )
{
// invalid return code.
MYASSERT(FALSE);
goto CLEANUPANDEXIT;
}
MYASSERT( cbTSPublicKey > 0 );
pbTSPublicKey = (PBYTE)LocalAlloc( LPTR, cbTSPublicKey );
if( NULL == pbTSPublicKey )
{
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
dwStatus = LsCsp_GetServerData(
LsCspInfo_PublicKey,
pbTSPublicKey,
&cbTSPublicKey
);
if( LICENSE_STATUS_OK != dwStatus )
{
MYASSERT(FALSE);
goto CLEANUPANDEXIT;
}
}
if( ERROR_SUCCESS == dwStatus )
{
dwStatus = HashSecurityData(
pbTSPublicKey,
cbTSPublicKey,
g_TSSecurityBlob
);
MYASSERT( ERROR_SUCCESS == dwStatus );
MYASSERT( g_TSSecurityBlob.Length() > 0 );
DebugPrintf(
_TEXT("HashSecurityData() returns %d\n"), dwStatus
);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
}
//
// SRV, ADS, ... SKU uses seperate thread
// to register with license server, so we use
// different thread to receive certificate change notification.
// Since TermSrv cached certificate, no reason to queue
// notification once we successfully loaded tersrmv public key
//
if( !IsPersonalOrProMachine() && FALSE == bUsesX509PublicKey )
{
DebugPrintf(
_TEXT("Setting up registry notification...\n")
);
MYASSERT( NULL != g_hTSCertificateChanged );
ResetEvent(g_hTSCertificateChanged);
// register a registry change notification
// RegNotifyChangeKeyValue() only signal once.
dwStatus = RegNotifyChangeKeyValue(
g_hTSCertificateRegKey,
TRUE,
REG_NOTIFY_CHANGE_LAST_SET,
g_hTSCertificateChanged,
TRUE
);
if( ERROR_SUCCESS != dwStatus )
{
MYASSERT(FALSE);
DebugPrintf(
_TEXT("RegNotifyChangeKeyValue() returns %d\n"), dwStatus
);
goto CLEANUPANDEXIT;
}
if( NULL != g_hWaitTSCertificateChanged )
{
if( FALSE == UnregisterWait( g_hWaitTSCertificateChanged ) )
{
dwStatus = GetLastError();
DebugPrintf(
_TEXT("UnregisterWait() returns %d\n"),
dwStatus
);
MYASSERT(FALSE);
}
g_hWaitTSCertificateChanged = NULL;
}
//
// Queue notification to threadpool, we need to use WT_EXECUTEONLYONCE
// since we are registering manual reset event.
//
bSuccess = RegisterWaitForSingleObject(
&g_hWaitTSCertificateChanged,
g_hTSCertificateChanged,
(WAITORTIMERCALLBACK) TSCertChangeCallback,
NULL,
INFINITE,
WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE
);
if( FALSE == bSuccess )
{
dwStatus = GetLastError();
DebugPrintf(
_TEXT("RegisterWaitForSingleObject() returns %d\n"), dwStatus
);
}
}
CLEANUPANDEXIT:
if( ERROR_SUCCESS != dwStatus )
{
//
// TS either update its public key or key has change
// and we failed to reload it, there is no reason to
// to continue create help ticket since public key already
/// mismatached, set service status and log error event
//
g_TSSecurityBlob.Empty();
}
if( NULL != pbTSPublicKey )
{
LocalFree(pbTSPublicKey);
}
return HRESULT_FROM_WIN32( dwStatus );
}
DWORD
LoadAndSetupTSCertChangeNotification()
{
DWORD dwStatus;
DWORD dwDisp;
BOOL bSuccess;
//
// Only setup registry change notification if we
// runs on higher SKU
//
g_hTSCertificateChanged = CreateEvent( NULL, TRUE, FALSE, NULL );
if( NULL == g_hTSCertificateChanged )
{
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
//
// Open parameters key under TermServices if key isn't
// there, create it, this does not interfere with TermSrv
// since we only create the reg. key not updating values
// under it.
//
dwStatus = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
REGKEY_TSX509_CERT ,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE | KEY_READ,
NULL,
&g_hTSCertificateRegKey,
&dwDisp
);
if( ERROR_SUCCESS != dwStatus )
{
MYASSERT(FALSE);
DebugPrintf(
_TEXT("RegCreateKeyEx on %s failed with 0x%08x\n"),
REGKEY_TSX509_CERT,
dwStatus
);
goto CLEANUPANDEXIT;
}
//
// Load security blob from TS, currently, we use TS public key
// as security blob
//
dwStatus = LoadTermSrvSecurityBlob();
if( ERROR_SUCCESS != dwStatus )
{
MYASSERT(FALSE);
}
CLEANUPANDEXIT:
return dwStatus;
}
LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
{
while (p1 != NULL && *p1 != NULL)
{
LPCTSTR p = p2;
while (p != NULL && *p != NULL)
{
if (*p1 == *p)
return CharNext(p1);
p = CharNext(p);
}
p1 = CharNext(p1);
}
return NULL;
}
void
LogSetup(
IN FILE* pfd,
IN LPCTSTR format, ...
)
/*++
Routine Description:
sprintf() like wrapper around OutputDebugString().
Parameters:
hConsole : Handle to console.
format : format string.
Returns:
None.
Note:
To be replace by generic tracing code.
++*/
{
TCHAR buf[8096]; // max. error text
DWORD dump;
va_list marker;
va_start(marker, format);
try {
_vsntprintf(
buf,
sizeof(buf)/sizeof(buf[0])-1,
format,
marker
);
if( NULL == pfd )
{
OutputDebugString(buf);
}
else
{
_fputts( buf, pfd );
fflush( pfd );
}
}
catch(...) {
}
va_end(marker);
return;
}
DWORD WINAPI
NotifySessionLogoff(
LPARAM pParm
)
/*++
Routine Description:
Routine to notified all currently loaded help that a user has
logoff/disconnect from session, routine is kick off via thread pools'
QueueUserWorkItem().
Parameters:
pContext : logoff or disconnected Session ID
Returns:
None.
Note :
We treat disconnect same as logoff since user might be actually
active on the other session logged in with same credential, so
we rely on resolver.
--*/
{
DebugPrintf(_TEXT("NotifySessionLogoff() started...\n"));
//
// Tell service don't shutdown, we are in process.
//
_Module.AddRef();
CRemoteDesktopHelpSessionMgr::NotifyHelpSesionLogoff( pParm );
_Module.Release();
return ERROR_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////
void
AddAccountToFilterList(
LPCTSTR lpszAccountName
)
/*++
Routine Description:
Add HelpAssistant account into account filter list, this is temporary
until we have long term solution.
Parameters:
lpszAccountName : Name of HelpAssistant account.
Returns:
None.
Note:
Account filter list is on
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList
<name of SALEM account> REG_DWORD 0x00000000
--*/
{
HKEY hKey = NULL;
DWORD dwStatus;
DWORD dwValue = 0;
dwStatus = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
_TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\SpecialAccounts\\UserList"),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL
);
if( ERROR_SUCCESS == dwStatus )
{
dwStatus = RegSetValueEx(
hKey,
lpszAccountName,
0,
REG_DWORD,
(LPBYTE) &dwValue,
sizeof(DWORD)
);
}
//MYASSERT( ERROR_SUCCESS == dwStatus );
if( NULL != hKey )
{
RegCloseKey( hKey );
}
return;
}
void
CServiceModule::LogSessmgrEventLog(
DWORD dwEventType,
DWORD dwEventCode,
CComBSTR& bstrNoviceDomain,
CComBSTR& bstrNoviceAccount,
CComBSTR& bstrRaType,
CComBSTR& bstrExpertIPFromClient,
CComBSTR& bstrExpertIPFromTS,
DWORD dwErrCode
)
/*++
Description:
Log a Salem specific event log, this includes all event log in sessmgr.
Parameters:
dwEventCode : Event code.
bstrNoviceDomain : Ticket owner's domain name.
bstrNoviceAccount : Ticket owner's user account name.
bstrExpertIPFromClient : Expert's IP address send from mstacax.
bstrExpertIPFromTS : Expert IP address we query from TermSrv.
dwErrCode : Error code.
Returns:
None.
Note:
Max. sessmgr specific log require at most 5 parameters but must
contain novice domain, account name and also expert IP address
send to mstscax and expert IP address we query from TermSrv.
--*/
{
TCHAR szErrCode[256];
LPCTSTR eventString[6];
_stprintf( szErrCode, L"0x%x", dwErrCode );
eventString[0] = (LPCTSTR)bstrNoviceDomain;
eventString[1] = (LPCTSTR)bstrNoviceAccount;
eventString[2] = (LPCTSTR)bstrRaType;
eventString[3] = (LPCTSTR)bstrExpertIPFromClient;
eventString[4] = (LPCTSTR)bstrExpertIPFromTS;
eventString[5] = szErrCode;
LogEventString(
dwEventType,
dwEventCode,
sizeof(eventString)/sizeof(eventString[0]),
eventString,
sizeof(dwErrCode),
&dwErrCode
);
return;
}
/////////////////////////////////////////////////////////////////////////////
void
CServiceModule::LogEventWithStatusCode(
IN DWORD dwEventType,
IN DWORD dwEventId,
IN DWORD dwErrorCode
)
/*++
--*/
{
TCHAR szErrCode[256];
LPCTSTR eventString[1];
eventString[0] = szErrCode;
_stprintf( szErrCode, L"0x%x", dwErrorCode );
LogEventString(
dwEventType,
dwEventId,
1,
eventString
);
return;
}
/////////////////////////////////////////////////////////////////////////////
void
CServiceModule::LogInfoEvent(
IN DWORD code
)
/*++
--*/
{
LogEventString(
EVENTLOG_INFORMATION_TYPE,
code,
0,
NULL
);
}
/////////////////////////////////////////////////////////////////////////////
void
CServiceModule::LogWarningEvent(
IN DWORD code
)
/*++
--*/
{
LogEventString(
EVENTLOG_WARNING_TYPE,
code,
0,
NULL
);
}
/////////////////////////////////////////////////////////////////////////////
void
CServiceModule::LogErrorEvent(
IN DWORD errCode
)
/*++
--*/
{
LogEventString(
EVENTLOG_ERROR_TYPE,
errCode,
0,
NULL
);
}
/////////////////////////////////////////////////////////////////////////////
void
CServiceModule::LogEventString(
IN DWORD dwEventType,
IN DWORD dwEventId,
IN DWORD wNumString,
IN LPCTSTR* lpStrings,
DWORD dwBinaryDataSize, /* 0 */
LPVOID lpRawData /* NULL */
)
/*++
--*/
{
HANDLE hAppLog=NULL;
BOOL bSuccess=FALSE;
WORD wElogType = (WORD) dwEventType;
try {
if(hAppLog=RegisterEventSource(NULL, m_szServiceDispName))
{
bSuccess = ReportEvent(
hAppLog,
wElogType,
0,
dwEventId,
NULL,
(WORD)wNumString,
dwBinaryDataSize,
(const TCHAR **) lpStrings,
lpRawData
);
DeregisterEventSource(hAppLog);
}
}
catch(...) {
}
return;
}
inline HRESULT
CServiceModule::SetupEventViewerSource(
IN FILE* pSetupLog
)
/*++
--*/
{
HKEY hKey = NULL;
DWORD dwData;
TCHAR szBuffer[MAX_PATH + 2];
DWORD dwStatus;
LogSetup( pSetupLog, L"Entering SetupEventViewerSource()...\n" );
_stprintf(
szBuffer,
_TEXT("%s\\%s"),
REGKEY_SYSTEM_EVENTSOURCE,
m_szServiceDispName
);
// Add your source name as a subkey under the Application
// key in the EventLog registry key.
dwStatus = RegCreateKey(
HKEY_LOCAL_MACHINE,
szBuffer,
&hKey
);
if( ERROR_SUCCESS != dwStatus )
{
LogSetup(
pSetupLog,
L"RegCreateKey() fail to create key %s with %d\n",
szBuffer,
dwStatus
);
goto CLEANUPANDEXIT;
}
dwStatus = GetModuleFileName(
NULL,
szBuffer,
MAX_PATH+1
);
if( 0 == dwStatus )
{
LogSetup(
pSetupLog,
L"GetModuleFileName() failed with error code %s\n",
dwStatus = GetLastError()
);
goto CLEANUPANDEXIT;
}
// Add the name to the EventMessageFile subkey.
dwStatus = RegSetValueEx(
hKey,
L"EventMessageFile",
0,
REG_SZ,
(LPBYTE) szBuffer,
(_tcslen(szBuffer)+1)*sizeof(TCHAR)
);
if( ERROR_SUCCESS != dwStatus )
{
LogSetup(
pSetupLog,
L"Failed to create EventMessageFile value, error code %d\n",
dwStatus
);
goto CLEANUPANDEXIT;
}
// Set the supported event types in the TypesSupported subkey.
dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
dwStatus = RegSetValueEx(
hKey,
L"TypesSupported",
0,
REG_DWORD,
(LPBYTE) &dwData,
sizeof(DWORD)
);
if( ERROR_SUCCESS != dwStatus )
{
LogSetup(
pSetupLog,
L"Failed to create TypesSupported value, error code %d\n",
dwStatus
);
}
CLEANUPANDEXIT:
if( NULL != hKey )
{
RegCloseKey(hKey);
}
LogSetup(
pSetupLog,
L"Exiting SetupEventViewerSource() with status code %d...\n",
dwStatus
);
return HRESULT_FROM_WIN32(dwStatus);
}
// Although some of these functions are big they are declared inline since they are only used once
inline HRESULT
CServiceModule::RegisterServer(FILE* pSetupLog, BOOL bRegTypeLib, BOOL bService)
{
CRegKey key;
HRESULT hr;
CRegKey keyAppID;
LONG lRes;
LogSetup(
pSetupLog,
L"\nEntering CServiceModule::RegisterServer %d, %d\n",
bRegTypeLib,
bService
);
hr = CoInitialize(NULL);
if (FAILED(hr))
{
LogSetup( pSetupLog, L"CoInitialize() failed with 0x%08x\n", hr );
goto CLEANUPANDEXIT;
}
// Remove any previous service since it may point to
// the incorrect file
//Uninstall();
// Add service entries
UpdateRegistryFromResource(IDR_Sessmgr, TRUE);
// Adjust the AppID for Local Server or Service
lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE);
if (lRes != ERROR_SUCCESS)
{
LogSetup( pSetupLog, L"Open key AppID failed with %d\n", lRes );
hr = HRESULT_FROM_WIN32(lRes);
goto CLEANUPANDEXIT;
}
lRes = key.Open(keyAppID, _T("{038ABBA4-4138-4AC4-A492-4A3DF068BD8A}"), KEY_WRITE);
if (lRes != ERROR_SUCCESS)
{
LogSetup( pSetupLog, L"Open key 038ABBA4-4138-4AC4-A492-4A3DF068BD8A failed with %d\n", lRes );
hr = HRESULT_FROM_WIN32(lRes);
goto CLEANUPANDEXIT;
}
key.DeleteValue(_T("LocalService"));
if (bService)
{
LogSetup( pSetupLog, L"Installing service...\n" );
BOOL bInstallSuccess;
key.SetValue(m_szServiceName, _T("LocalService"));
key.SetValue(_T("-Service"), _T("ServiceParameters"));
if( IsInstalled(pSetupLog) )
{
// update service description.
bInstallSuccess = UpdateService( pSetupLog );
}
else
{
//
// Create service
//
bInstallSuccess = Install(pSetupLog);
}
if( FALSE == bInstallSuccess )
{
LogSetup( pSetupLog, L"Install or update service description failed %d\n", GetLastError() );
MYASSERT( FALSE );
hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
}
else
{
LogSetup( pSetupLog, L"successfully installing service...\n" );
if( IsInstalled(pSetupLog) == FALSE )
{
LogSetup( pSetupLog, L"IsInstalled() return FALSE after Install()\n" );
MYASSERT(FALSE);
hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
}
SetupEventViewerSource(pSetupLog);
}
}
if( SUCCEEDED(hr) )
{
// Add object entries
hr = CComModule::RegisterServer(bRegTypeLib);
if( FAILED(hr) )
{
LogSetup( pSetupLog, L"CComModule::RegisterServer() on type library failed with 0x%08x\n", hr );
}
}
CoUninitialize();
CLEANUPANDEXIT:
LogSetup( pSetupLog, L"Leaving CServiceModule::RegisterServer 0x%08x\n", hr );
return hr;
}
inline HRESULT CServiceModule::UnregisterServer(FILE* pSetupLog)
{
LogSetup( pSetupLog, L"\nEntering CServiceModule::UnregisterServer\n" );
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
LogSetup( pSetupLog, L"CoInitialize() failed with 0x%08x\n", hr );
goto CLEANUPANDEXIT;
}
// Remove service entries
UpdateRegistryFromResource(IDR_Sessmgr, FALSE);
// Remove service
Uninstall(pSetupLog);
// Remove object entries
CComModule::UnregisterServer(TRUE);
CoUninitialize();
CLEANUPANDEXIT:
LogSetup( pSetupLog, L"Leaving CServiceModule::UnregisterServer() - 0x%08x\n", hr );
return S_OK;
}
inline void
CServiceModule::Init(
_ATL_OBJMAP_ENTRY* p,
HINSTANCE h,
UINT nServiceNameID,
UINT nServiceDispNameID,
UINT nServiceDescID,
const GUID* plibid
)
/*++
ATL Wizard generated code
--*/
{
CComModule::Init(p, h, plibid);
m_bService = TRUE;
m_dwServiceStartupStatus = ERROR_SUCCESS;
LoadString(h, nServiceNameID, m_szServiceName, sizeof(m_szServiceName) / sizeof(TCHAR));
LoadString(h, nServiceDescID, m_szServiceDesc, sizeof(m_szServiceDesc) / sizeof(TCHAR));
LoadString(h, nServiceDispNameID, m_szServiceDispName, sizeof(m_szServiceDispName)/sizeof(TCHAR));
// set up the initial service status
m_hServiceStatus = NULL;
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_status.dwCurrentState = SERVICE_STOPPED;
m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SESSIONCHANGE;
m_status.dwWin32ExitCode = 0;
m_status.dwServiceSpecificExitCode = 0;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = 0;
}
LONG CServiceModule::Unlock()
{
LONG l = CComModule::Unlock();
if (l == 0 && !m_bService)
PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
return l;
}
BOOL CServiceModule::IsInstalled(FILE* pSetupLog)
{
LogSetup( pSetupLog, L"\nEntering CServiceModule::IsInstalled()\n" );
BOOL bResult = FALSE;
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM != NULL)
{
SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_QUERY_CONFIG);
if (hService != NULL)
{
LogSetup( pSetupLog, L"OpenService() Succeeded\n" );
bResult = TRUE;
::CloseServiceHandle(hService);
}
else
{
LogSetup( pSetupLog, L"OpenService() failed with %d\n", GetLastError() );
}
::CloseServiceHandle(hSCM);
}
else
{
LogSetup( pSetupLog, L"OpenSCManager() failed with %d\n", GetLastError() );
}
LogSetup( pSetupLog, L"Leaving IsInstalled() - %d\n", bResult );
return bResult;
}
inline BOOL CServiceModule::UpdateService(FILE* pSetupLog)
{
DWORD dwStatus = ERROR_SUCCESS;
SERVICE_DESCRIPTION serviceDesc;
SC_HANDLE hSCM = NULL;
SC_HANDLE hService = NULL;
LogSetup( pSetupLog, L"\nEntering CServiceModule::UpdateServiceDescription()...\n" );
hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"OpenSCManager() failed with %d\n", dwStatus );
goto CLEANUPANDEXIT;
}
hService = ::OpenService( hSCM, m_szServiceName, SERVICE_CHANGE_CONFIG );
if (hService == NULL)
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"OpenService() failed with %d\n", dwStatus );
goto CLEANUPANDEXIT;
}
serviceDesc.lpDescription = (LPTSTR)m_szServiceDesc;
if( FALSE == ChangeServiceConfig2( hService, SERVICE_CONFIG_DESCRIPTION, (LPVOID)&serviceDesc ) )
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"ChangeServiceConfig2() failed with %d\n", dwStatus );
MYASSERT( ERROR_SUCCESS == dwStatus );
}
//
// Performance : Set service to be demand start for upgrade
//
if( FALSE == ChangeServiceConfig(
hService,
SERVICE_NO_CHANGE,
SERVICE_DEMAND_START,
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
m_szServiceDispName
) )
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"ChangeServiceConfig() failed with %d\n", dwStatus );
MYASSERT( ERROR_SUCCESS == dwStatus );
}
CLEANUPANDEXIT:
if( NULL != hService )
{
::CloseServiceHandle(hService);
}
if( NULL != hSCM )
{
::CloseServiceHandle(hSCM);
}
LogSetup( pSetupLog, L"Leaving UpdateServiceDescription::Install() - %d\n", dwStatus );
return dwStatus == ERROR_SUCCESS;
}
inline BOOL CServiceModule::Install(FILE* pSetupLog)
{
DWORD dwStatus = ERROR_SUCCESS;
SERVICE_DESCRIPTION serviceDesc;
SC_HANDLE hSCM;
TCHAR szFilePath[_MAX_PATH];
SC_HANDLE hService;
LogSetup( pSetupLog, L"\nEntering CServiceModule::Install()...\n" );
if (IsInstalled(pSetupLog))
{
LogSetup( pSetupLog, L"Service already installed\n" );
dwStatus = ERROR_SUCCESS;
goto CLEANUPANDEXIT;
}
hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"OpenSCManager() failed with %d\n", dwStatus );
goto CLEANUPANDEXIT;
}
// Get the executable file path
::GetModuleFileName(NULL, szFilePath, _MAX_PATH);
hService = ::CreateService(
hSCM,
m_szServiceName,
m_szServiceDispName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
szFilePath,
NULL,
NULL,
_T("RPCSS\0"),
NULL,
NULL
);
if (hService == NULL)
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"CreateService() failed with %d\n", dwStatus );
::CloseServiceHandle(hSCM);
goto CLEANUPANDEXIT;
}
serviceDesc.lpDescription = (LPTSTR)m_szServiceDesc;
if( FALSE == ChangeServiceConfig2( hService, SERVICE_CONFIG_DESCRIPTION, (LPVOID)&serviceDesc ) )
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"ChangeServiceConfig2() failed with %d\n", dwStatus );
MYASSERT( ERROR_SUCCESS == dwStatus );
}
::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);
CLEANUPANDEXIT:
LogSetup( pSetupLog, L"Leaving CServiceModule::Install() - %d\n", dwStatus );
return dwStatus == ERROR_SUCCESS;
}
inline BOOL CServiceModule::Uninstall(FILE* pSetupLog)
{
BOOL bStatus = TRUE;
SC_HANDLE hService;
SC_HANDLE hSCM;
SERVICE_STATUS status;
LogSetup( pSetupLog, L"\nEntering CServiceModule::Uninstall()...\n" );
if (!IsInstalled(pSetupLog))
{
LogSetup( pSetupLog, L"Service is not installed...\n" );
goto CLEANUPANDEXIT;
}
hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
LogSetup( pSetupLog, L"OpenSCManager() failed with %d\n", GetLastError() );
bStatus = FALSE;
goto CLEANUPANDEXIT;
}
hService = ::OpenService(hSCM, m_szServiceName, SERVICE_STOP | DELETE);
if (hService == NULL)
{
::CloseServiceHandle(hSCM);
LogSetup( pSetupLog, L"OpenService() failed with %d\n", GetLastError() );
bStatus = FALSE;
goto CLEANUPANDEXIT;
}
::ControlService(hService, SERVICE_CONTROL_STOP, &status);
bStatus = ::DeleteService(hService);
if( FALSE == bStatus )
{
LogSetup( pSetupLog, L"DeleteService() failed with %d\n", GetLastError() );
}
::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);
CLEANUPANDEXIT:
LogSetup( pSetupLog, L"Leaving CServiceModule::Uninstall()\n" );
return bStatus;
}
//////////////////////////////////////////////////////////////////////////////////////////////
// Service startup and registration
inline void CServiceModule::Start()
{
SERVICE_TABLE_ENTRY st[] =
{
{ m_szServiceName, _ServiceMain },
{ NULL, NULL }
};
if (m_bService && !::StartServiceCtrlDispatcher(st))
{
m_bService = FALSE;
}
if (m_bService == FALSE)
Run();
}
inline void CServiceModule::ServiceMain(DWORD /* dwArgc */, LPTSTR* /* lpszArgv */)
{
// Register the control request handler
m_status.dwCurrentState = SERVICE_START_PENDING;
m_hServiceStatus = RegisterServiceCtrlHandlerEx(m_szServiceName, HandlerEx, this);
if (m_hServiceStatus == NULL)
{
//LogEvent(_T("Handler not installed"));
return;
}
m_status.dwWin32ExitCode = S_OK;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = SERVICE_STARTUP_WAITHINT;
SetServiceStatus(SERVICE_START_PENDING);
// When the Run function returns, the service has stopped.
Run();
SetServiceStatus(SERVICE_STOPPED);
}
inline void CServiceModule::Handler(DWORD dwOpcode)
{
switch (dwOpcode)
{
case SERVICE_CONTROL_STOP:
SetServiceStatus(SERVICE_STOP_PENDING);
if( PostThreadMessage(dwThreadID, WM_QUIT, 0, 0) == FALSE )
{
DWORD dwStatus = GetLastError();
}
break;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
break;
//default:
// LogEvent(_T("Bad service request"));
}
}
inline DWORD WINAPI
CServiceModule::HandlerEx(
DWORD dwControl,
DWORD dwEventType,
LPVOID lpEventData,
LPVOID lpContext
)
/*++
--*/
{
DWORD dwRetCode;
switch (dwControl)
{
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_PAUSE:
case SERVICE_CONTROL_CONTINUE:
case SERVICE_CONTROL_INTERROGATE:
case SERVICE_CONTROL_SHUTDOWN:
dwRetCode = NO_ERROR;
_Handler(dwControl);
break;
#if DISABLESECURITYCHECKS
// this is require for Salem Unit test, we need to update
// user session status but for pcHealth, resolver will
// always popup invitation dialog so no need to track
// user session status.
case SERVICE_CONTROL_SESSIONCHANGE:
MYASSERT( NULL != lpEventData );
if( NULL != lpEventData )
{
switch( dwEventType )
{
case WTS_SESSION_LOGON:
DebugPrintf(
_TEXT("Session %d has log on...\n"),
((WTSSESSION_NOTIFICATION *)lpEventData)->dwSessionId
);
break;
case WTS_SESSION_LOGOFF:
case WTS_CONSOLE_DISCONNECT:
case WTS_REMOTE_DISCONNECT:
DebugPrintf(
_TEXT("Session %d has log off...\n"),
((WTSSESSION_NOTIFICATION *)lpEventData)->dwSessionId
);
//
// Deadlock if we use other thread to process logoff or
// disconnect.
//
// Notification thread lock pending help table and need
// to run Resolver in COM, COM is in the middle of
// dispatching create help ticket call which also need
// lock to pending help table, this causes deadlock
//
PostThreadMessage(
_Module.dwThreadID,
WM_SESSIONLOGOFFDISCONNECT,
0,
(LPARAM)((WTSSESSION_NOTIFICATION *)lpEventData)->dwSessionId
);
}
}
dwRetCode = NO_ERROR;
break;
#endif
default:
dwRetCode = ERROR_CALL_NOT_IMPLEMENTED;
}
return dwRetCode;
}
void WINAPI CServiceModule::_ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
{
_Module.ServiceMain(dwArgc, lpszArgv);
}
void WINAPI CServiceModule::_Handler(DWORD dwOpcode)
{
_Module.Handler(dwOpcode);
}
void CServiceModule::SetServiceStatus(DWORD dwState)
{
m_status.dwCurrentState = dwState;
::SetServiceStatus(m_hServiceStatus, &m_status);
}
HANDLE CServiceModule::gm_hIdle = NULL;
HANDLE CServiceModule::gm_hIdleMonitorThread = NULL;
HANDLE CServiceModule::gm_hICSAlertEvent = NULL;
unsigned __stdcall
StartupInitThread( void* ptr )
{
HRESULT hRes = S_OK;
DWORD dwErrCode = ERROR_SUCCESS;
hRes = g_HelpSessTable.OpenSessionTable(NULL);
if( SUCCEEDED(hRes) )
{
CRemoteDesktopHelpSessionMgr::NotifyPendingHelpServiceStartup();
}
else
{
dwErrCode = SESSMGR_E_HELPSESSIONTABLE;
}
if( FAILED(hRes) )
{
_Module.LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
dwErrCode,
hRes
);
hRes = dwErrCode;
}
_endthreadex( hRes );
return hRes;
}
ULONG
CServiceModule::AddRef()
{
CCriticalSectionLocker l( m_Locks );
m_RefCount++;
if( m_RefCount > 0 )
{
ResetEvent( gm_hIdle );
}
return m_RefCount;
}
ULONG
CServiceModule::Release()
{
CCriticalSectionLocker l( m_Locks );
m_RefCount--;
if( m_RefCount <= 0 )
{
// Only signal idle when there is no more pending help
if( g_HelpSessTable.NumEntries() == 0 )
{
SetEvent( gm_hIdle );
}
}
return m_RefCount;
}
unsigned int WINAPI
CServiceModule::IdleMonitorThread( void* ptr )
{
DWORD dwStatus = ERROR_SUCCESS;
CServiceModule* pServiceModule = (CServiceModule *)ptr;
HANDLE hWaitHandles[] = {gm_hICSAlertEvent, gm_hIdle};
CoInitialize(NULL);
if( pServiceModule != NULL )
{
while (TRUE)
{
dwStatus = WaitForMultipleObjects(
sizeof( hWaitHandles ) / sizeof( hWaitHandles[0] ),
hWaitHandles,
FALSE,
EXPIRE_HELPSESSION_PERIOD
);
if( WAIT_TIMEOUT == dwStatus )
{
// expire help ticket, refer to session logoff/disconnect
// comment above on why PostThreadMessage.
PostThreadMessage(
_Module.dwThreadID,
WM_EXPIREHELPSESSION,
0,
0
);
}
else if( WAIT_OBJECT_0 == dwStatus )
{
// ICS has signal us something has changed.
ResetEvent( gm_hICSAlertEvent );
}
else if( WAIT_OBJECT_0 + 1 == dwStatus )
{
// we have been idel for too long, time to try shutdown.
// idle event will only be signal when there is no
// pending help so we don't have to worry about address
// changes.
Sleep( IDLE_SHUTDOWN_PERIOD );
dwStatus = WaitForSingleObject( gm_hIdle, 0 );
if( WAIT_OBJECT_0 == dwStatus )
{
// no one holding object, time to shutdown
dwStatus = ERROR_SUCCESS;
break;
}
}
else if( WAIT_FAILED == dwStatus )
{
// some bad thing happen, shutdown.
//MYASSERT(FALSE);
break;
}
}
}
// TOBE enable with ICS work
//pServiceModule->LogInfoEvent( SESSMGR_I_SERVICE_IDLESTOP );
pServiceModule->Handler(SERVICE_CONTROL_STOP);
CoUninitialize();
_endthreadex( dwStatus );
return dwStatus;
}
BOOL
CServiceModule::InitializeSessmgr()
{
CCriticalSectionLocker l( m_Locks );
//
// Already initialize.
//
if( m_Initialized )
{
return TRUE;
}
//
// Service failed to startup, just return without initialize
// anything
//
if( !_Module.IsSuccessServiceStartup() )
{
return FALSE;
}
DWORD dwStatus;
unsigned int junk;
//
// Start ICSHELPER library.
//
dwStatus = StartICSLib();
if( ERROR_SUCCESS != dwStatus )
{
// Log an error event, we still need to startup
// so that we can report error back to caller
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_ICSHELPER,
dwStatus
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_ICSHELPER;
}
else
{
CRemoteDesktopHelpSessionMgr::NotifyPendingHelpServiceStartup();
}
m_Initialized = TRUE;
return _Module.IsSuccessServiceStartup();
}
void CServiceModule::Run()
{
//
// Mark we are not initialized yet...
//
m_Initialized = FALSE;
_Module.dwThreadID = GetCurrentThreadId();
DWORD dwStatus;
unsigned int dwJunk;
WSADATA wsData;
ISAFRemoteDesktopCallback* pIResolver = NULL;
LPWSTR pszSysAccName = NULL;
DWORD cbSysAccName = 0;
LPWSTR pszSysDomainName = NULL;
DWORD cbSysDomainName = 0;
SID_NAME_USE SidType;
HRESULT hr;
//
// **** DO NOT CHANGE SEQUENCE ****
//
// Refer to XP RAID 407457 for detail
//
// A thread named SessMgr!DpNatHlpThread is calling into dpnhupnp.dll,
// which is doing COM-related stuff, this is happening before the
// sessmgr!CServiceModule__Run method calls CoInitializeSecurity.
// When you do COM stuff before calling CoInitSec, COM do it for you,
// and you end up accepting the defaults
//
hr = g_HelpAccount.Initialize();
if( FAILED(hr) )
{
dwStatus = SESSMGR_E_HELPACCOUNT;
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_GENERALSTARTUP,
hr
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_HELPACCOUNT;
MYASSERT(FALSE);
}
hr = LoadLocalSystemSID();
if( FAILED(hr) )
{
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_GENERALSTARTUP,
hr
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
MYASSERT(FALSE);
}
//
// We always need to startup otherwise will cause caller to timeout
// or AV.
//
hr = CoInitialize(NULL);
// If you are running on NT 4.0 or higher you can use the following call
// instead to make the EXE free threaded.
// This means that calls come in on a random RPC thread
// HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
_ASSERTE(SUCCEEDED(hr));
CSecurityDescriptor sd;
sd.InitializeFromThreadToken(); // get a default DACL
#ifndef DISABLESECURITYCHECKS
if( _Module.IsSuccessServiceStartup() )
{
BOOL bSuccess;
CComBSTR bstrHelpAccName;
//
// Retrieve System account name, might not be necessary since this
// pre-defined account shouldn't be localizable.
//
pszSysAccName = NULL;
cbSysAccName = 0;
pszSysDomainName = NULL;
cbSysDomainName = 0;
bSuccess = LookupAccountSid(
NULL,
g_pSidSystem,
pszSysAccName,
&cbSysAccName,
pszSysDomainName,
&cbSysDomainName,
&SidType
);
if( TRUE == bSuccess ||
ERROR_INSUFFICIENT_BUFFER == GetLastError() )
{
pszSysAccName = (LPWSTR) LocalAlloc( LPTR, (cbSysAccName + 1) * sizeof(WCHAR) );
pszSysDomainName = (LPWSTR) LocalAlloc( LPTR, (cbSysDomainName + 1) * sizeof(WCHAR) );
if( NULL != pszSysAccName && NULL != pszSysDomainName )
{
bSuccess = LookupAccountSid(
NULL,
g_pSidSystem,
pszSysAccName,
&cbSysAccName,
pszSysDomainName,
&cbSysDomainName,
&SidType
);
if( TRUE == bSuccess )
{
hr = sd.Allow( pszSysAccName, COM_RIGHTS_EXECUTE );
}
}
}
if( FALSE == bSuccess )
{
dwStatus = GetLastError();
hr = HRESULT_FROM_WIN32( dwStatus );
MYASSERT( SUCCEEDED(hr) );
}
//
// Add access permission to help assistant account
if( SUCCEEDED(hr) )
{
//
// Allow access to HelpAssistant account
//
hr = g_HelpAccount.GetHelpAccountNameEx( bstrHelpAccName );
if( SUCCEEDED(hr) )
{
hr = sd.Allow( (LPCTSTR)bstrHelpAccName, COM_RIGHTS_EXECUTE );
MYASSERT( SUCCEEDED(hr) );
}
}
//
// If we failed in setting DACL, we still need to startup but without
// full security, however, our interface will fail because service
// does not initialize correctly.
//
if( FAILED(hr) )
{
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_RESTRICTACCESS,
hr
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_RESTRICTACCESS;
}
}
#endif
//
// We still need to startup or client might behave weird; interface call
// will be block by checking service startup status.
//
hr = CoInitializeSecurity(
sd,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
_ASSERTE(SUCCEEDED(hr));
hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
_ASSERTE(SUCCEEDED(hr));
//
// Load unknown string for event loggging
//
g_UnknownString.LoadString( IDS_UNKNOWN );
//
// Load RA and URA string for event log
//
g_RAString.LoadString( IDS_RA_STRING );
g_URAString.LoadString( IDS_URA_STRING );
if( _Module.IsSuccessServiceStartup() )
{
//
// Startup TLSAPI in order to get public key
//
dwStatus = TLSInit();
if( LICENSE_STATUS_OK != dwStatus )
{
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_GENERALSTARTUP,
dwStatus
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
MYASSERT(FALSE);
}
}
if( _Module.IsSuccessServiceStartup() )
{
//
// Load TermSrv public key, on PRO/PER we load public key from
// non-x509 certificate, on other SKU, we register a registry change
// notification and post ourself a message regarding public key
// change.
//
dwStatus = LoadAndSetupTSCertChangeNotification();
MYASSERT( ERROR_SUCCESS == dwStatus );
if( ERROR_SUCCESS != dwStatus )
{
// Log an error event, we still need to startup
// so that we can report error back to caller
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_GENERALSTARTUP,
dwStatus
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
}
}
if( _Module.IsSuccessServiceStartup() )
{
//
// Create an event for ICS to signal us
// any address change
//
gm_hICSAlertEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
);
if( NULL == gm_hICSAlertEvent )
{
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_GENERALSTARTUP,
GetLastError()
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
MYASSERT(FALSE);
}
}
if( _Module.IsSuccessServiceStartup() )
{
//
// Initialize encryption library
//
dwStatus = TSHelpAssistantInitializeEncryptionLib();
if( ERROR_SUCCESS != dwStatus )
{
// Log an error event, we still need to startup
// so that we can report error back to caller
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_INIT_ENCRYPTIONLIB,
dwStatus
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_INIT_ENCRYPTIONLIB;
MYASSERT(FALSE);
}
}
if( _Module.IsSuccessServiceStartup() )
{
//
// startup WSA so we can invoke gethostname()
// critical error if we can startup WSA
if( WSAStartup(0x0101, &wsData) != 0 )
{
// Log an error event, we still need to startup
// so that we can report error back to caller
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_WSASTARTUP,
GetLastError()
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_WSASTARTUP;
}
}
if( _Module.IsSuccessServiceStartup() )
{
hr = g_HelpSessTable.OpenSessionTable(NULL);
if( FAILED(hr) )
{
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_HELPSESSIONTABLE,
hr
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_HELPSESSIONTABLE;
MYASSERT(FALSE);
}
}
if( _Module.IsSuccessServiceStartup() )
{
//
// Service might startup from system restore, re-setup HelpAssistant account
// settings
if( g_HelpSessTable.NumEntries() == 0)
{
g_HelpAccount.EnableHelpAssistantAccount(FALSE);
g_HelpAccount.EnableRemoteInteractiveRight(FALSE);
}
else
{
//
// make sure HelpAssistant account is enabled and can logon locally
//
g_HelpAccount.EnableHelpAssistantAccount(TRUE);
g_HelpAccount.EnableRemoteInteractiveRight(TRUE);
g_HelpAccount.SetupHelpAccountTSSettings();
}
//
// Create an manual reset event for background thread to terminate
// service
//
gm_hIdle = CreateEvent(
NULL,
TRUE,
(g_HelpSessTable.NumEntries() == 0) ? TRUE : FALSE,
NULL
);
if( NULL == gm_hIdle )
{
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_GENERALSTARTUP,
GetLastError()
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
MYASSERT(FALSE);
}
// Create nackground thread thread
gm_hIdleMonitorThread = (HANDLE)_beginthreadex(
NULL,
0,
IdleMonitorThread,
(HANDLE)this,
0,
&dwJunk
);
if( NULL == gm_hIdleMonitorThread )
{
_Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
}
}
//LogEvent(_T("Service started"));
if (m_bService)
SetServiceStatus(SERVICE_RUNNING);
// TOBE enable with ICS work
//LogInfoEvent(SESSMGR_I_SERVICE_START);
//
// Load resolver, this will put one ref. count on it
// so it won't got unload until we are done.
//
hr = CoCreateInstance(
SESSIONRESOLVERCLSID,
NULL,
CLSCTX_SERVER,
IID_ISAFRemoteDesktopCallback,
(void **)&pIResolver
);
MYASSERT( SUCCEEDED(hr) );
if( FAILED(hr) )
{
//
// Can't initialize session resolver,
// session resolver will not be able to
// do caching.
//
LogEventWithStatusCode(
EVENTLOG_WARNING_TYPE,
SESSMGR_E_SESSIONRESOLVER,
hr
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_SESSIONRESOLVER;
}
else
{
//
// Create global interface table
//
hr = InitializeGlobalInterfaceTable();
if( SUCCEEDED(hr) )
{
//
// register resolver interface with GIT, resolver has some
// data structure that depends on single instance.
//
hr = RegisterResolverWithGIT(pIResolver);
}
if( FAILED(hr) )
{
//
// Not critical, Resolver function is disabled.
LogEventWithStatusCode(
EVENTLOG_WARNING_TYPE,
SESSMGR_E_REGISTERSESSIONRESOLVER,
hr
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_REGISTERSESSIONRESOLVER;
}
}
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
switch( msg.message )
{
case WM_EXPIREHELPSESSION:
DebugPrintf(_TEXT("Executing TimeoutHelpSesion()...\n"));
CRemoteDesktopHelpSessionMgr::TimeoutHelpSesion();
break;
case WM_SESSIONLOGOFFDISCONNECT:
DebugPrintf(_TEXT("Executing NotifySessionLogoff() %d...\n"), msg.lParam);
NotifySessionLogoff( msg.lParam );
break;
case WM_LOADTSPUBLICKEY:
DebugPrintf( _TEXT("Executing LoadTermSrvSecurityBlob() ...\n") );
dwStatus = LoadTermSrvSecurityBlob();
if( ERROR_SUCCESS != dwStatus )
{
// Log an error event, we still need to startup
// so that we can report error back to caller
LogEventWithStatusCode(
EVENTLOG_ERROR_TYPE,
SESSMGR_E_GENERALSTARTUP,
dwStatus
);
_Module.m_dwServiceStartupStatus = SESSMGR_E_GENERALSTARTUP;
}
break;
case WM_HELPERRDSADDINEXIT:
DebugPrintf( _TEXT("WM_HELPERRDSADDINEXIT()...\n") );
CRemoteDesktopHelpSessionMgr::NotifyExpertLogoff( msg.wParam, (BSTR)msg.lParam );
break;
default:
DispatchMessage(&msg);
}
}
CleanupMonitorExpertList();
if( g_hWaitTSCertificateChanged )
{
UnregisterWait( g_hWaitTSCertificateChanged );
g_hWaitTSCertificateChanged = NULL;
}
if( g_hTSCertificateChanged )
{
CloseHandle( g_hTSCertificateChanged );
g_hTSCertificateChanged = NULL;
}
if( g_hTSCertificateRegKey )
{
RegCloseKey( g_hTSCertificateRegKey );
g_hTSCertificateRegKey = NULL;
}
//
//
if( NULL != pIResolver )
{
pIResolver->Release();
}
_Module.RevokeClassObjects();
// TOBE enable with ICS work
//LogInfoEvent(SESSMGR_I_SERVICE_STOP);
CoUninitialize();
if( NULL != gm_hIdle )
{
CloseHandle( gm_hIdle );
}
if( WSACleanup() != 0 )
{
// shutting down, ignore WSA error
#if DBG
OutputDebugString( _TEXT("WSACleanup() failed...\n") );
#endif
}
#if DBG
OutputDebugString( _TEXT("Help Session Manager Exited...\n") );
#endif
// Close the help session table, help session table
// open by init. thread
g_HelpSessTable.CloseSessionTable();
// Stop ICS library, ignore error code.
StopICSLib();
TSHelpAssistantEndEncryptionLib();
UnInitializeGlobalInterfaceTable();
if( NULL != pszSysAccName )
{
LocalFree( pszSysAccName );
}
if( NULL != pszSysDomainName )
{
LocalFree( pszSysDomainName );
}
TLSShutdown();
}
HRESULT
CreatePendingHelpTable(
FILE* pSetupLog
)
/*++
Routine to create pending help table registry key, if registry key already exist,
set the DACL to system context only.
--*/
{
PACL pAcl=NULL;
DWORD dwStatus = ERROR_SUCCESS;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
DWORD cbAcl = 0;
PSID pSidSystem = NULL;
HKEY hKey = NULL;
LogSetup( pSetupLog, L"\nEntering CreatePendingHelpTable\n" );
pSecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, sizeof(SECURITY_DESCRIPTOR));
if( NULL == pSecurityDescriptor )
{
LogSetup( pSetupLog, L"Can't alloc memory for SECURITY_DESCRIPTOR\n" );
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
//
// Initialize the security descriptor.
//
if (!InitializeSecurityDescriptor(
pSecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION
))
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"InitializeSecurityDescriptor() failed with %d\n", dwStatus );
goto CLEANUPANDEXIT;
}
dwStatus = CreateSystemSid( &pSidSystem );
if( ERROR_SUCCESS != dwStatus )
{
LogSetup( pSetupLog, L"CreateSystemSid() failed with %d\n", dwStatus );
goto CLEANUPANDEXIT;
}
cbAcl = GetLengthSid( pSidSystem ) + sizeof(ACL) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
pAcl = (PACL) LocalAlloc( LPTR, cbAcl );
if( NULL == pAcl )
{
LogSetup( pSetupLog, L"Can't alloc memory for ACL\n" );
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
//
// Initialize the ACL.
//
if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION))
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"InitializeAcl() failed with error code %d\n", dwStatus );
goto CLEANUPANDEXIT;
}
//
if (!AddAccessAllowedAce(pAcl,
ACL_REVISION,
GENERIC_READ | GENERIC_WRITE | GENERIC_ALL,
pSidSystem
))
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"AddAccessAllowedAce() failed with error code %d\n", dwStatus );
goto CLEANUPANDEXIT;
}
if (!SetSecurityDescriptorDacl(pSecurityDescriptor,
TRUE, pAcl, FALSE))
{
dwStatus = GetLastError();
LogSetup( pSetupLog, L"SetSecurityDescriptorDacl() failed with error code %d\n", dwStatus );
goto CLEANUPANDEXIT;
}
//
// Create/open the pending table registry key
//
dwStatus = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL
);
if( ERROR_SUCCESS != dwStatus )
{
LogSetup( pSetupLog, L"RegCreateKeyEx() failed with error code %d\n", dwStatus );
goto CLEANUPANDEXIT;
}
//
// Set table (registry) DACL
//
dwStatus = RegSetKeySecurity(
hKey,
DACL_SECURITY_INFORMATION,
pSecurityDescriptor
);
if( ERROR_SUCCESS != dwStatus )
{
LogSetup( pSetupLog, L"RegSetKeySecurity() failed with error code %d\n", dwStatus );
}
CLEANUPANDEXIT:
if( NULL != hKey )
{
RegCloseKey(hKey);
}
if( pAcl != NULL )
{
LocalFree(pAcl);
}
if( pSecurityDescriptor != NULL )
{
LocalFree( pSecurityDescriptor );
}
if( pSidSystem != NULL )
{
FreeSid( pSidSystem );
}
LogSetup( pSetupLog, L"CreatePendingHelpTable() return %d\n", dwStatus );
return HRESULT_FROM_WIN32(dwStatus);
}
void
UpgradeSessmgr(
FILE* pSetupLog
)
/*++
Routine to upgrade session manager
--*/
{
LogSetup( pSetupLog, L"\nEntering UpgradeSessmgr\n" );
//
// Migrate fAllowToGetHelp policy in HKLM\Software\Microsoft\Remote Desktop\Policies
// to termsrv so listening thread can look at single place.
//
DWORD dwValue;
DWORD dwStatus;
DWORD dwSize;
DWORD dwType;
HKEY hKey;
BOOL bUpgradeFromB1 = FALSE;
LogSetup( pSetupLog, L"Setting policy registry key\n" );
//
// Open TS registry key under HKLM\System\CurrentControlSet\Control\Terminal Serv...
//
dwStatus = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
REG_CONTROL_GETHELP,
0,
KEY_READ | KEY_WRITE,
&hKey
);
if( ERROR_SUCCESS == dwStatus )
{
dwStatus = GetPolicyAllowGetHelpSetting(
HKEY_LOCAL_MACHINE,
OLD_REG_CONTROL_GETHELP,
RDS_ALLOWGETHELP_VALUENAME,
&dwValue
);
if( ERROR_SUCCESS == dwStatus )
{
LogSetup( pSetupLog, L"B1 policy value %d\n", dwValue );
//
// Delete the old policy key, ignore error.
//
RegDelKey( HKEY_LOCAL_MACHINE, OLD_REG_CONTROL_GETHELP );
//
// This value exists in old Salem policy key, system must be
// upgrading from B1.
//
dwStatus = RegSetValueEx(
hKey,
RDS_ALLOWGETHELP_VALUENAME,
0,
REG_DWORD,
(PBYTE)&dwValue,
sizeof(dwValue)
);
bUpgradeFromB1 = TRUE;
}
else
{
LogSetup( pSetupLog, L"B1 policy key does not exist\n" );
dwSize = sizeof(dwValue);
//
// Upgrade from B2 and beyond, check to see if fAllowToGetHelp exist
// if not, set it to 1.
//
dwStatus = RegQueryValueEx(
hKey,
RDS_ALLOWGETHELP_VALUENAME,
0,
&dwType,
(PBYTE)&dwValue,
&dwSize
);
if( ERROR_FILE_NOT_FOUND == dwStatus || REG_DWORD != dwType )
{
//
// default is not allow to get help if
// value does not exist.
//
dwValue = 1;
dwStatus = RegSetValueEx(
hKey,
RDS_ALLOWGETHELP_VALUENAME,
0,
REG_DWORD,
(PBYTE)&dwValue,
sizeof(dwValue)
);
}
else
{
LogSetup( pSetupLog, L"Existing fAllowToGetHelp Policy value %d\n", dwValue );
}
}
LogSetup( pSetupLog, L"Setting fAllowGetHelp policy key result - %d\n", dwStatus );
RegCloseKey( hKey );
}
else
{
LogSetup(
pSetupLog,
L"Can't open registry key %s, error code %d\n",
REG_CONTROL_GETHELP,
dwStatus
);
}
if( TRUE == bUpgradeFromB1 )
{
//
// B1, help assistant account password is clear text, this will fix the
// security leak.
//
LogSetup( pSetupLog, L"Upgrade from B1, delete all pending help and reset account password\n" );
RegDelKey(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
);
g_HelpAccount.ResetHelpAccountPassword();
}
LogSetup( pSetupLog, L"Leaving UpgradeSessmgr\n" );
return;
}
#define UNINSTALL_BEFORE_INSTALL _TEXT("UninstallBeforeInstall")
HRESULT
InstallUninstallSessmgr(
DWORD code
)
/*++
--*/
{
FILE* pSetupLog;
TCHAR LogFile[MAX_PATH+1];
HRESULT hRes = S_OK;
DWORD dwStatus = ERROR_SUCCESS;
HKEY hKey = NULL;
DWORD dwValue = 1;
DWORD dwType;
DWORD cbData = sizeof(dwValue);
GetWindowsDirectory( LogFile, MAX_PATH );
lstrcat( LogFile, L"\\" );
lstrcat( LogFile, SETUPLOGFILE_NAME );
pSetupLog = _tfopen( LogFile, L"a+t" );
MYASSERT( NULL != pSetupLog );
LogSetup( pSetupLog, L"\n\n********* Install/uninstall sessmgr service *********\n" );
//
// no checking on return, if failure, we just do OutputDebugString();
//
switch( code )
{
case SESSMGR_UNREGSERVER:
{
LogSetup( pSetupLog, L"Uninstalling sessmgr service\n" );
//
// Delete all pending help session.
//
dwStatus = RegDelKey(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
);
LogSetup( pSetupLog, L"Delete pending table return %d\n", dwStatus );
//
// We might not be running in system context so deleting registry and
// cleanup LSA key will fail, write a key to our control location to
// mark such that delete everything before install
//
dwStatus = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK,
0,
KEY_ALL_ACCESS,
&hKey
);
if( ERROR_SUCCESS == dwStatus )
{
dwStatus = RegSetValueEx(
hKey,
UNINSTALL_BEFORE_INSTALL,
0,
REG_DWORD,
(BYTE *) &dwValue,
sizeof(dwValue)
);
if( ERROR_SUCCESS != dwStatus )
{
LogSetup( pSetupLog, L"Failed to set value, error code %d\n", dwStatus );
MYASSERT(FALSE);
}
RegCloseKey( hKey );
}
else
{
// This is OK since we havn't been install before.
LogSetup( pSetupLog, L"Failed to open control key, error code %d\n", dwStatus );
}
//
// Initialize to get help account name.
//
hRes = g_HelpAccount.Initialize();
LogSetup( pSetupLog, L"Initialize help account return 0x%08x\n", hRes );
//
// ignore error, try to delete the account
hRes = g_HelpAccount.DeleteHelpAccount();
LogSetup( pSetupLog, L"Delete help account return 0x%08x\n", hRes );
MYASSERT( SUCCEEDED(hRes) );
hRes = _Module.UnregisterServer(pSetupLog);
LogSetup( pSetupLog, L"UnregisterServer() returns 0x%08x\n", hRes );
if( ERROR_SUCCESS == StartICSLib() )
{
// Non-critical if we can't startup the lib since after we shutdown,
// we would have close all the port
CloseAllOpenPorts();
StopICSLib();
}
}
break;
case SESSMGR_REGSERVER:
{
LogSetup( pSetupLog, L"Installing as non-service\n" );
#if DBG
AddAccountToFilterList( HELPASSISTANTACCOUNT_NAME );
MYASSERT( ERROR_SUCCESS == g_HelpAccount.CreateHelpAccount() ) ;
hRes = _Module.RegisterServer(pSetupLog, TRUE, FALSE);
#else
hRes = E_INVALIDARG;
#endif
}
break;
//case SESSMGR_UPGRADE:
//
// TODO - ICS work, add upgrade special code.
//
case SESSMGR_SERVICE:
{
LogSetup( pSetupLog, L"Installing sessmgr service\n" );
hRes = S_OK;
//
// Clean up again, we might not be running in system
// context at the time of uninstall so clean up will failed.
//
dwStatus = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK,
0,
KEY_ALL_ACCESS,
&hKey
);
if( ERROR_SUCCESS == dwStatus )
{
//
// Check to see if previous uninstall failed,
// we only need to check value exists.
//
dwStatus = RegQueryValueEx(
hKey,
UNINSTALL_BEFORE_INSTALL,
0,
&dwType,
(BYTE *) &dwValue,
&cbData
);
if( ERROR_SUCCESS != dwStatus || REG_DWORD != dwType )
{
//
// No previous uninstall information, no need to delete anything
//
LogSetup( pSetupLog, L"UninstallBeforeInstall value not found or invalid, code %d\n", dwStatus );
}
else
{
LogSetup( pSetupLog, L"UninstallBeforeInstall exists, cleanup previous uninstall\n" );
//
// Previous uninstall failed, delete all pending help session,
// and clean up encryption key
//
dwStatus = RegDelKey(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
);
//
// It's OK to fail here since we reset encryption key making existing
// ticket useless and will be deleted on expire.
//
LogSetup( pSetupLog, L"Delete pending table return %d\n", dwStatus );
dwStatus = TSHelpAssistantInitializeEncryptionLib();
if( ERROR_SUCCESS == dwStatus )
{
dwStatus = TSHelpAssisantEndEncryptionCycle();
if( ERROR_SUCCESS != dwStatus )
{
LogSetup( pSetupLog, L"TSHelpAssisantEndEncryptionCycle() returns 0x%08x\n", dwStatus );
LogSetup( pSetupLog, L"sessmgr setup can't continue\n" );
// Critical security error, existing ticket might still be valid
hRes = HRESULT_FROM_WIN32( dwStatus );
}
TSHelpAssistantEndEncryptionLib();
}
else
{
LogSetup( pSetupLog, L"TSHelpAssistantInitializeEncryptionLib return %d\n", dwStatus );
LogSetup( pSetupLog, L"sessmgr setup can't continue\n" );
// Critical security error, existing ticket might still be valid
hRes = HRESULT_FROM_WIN32( dwStatus );
}
}
if( SUCCEEDED(hRes) )
{
//
// Delete reg. value to uninstall before install only when successfully
// resetting encryption key
//
RegDeleteValue( hKey, UNINSTALL_BEFORE_INSTALL );
}
RegCloseKey( hKey );
}
if( SUCCEEDED(hRes) )
{
hRes = g_HelpAccount.CreateHelpAccount();
if( SUCCEEDED(hRes) )
{
CComBSTR bstrHelpAccName;
hRes = g_HelpAccount.GetHelpAccountNameEx( bstrHelpAccName );
MYASSERT( SUCCEEDED(hRes) );
if( FAILED(hRes) )
{
// not a critical error, we can still use help
LogSetup( pSetupLog, L"Failed to retrieve HelpAssistantaccount name - 0x%08x\n", hRes );
}
else
{
LogSetup( pSetupLog, L"HelpAssistant account name - %s\n", bstrHelpAccName );
// Add HelpAssistantAccount into account filter list
AddAccountToFilterList( bstrHelpAccName );
}
//
// Two type of SP install, one thru SP1 installer and the other is
// normal NT setup including all SP fixes.
// We disable account on setup and let service startup to re-enable it
//
g_HelpAccount.EnableHelpAssistantAccount(FALSE);
//
// Upgrade session manager
//
UpgradeSessmgr(pSetupLog);
LogSetup( pSetupLog, L"Successfully setup account\n" );
hRes = _Module.RegisterServer(pSetupLog, TRUE, TRUE);
if( FAILED(hRes) )
{
LogSetup( pSetupLog, L"Failed to register/installing service - 0x%08x\n", hRes );
}
}
else
{
LogSetup( pSetupLog, L"Creating Help Assistant account failed with 0x%08x\n", hRes );
(void) g_HelpAccount.DeleteHelpAccount();
hRes = E_FAIL;
}
}
if( SUCCEEDED(hRes) )
{
hRes = CreatePendingHelpTable(pSetupLog);
if( FAILED(hRes) )
{
LogSetup(
pSetupLog,
L"CreatePendingHelpTable() failed - 0x%08x\n",
hRes
);
}
}
}
break;
default:
LogSetup( pSetupLog, L"Invalid setup operation %d\n", code );
hRes = E_UNEXPECTED;
}
LogSetup( pSetupLog, L"\n*** Finish Setup with Status 0x%08x ***\n", hRes );
if( pSetupLog )
{
fflush( pSetupLog );
fclose( pSetupLog);
}
return hRes;
}
/////////////////////////////////////////////////////////////////////////////
//
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
{
HRESULT hRes;
CComBSTR bstrErrMsg;
CComBSTR bstrServiceDesc;
DWORD dwStatus;
lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
_Module.Init(ObjectMap, hInstance, IDS_SERVICENAME, IDS_SERVICEDISPLAYNAME, IDS_SERVICEDESC, &LIBID_RDSESSMGRLib);
_Module.m_bService = TRUE;
TCHAR szTokens[] = _T("-/");
//
// We don't do OS version checking as in Win9x case, some of our
// call uses API not exists on Win9x so will get unresolve
// reference when running on Win9x box.
//
bstrServiceDesc.LoadString( IDS_SERVICEDISPLAYNAME );
LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
while (lpszToken != NULL)
{
if (lstrcmpi(lpszToken, _T("UnregServer"))==0)
{
return InstallUninstallSessmgr( SESSMGR_UNREGSERVER );
}
else if (lstrcmpi(lpszToken, _T("RegServer"))==0)
{
return InstallUninstallSessmgr( SESSMGR_REGSERVER );
}
else if (lstrcmpi(lpszToken, _T("Service"))==0)
{
return InstallUninstallSessmgr( SESSMGR_SERVICE );
}
else if ( lstrcmpi(lpszToken, _T("SP1Upgrade"))==0)
{
// BUGL 602653, HelpAssistant account is not disable at clean install
// disable account here and let service start up to re-enable.
return EnableLocalAccount( HELPASSISTANTACCOUNT_NAME, FALSE );
}
lpszToken = FindOneOf(lpszToken, szTokens);
}
// Are we Service or Local Server
CRegKey keyAppID;
LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_READ);
if (lRes != ERROR_SUCCESS)
{
_Module.LogErrorEvent( SESSMGR_E_SETUP );
return lRes;
}
CRegKey key;
lRes = key.Open(keyAppID, _T("{038ABBA4-4138-4AC4-A492-4A3DF068BD8A}"), KEY_READ);
if (lRes != ERROR_SUCCESS)
{
_Module.LogErrorEvent( SESSMGR_E_SETUP );
return lRes;
}
TCHAR szValue[_MAX_PATH];
DWORD dwLen = _MAX_PATH;
lRes = key.QueryValue(szValue, _T("LocalService"), &dwLen);
_Module.m_bService = FALSE;
if (lRes == ERROR_SUCCESS)
_Module.m_bService = TRUE;
_Module.Start();
// When we get here, the service has been stopped
return _Module.m_status.dwWin32ExitCode;
}