Windows2003-3790/termsrv/setup/dll/subcore.cpp
2020-09-30 16:53:55 +02:00

2073 lines
61 KiB
C++

//
//Copyright (c) 1998 - 1999 Microsoft Corporation
//
//
// SubCore.cpp
// subcomponent Core terminal server implementation.
//
#include "stdafx.h"
#include "SubCore.h"
#include "acl.h"
#include "rdpdrstp.h"
BOOL UpdateAudioCodecs (BOOL bIsProfessional);
LPCTSTR SubCompCoreTS::GetSubCompID () const
{
return BASE_COMPONENT_NAME;
}
DWORD SubCompCoreTS::GetStepCount () const
{
return 18;
}
DWORD SubCompCoreTS::OnQueryState ( UINT /* uiWhichState */)
{
AssertFalse(); // since this is our internal component.
return SubcompUseOcManagerDefault;
}
DWORD SubCompCoreTS::OnQuerySelStateChange (BOOL /*bNewState*/, BOOL /*bDirectSelection*/) const
{
// we are not a real sub comp.
ASSERT(FALSE);
return TRUE;
}
LPCTSTR SubCompCoreTS::GetSectionToBeProcessed (ESections /* eSection */) const
{
LPCTSTR sectionname = NULL;
if (StateObject.IsGuiModeSetup()) // core installation is only for gui-mode.
{
ETSInstallType eInstallType = StateObject.GetInstalltype();
switch (eInstallType)
{
case eFreshInstallTS:
if (StateObject.IsX86())
{
sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_X86 : FRESH_INSTALL_SERVER_X86;
}
else
{
if (StateObject.IsAMD64())
{
sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_AMD64 : FRESH_INSTALL_SERVER_AMD64;
}
else
{
sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_IA64 : FRESH_INSTALL_SERVER_IA64;
}
}
break;
case eUpgradeFrom40TS:
ASSERT(StateObject.IsServer());
if (StateObject.IsX86())
{
sectionname = UPGRADE_FROM_40_SERVER_X86;
}
else
{
ASSERT(FALSE); // we did not have ts4 on ia64
sectionname = UPGRADE_FROM_40_SERVER_IA64;
}
break;
case eUpgradeFrom50TS:
//
// we dont really have a upgrade from 50 case for Professional, But to support old 51 (pre 2220) builds)
// of pro which think that they are 50, we need to check for professional here.
//
if (StateObject.IsX86())
{
sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_51_PRO_X86 : UPGRADE_FROM_50_SERVER_X86;
}
else
{
sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_51_PRO_IA64 : UPGRADE_FROM_50_SERVER_IA64;
}
break;
case eUpgradeFrom51TS:
if (StateObject.IsX86())
{
sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_51_PRO_X86 : UPGRADE_FROM_51_SERVER_X86;
}
else
{
sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_51_PRO_IA64 : UPGRADE_FROM_51_SERVER_IA64;
}
break;
case eUpgradeFrom52TS:
if (StateObject.IsX86())
{
sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_52_PRO_X86 : UPGRADE_FROM_52_SERVER_X86;
}
else
{
if (StateObject.IsAMD64()) {
sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_52_PRO_AMD64 : UPGRADE_FROM_52_SERVER_AMD64;
}
else
{
sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_52_PRO_IA64 : UPGRADE_FROM_52_SERVER_IA64;
}
}
break;
case eStandAloneSetup:
ASSERT(FALSE);
sectionname = NULL;
break;
default:
ASSERT(FALSE);
if (StateObject.IsX86())
{
sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_X86 : FRESH_INSTALL_SERVER_X86;
}
else
{
if (StateObject.IsAMD64())
{
sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_AMD64 : FRESH_INSTALL_SERVER_AMD64;
}
else
{
sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_IA64 : FRESH_INSTALL_SERVER_IA64;
}
}
}
}
return sectionname;
}
BOOL SubCompCoreTS::BeforeCompleteInstall ()
{
IsCSCEnabled();
return(TRUE);
}
BOOL SubCompCoreTS::AfterCompleteInstall ()
{
IsCSCEnabled();
//
// This is core TS subcomponent.
// It has nothing to do with standalone seutp.
// so if we are in standalone setup. just return.
//
//
// Deny Connections registry
//
WriteDenyConnectionRegistry ();
Tick();
if (!StateObject.IsGuiModeSetup())
{
return TRUE;
}
SetProgressText(IDS_STRING_PROGRESS_CORE_TS);
//
// add ts product suite to registry.
//
AddRemoveTSProductSuite();
Tick();
#ifndef TERMSRV_PROC
//
// add termsrv to netsvcs group.
//
AddTermSrvToNetSVCS ();
Tick();
#endif
//
// apply hydra security to registry.
//
DoHydraRegistrySecurityChanges();
Tick();
//
// Audio Redirection
//
UpdateAudioCodecs( StateObject.IsWorkstation() );
Tick();
//
// Client Drive Mappings.
//
AddRemoveRDPNP();
Tick();
//
// Hot key for Local Language change.
//
// We dont need to do this.
// HandleHotkey ();
// Tick();
//
// Printer Redirection.
//
InstallUninstallRdpDr ();
Tick();
#ifdef TSOC_CONSOLE_SHADOWING
//
// Console Shadowing.
//
SetupConsoleShadow();
Tick();
#endif // TSOC_CONSOLE_SHADOWING
//InstallTermdd();
//Tick();
//
// Performance monitors for TS. BUGBUG - check with ErikMa - do they work when TS is not started ?
//
LoadOrUnloadPerf();
Tick();
//
// If this were a real subcomponent, one that the OC manager knew
// about and handled, the following call would be to
// GetOriginalSubCompState().
//
if (StateObject.WasTSInstalled())
{
UpgradeRdpWinstations();
Tick();
//
// This no longer exists in Whistler
//
DisableInternetConnector();
Tick();
if (StateObject.IsUpgradeFrom40TS())
{
//
// this is upgrade from TS4
// we want to remove service pack key in uninstall. this is to
// ensure that service pack do not appear in Add/Remove Programs
// and in our incompatible applications list.
//
RemoveTSServicePackEntry();
Tick();
//
// There are some metaframe components in user init,
// we need to remove thouse as we upgrade ts40
//
RemoveMetaframeFromUserinit ();
Tick();
}
//
// we need to reset Win2000 ts grace period for licenses on upgrades
// Whistler uses a different location, so this won't affect RTM to
// RTM upgrades
//
ResetTermServGracePeriod();
Tick();
//
// Delete old LSA secrets used by public/private keys
//
RemoveOldKeys();
Tick();
}
// some new code to uninstall TSClient.
if (!UninstallTSClient())
{
LOGMESSAGE0(_T("ERROR: Could not uninstall tsclient."));
}
IsCSCEnabled();
Tick();
return TRUE;
}
BOOL SubCompCoreTS::IsTermSrvInNetSVCS ()
{
BOOL bStringExists = FALSE;
DWORD dw = IsStringInMultiString(
HKEY_LOCAL_MACHINE,
SVCHOSST_KEY,
NETSVCS_VAL,
TERMSERVICE,
&bStringExists);
return (dw == ERROR_SUCCESS) && bStringExists;
}
BOOL SubCompCoreTS::AddTermSrvToNetSVCS ()
{
DWORD dw = NO_ERROR;
if (StateObject.IsWorkstation())
{
//
// for workstations, we want to share process with netsvcs group
//
if (!IsTermSrvInNetSVCS())
{
dw = AppendStringToMultiString(
HKEY_LOCAL_MACHINE,
SVCHOSST_KEY,
NETSVCS_VAL,
TERMSERVICE
);
if (dw != NO_ERROR)
{
LOGMESSAGE1(_T("Error, appending TermService to netsvcs, Errorcode = %u"), dw);
}
}
}
//
// for servers we want to have our own svchost for termsrv.
// lets create the necessary entries for pro as well, so that for debugging termsrv it'll be easier to switch to own svchost.
//
{
//
// for servers we want to have our own svchost process.
//
CRegistry oReg;
dw = oReg.OpenKey(HKEY_LOCAL_MACHINE, SVCHOSST_KEY);
if (ERROR_SUCCESS == dw)
{
dw = oReg.WriteRegMultiString(TERMSVCS_VAL, TERMSERVICE_MULTISZ, (_tcslen(TERMSERVICE) + 2) * sizeof(TCHAR));
if (ERROR_SUCCESS == dw)
{
// add CoInitializeSecurityParam, so that CoInitialize gets called in main thread for this svc group.
CRegistry termsvcKey;
dw = termsvcKey.CreateKey(HKEY_LOCAL_MACHINE, SVCHOSST_TERMSRV_KEY );
if (ERROR_SUCCESS == dw)
{
dw = termsvcKey.WriteRegDWord(TERMSVCS_PARMS, 1);
if (ERROR_SUCCESS != dw)
{
LOGMESSAGE1(_T("Failed to write termsvc coinit params, Error = %d"), dw);
}
}
else
{
LOGMESSAGE1(_T("Error, Failed to create svchost\termsrv key, Error = %d"), dw);
}
}
else
{
LOGMESSAGE1(_T("Error, Writing termsrv value, Error = %d"), dw);
}
}
else
{
LOGMESSAGE1(_T("Error, Opening Svchost key, Error = %d"), dw);
}
}
return dw == NO_ERROR;
}
/*--------------------------------------------------------------------------------------------------------
* DWORD AddRemoveTSProductSuite (BOOL bAddRemove)
* does the necessary changes for installing hydra specific registry keys which are not done from inf.
* parameter state decides if key is to be added or removed.
* returns success
* -------------------------------------------------------------------------------------------------------*/
BOOL SubCompCoreTS::AddRemoveTSProductSuite ()
{
//
// add product suite key only for servers.
// This is required only for TS4 compatibility.
// TS4 applications detect if machine is terminal server using this key.
//
DWORD dw = NO_ERROR;
if (StateObject.IsServer())
{
// installing/upgrading.
if (!DoesHydraKeysExists())
{
ASSERT(FALSE == StateObject.WasTSInstalled());
// now read the original data in this product suite value.
dw = AppendStringToMultiString(
HKEY_LOCAL_MACHINE,
PRODUCT_SUITE_KEY,
PRODUCT_SUITE_VALUE,
TS_PRODUCT_SUITE_STRING
);
if (dw != NO_ERROR)
LOGMESSAGE1(_T("ERROR:DoHydraRegistryChanges : Error Appending String = <%lu>"), dw);
}
}
dw = SetTSVersion(TERMINAL_SERVER_THIS_VERSION);
if (ERROR_SUCCESS != dw)
{
LOGMESSAGE1(_T("ERROR, Setting TS version, ErrorCode = %u "), dw);
}
return dw == NO_ERROR;
}
BOOL SubCompCoreTS::DisableWinStation (CRegistry *pRegWinstation)
{
ASSERT(pRegWinstation);
#ifdef DBG
// the value must be there already.
DWORD dwValue;
ASSERT(ERROR_SUCCESS == pRegWinstation->ReadRegDWord(_T("fEnableWinStation"), &dwValue));
#endif
VERIFY(ERROR_SUCCESS == pRegWinstation->WriteRegDWord(_T("fEnableWinStation"), 0));
return TRUE;
}
BOOL SubCompCoreTS::DoesLanaTableExist ()
{
static fValueDetermined = FALSE;
static fRet;
if (fValueDetermined)
{
return(fRet);
}
else
{
CRegistry Reg;
fRet = Reg.OpenKey(HKEY_LOCAL_MACHINE, TS_LANATABLE_KEY) == ERROR_SUCCESS;
fValueDetermined = TRUE;
LOGMESSAGE1(_T("DoesLanaTableExist: %s"), fRet ? _T("Yes") : _T("No"));
return(fRet);
}
}
void SubCompCoreTS::VerifyLanAdapters (CRegistry *pRegWinstation, LPTSTR pszWinstation)
{
DWORD dwLana = 0;
static BOOL fErrorLogged = FALSE;
LOGMESSAGE1(_T("Verifying lan adapters for %s"), pszWinstation);
if (DoesLanaTableExist())
{
LOGMESSAGE0(_T("OK: GuidTable already exists."));
return;
}
if (pRegWinstation->ReadRegDWord(_T("LanAdapter"), &dwLana) == ERROR_SUCCESS)
{
if (dwLana == 0)
{
LOGMESSAGE0(_T("OK: using all adapters"));
}
else
{
LPTSTR lpStrings[1] = { NULL };
LOGMESSAGE0(_T("ERROR: using custom bindings"));
LOGMESSAGE1(_T("%s will be disabled and bindings reset"), pszWinstation);
VERIFY(ERROR_SUCCESS == pRegWinstation->WriteRegDWord(_T("LanAdapter"), (DWORD)-1));
VERIFY(ERROR_SUCCESS == pRegWinstation->WriteRegDWord(_T("fEnableWinStation"), 0));
//
// Log error to setuperr.txt once. Log error to eventlog
// each time.
//
if (!fErrorLogged)
{
fErrorLogged = TRUE;
LogErrorToSetupLog(OcErrLevWarning, IDS_STRING_GENERIC_LANA_WARNING);
}
lpStrings[0] = pszWinstation;
LogErrorToEventLog(
EVENTLOG_WARNING_TYPE,
CATEGORY_NOTIFY_EVENTS,
EVENT_WINSTA_DISABLED_DUE_TO_LANA,
1,
0,
(LPCTSTR *)lpStrings,
NULL
);
}
}
else
{
LOGMESSAGE0(_T("OK: No LanAdapter value"));
}
}
BOOL SubCompCoreTS::UpdateRDPWinstation (CRegistry *pRegWinstation, LPTSTR lpWinStationName)
{
// BUG WARNING: ALL OF THESE VALUES MUST BE KEPT IN SYNC WITH TSOC.INX!!!
//
// These entries will be modified on upgrades.
//
LOGMESSAGE1(_T("Updating Winstation - %s"), lpWinStationName);
ASSERT(pRegWinstation);
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableClip"), 0) );
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableCpm"), 0) );
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableLPT"), 0) );
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fInheritAutoClient"), 1) );
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fAutoClientLpts"), 1) );
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fForceClientLptDef"), 1) );
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegString(_T("WdName"), _T("Microsoft RDP 5.2")));
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWord(_T("WdFlag"), 0x36) );
// per JoyC updated for RDPWD, RDP-TCP winstations.
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableCcm"), 0x0) );
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableCdm"), 0x0) );
// enable audio redirection for Professional, disable for server
//
if ( StateObject.IsWorkstation() )
{
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableCam"), 0x0 ));
}
// Per AraBern, updated for RDPWD, RDP-TCP winstations.
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("ColorDepth"), StateObject.IsWorkstation() ? 0x4 : 0x3) );
VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fInheritColorDepth"), 0x0) );
// HKLM ,"SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\UserOverride\Control Panel\Desktop","Wallpaper",STRIG_RETAIN,""
// To address bug 727650 (appcompat problem if cursorblink is set to -1_, remove the following regvalue:
// Remove HKLM ,"SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\UserOverride\Control Panel\Desktop","DisableCursorBlink"
CRegistry oReg;
if (ERROR_SUCCESS == oReg.CreateKey(*pRegWinstation, _T("UserOverride\\Control Panel\\Desktop")))
{
//
// set cursor blink and wallpaper off on servers.
//
if (!StateObject.IsWorkstation())
{
oReg.DeleteValue(_T("DisableCursorBlink"));
oReg.WriteRegString(_T("Wallpaper"), _T(""));
}
}
// Move old autologon password into LSA (a-sajara)
// We only want to move the password if a valid winstation name is provided
if (lpWinStationName != NULL)
{
MoveWinStationPassword(pRegWinstation, lpWinStationName);
}
return TRUE;
}
/*****************************************************************************
* Method: MoveWinStationPassword
*
* Overview: For security reasons the lightly encrypted password that is
* stored in the winstation registry key is being moved to LSA
* secret. We are going to keep the password in it's encrypted
* form so we can just copy it over as is.
*
* Parameters: pRegWinstation (IN) - pointer to winstation registry key
* strWinStationName (IN) - Winstation name we are looking at
*
*****************************************************************************/
BOOL
SubCompCoreTS::MoveWinStationPassword(CRegistry *pRegWinstation,
LPTSTR strWinStationName)
{
USES_CONVERSION;
DWORD dwRet;
LPTSTR strKeyName = NULL;
LPTSTR strPassword = NULL;
DWORD dwKeyLength;
DWORD dwPasswordLength;
// Make sure a Winstation name is provided this is used for a unique LSA key
if (strWinStationName == NULL)
{
LOGMESSAGE0(_T("ERROR, Winstation name not provided."));
return FALSE;
}
// Read password from the registry
dwRet = pRegWinstation->ReadRegString(OLD_PASSWORD_VALUE_NAME,
&strPassword,
&dwPasswordLength);
if (dwRet != ERROR_SUCCESS)
{
LOGMESSAGE0(_T("Failed to read Password value for Winstation"));
return FALSE;
}
LOGMESSAGE1(_T("Password for this winstation = %s"), strPassword);
// Build LSA key name by appending the Winstation Name to the static KeyName
dwKeyLength = _tcslen(LSA_PSWD_KEYNAME_T) + _tcslen(strWinStationName) + 1;
// Allocate memory for the password KEY
strKeyName = (LPTSTR)LocalAlloc(LMEM_FIXED, dwKeyLength * sizeof(TCHAR));
if (strKeyName == NULL)
{
LOGMESSAGE0(_T("ERROR, Failed to allocate memory for LSA password key"));
return FALSE;
}
_tcscpy(strKeyName, LSA_PSWD_KEYNAME_T);
_tcscat(strKeyName, strWinStationName);
strKeyName[dwKeyLength - 1] = _T('\0');
LOGMESSAGE1(_T("Storing the password in LSA key:%s"), strKeyName);
// Store the password in LSA
dwRet = StoreSecretKey(T2W(strKeyName),
(PBYTE)strPassword,
dwPasswordLength);
if (dwRet != ERROR_SUCCESS)
{
LOGMESSAGE1(_T("StoreSecretKey(strKeyName) failed. Reason %ld"), dwRet);
}
LocalFree(strKeyName);
LOGMESSAGE1(_T("Deleting password key:%s"),strKeyName);
// Delete the password key
dwRet = pRegWinstation->DeleteValue(OLD_PASSWORD_VALUE_NAME);
if (dwRet != ERROR_SUCCESS)
{
LOGMESSAGE0(_T("ERROR, Failed to delete Password value for Winstation"));
return FALSE;
}
return TRUE;
}
BOOL SubCompCoreTS::IsRdpWinStation(CRegistry *pRegWinstation)
{
ASSERT(pRegWinstation);
DWORD dwWdFlag;
if (ERROR_SUCCESS == pRegWinstation->ReadRegDWord(_T("WdFlag"), &dwWdFlag))
{
#ifdef DBG
// if this is an RDP winstation,
// we must have Microsoft in the WdName string
if (WDF_TSHARE & dwWdFlag)
{
LPTSTR strWdName;
DWORD dwSize;
if (ERROR_SUCCESS == pRegWinstation->ReadRegString(_T("WdName"), &strWdName, &dwSize))
{
ASSERT(_tcsstr(strWdName,_T("Microsoft")) && _tcsstr(strWdName, _T("RDP")));
}
else
{
//
// we failed to read strWdName.
// it shouldn't have happened.
ASSERT(FALSE);
}
}
#endif
return WDF_TSHARE & dwWdFlag;
}
else
{
//
// we failed to read WdFlag, it should not have happened.
//
LOGMESSAGE0(_T("ERROR, Failed to read WdFlag for winstation"));
ASSERT(FALSE);
return FALSE;
}
}
BOOL SubCompCoreTS::IsConsoleWinStation(CRegistry *pRegWinstation)
{
ASSERT(pRegWinstation);
LPTSTR strWdName;
DWORD dwSize;
if (ERROR_SUCCESS == pRegWinstation->ReadRegString(_T("WdName"), &strWdName, &dwSize))
{
// if the value wdname contains the string "Console"
// this is console winstation subkey
LOGMESSAGE1(_T("WdName for this winstation = %s"), strWdName);
#ifdef DBG
// if this is console winstation
if (_tcsicmp(strWdName,_T("Console")) == 0)
{
// then it cannot be either RDP or MetaFrame winstation
ASSERT(!IsMetaFrameWinstation(pRegWinstation) && !IsRdpWinStation(pRegWinstation));
}
#endif
return _tcsicmp(strWdName,_T("Console")) == 0;
}
else
{
LOGMESSAGE0(_T("ERROR, Failed to read Wdname for winstation"));
ASSERT(FALSE);
return FALSE;
}
}
// returns true if this is non-rdp and non-console winstation subkey.
BOOL SubCompCoreTS::IsMetaFrameWinstation(CRegistry *pRegWinstation)
{
ASSERT(pRegWinstation);
DWORD dwWdFlag;
if (ERROR_SUCCESS == pRegWinstation->ReadRegDWord(_T("WdFlag"), &dwWdFlag))
{
return WDF_ICA & dwWdFlag;
}
else
{
//
// we could not read WdFlag value.
//
LOGMESSAGE0(_T("ERROR, Failed to read WdFlag for winstation"));
ASSERT(FALSE);
return TRUE;
}
}
BOOL SubCompCoreTS::UpgradeRdpWinstations ()
{
// we need to upgrade RDP capabilities for RDPWD and existing RDP winstations.
// see also #240925
// also if during upgrades we found any non-rdp winstations
// we must disable them as they are not compatible with NT5.
// #240905
CRegistry reg;
if (ERROR_SUCCESS == reg.OpenKey(HKEY_LOCAL_MACHINE, REG_WINSTATION_KEY))
{
LPTSTR lpStr = NULL;
DWORD dwSize = 0;
if (ERROR_SUCCESS == reg.GetFirstSubKey(&lpStr, &dwSize))
{
do
{
ASSERT(lpStr);
ASSERT(dwSize > 0);
// check if the current key is on rdp winstation
CRegistry regSubKey;
if ( ERROR_SUCCESS == regSubKey.OpenKey(reg, lpStr) )
{
if (IsRdpWinStation(&regSubKey))
{
LOGMESSAGE1(_T("Updating Winstation - %s"), lpStr);
UpdateRDPWinstation(&regSubKey, lpStr);
VerifyLanAdapters(&regSubKey, lpStr);
}
else if (IsMetaFrameWinstation(&regSubKey))
{
LOGMESSAGE1(_T("Disabling winstaion - %s"), lpStr);
DisableWinStation(&regSubKey);
VerifyLanAdapters(&regSubKey, lpStr);
}
else
{
LOGMESSAGE1(_T("Found a Console Winstation - %s"), lpStr);
// this must be console winstation
// do nothing for this.
}
}
else
{
AssertFalse();
LOGMESSAGE1(_T("ERROR:Failed to Open Winstation Key %s"), lpStr);
}
}
while (ERROR_SUCCESS == reg.GetNextSubKey(&lpStr, &dwSize ));
}
else
{
// since this is upgrade we must find key under Winstations.
AssertFalse();
return FALSE;
}
}
else
{
AssertFalse();
return FALSE;
}
// we need to upgrade Wds\rdpwd as well.
if ( ERROR_SUCCESS == reg.OpenKey(HKEY_LOCAL_MACHINE, SYSTEM_RDPWD_KEY))
{
//
// this is not really a winstation.
// but this call will upgrade the required entries.
//
UpdateRDPWinstation(&reg, NULL);
}
else
{
AssertFalse();
return FALSE;
}
return TRUE;
}
/*--------------------------------------------------------------------------------------------------------
* BOOL DoHydraRegistrySecurityChanges ()
* does the necessary security changes for installing hydra
* that is Adds/remove LogOnLocall rights to EveryOne group.
* returns success
* Parameter decides if hydra is getting enabled or disabled.
* -------------------------------------------------------------------------------------------------------*/
BOOL SubCompCoreTS::DoHydraRegistrySecurityChanges ()
{
BOOL bAddRemove = StateObject.IsTSEnableSelected();
DWORD dwError = NO_ERROR;
if (bAddRemove)
{
CRegistry reg;
dwError = reg.OpenKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software"));
if (ERROR_SUCCESS == dwError)
{
PSECURITY_DESCRIPTOR pSecDec, pSecDecNew;
DWORD dwSize;
dwError = reg.GetSecurity(&pSecDec, DACL_SECURITY_INFORMATION, &dwSize);
if (dwError != ERROR_SUCCESS)
{
LOGMESSAGE1(_T("ERROR:GetSecurity failed with %u"), dwError);
}
else
{
ASSERT(pSecDec);
ASSERT(IsValidSecurityDescriptor(pSecDec));
pSecDecNew = pSecDec;
PACL pNewDacl = NULL;
if (!AddTerminalServerUserToSD(&pSecDecNew, GENERIC_WRITE, &pNewDacl ))
{
LOGMESSAGE1(_T("ERROR:AddUserToSD failed with %u"), GetLastError());
}
else
{
// due to a bug in RegSetKeySecurity(), existing children of this key
// will not get the new SID, hence, we must use MARTA calls intead.
dwError = SetNamedSecurityInfo(
_T("Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software"),
SE_REGISTRY_KEY,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
pNewDacl,
NULL);
if (dwError != ERROR_SUCCESS)
{
LOGMESSAGE1(_T("ERROR:SetNamedSecurityInfo failed with %u"), dwError);
}
}
// if new sec desciptor been allocated
if (pSecDecNew != pSecDec)
LocalFree(pSecDecNew);
}
}
else
{
LOGMESSAGE1(_T("ERROR, OpenKey failed, error = %d"), dwError);
}
}
else
{
ASSERT(FALSE);
}
return dwError == NO_ERROR;
}
#define INTERNET_CONNECTOR_LICENSE_STORE L"INET_LICENSE_STORE_2_60e55c11-a780-11d2-b1a0-00c04fa30cc4"
#define INTERNET_CONNECTOR_LSERVER_STORE L"INET_LSERVER_STORE_2_341D3DAB-BD58-11d2-B130-00C04FB16103"
#define INTERNET_CONNECTOR_LSERVER_STORE2 L"INET_LSERVER_STORE_3_341D3DAB-BD58-11d2-B130-00C04FB16103"
#define HYDRA_SERVER_PARAM _T("SYSTEM\\CurrentControlSet\\Services\\TermService\\Parameters")
#define HS_PARAM_INTERNET_CONNECTOR_FLAG _T("fInternetConnector")
BOOL SubCompCoreTS::DisableInternetConnector ()
{
LOGMESSAGE0(_T("DisableInternetConnector"));
// Wipe out the secret keys in LSA, regarding to Internet Connector
DWORD dwStatus = StoreSecretKey(INTERNET_CONNECTOR_LICENSE_STORE,(PBYTE) NULL,0);
if (dwStatus == ERROR_SUCCESS)
{
LOGMESSAGE0(_T("StoreSecretKey succeeded for INTERNET_CONNECTOR_LICENSE_STORE"));
}
else
{
LOGMESSAGE1(_T("StoreSecretKey(INTERNET_CONNECTOR_LICENSE_STORE) failed. Reason %ld"),dwStatus);
}
dwStatus = StoreSecretKey(INTERNET_CONNECTOR_LSERVER_STORE,(PBYTE) NULL,0);
if (dwStatus == ERROR_SUCCESS)
{
LOGMESSAGE0(_T("StoreSecretKey succeeded for INTERNET_CONNECTOR_LSERVER_STORE"));
}
else
{
LOGMESSAGE1(_T("StoreSecretKey(INTERNET_CONNECTOR_LSERVER_STORE) failed. Reason %ld"),dwStatus);
}
dwStatus = StoreSecretKey(INTERNET_CONNECTOR_LSERVER_STORE2,(PBYTE) NULL,0);
if (dwStatus == ERROR_SUCCESS)
{
LOGMESSAGE0(_T("StoreSecretKey succeeded for INTERNET_CONNECTOR_LSERVER_STORE2"));
}
else
{
LOGMESSAGE1(_T("StoreSecretKey(INTERNET_CONNECTOR_LSERVER_STORE2) failed. Reason %ld"),dwStatus);
}
NET_API_STATUS dwNtStatus = NetUserDel(NULL,L"TsInternetUser");
if (dwNtStatus == NERR_Success)
{
LOGMESSAGE0(_T("NetUserDel succeeded for TsInternetUser"));
}
else
{
LOGMESSAGE1(_T("NetUserDel(TsInternetUser) failed. Reason %ld"),dwNtStatus);
}
return FALSE;
}
#define LICENSING_TIME_BOMB_5_0 L"TIMEBOMB_832cc540-3244-11d2-b416-00c04fa30cc4"
#define RTMLICENSING_TIME_BOMB_5_0 L"RTMTSTB_832cc540-3244-11d2-b416-00c04fa30cc4"
BOOL SubCompCoreTS::ResetTermServGracePeriod ()
{
//
// Wipe out the secret keys in LSA for the Win2000 grace period
//
LOGMESSAGE0(_T("Calling StoreSecretKey"));
StoreSecretKey(LICENSING_TIME_BOMB_5_0,(PBYTE) NULL,0);
StoreSecretKey(RTMLICENSING_TIME_BOMB_5_0,(PBYTE) NULL,0);
return TRUE;
}
// Old LSA key names:
#define OLD_PRIVATE_KEY_NAME \
L"HYDRAKEY_28ada6da-d622-11d1-9cb9-00c04fb16e75"
#define OLD_X509_CERT_PRIVATE_KEY_NAME \
L"HYDRAKEY_dd2d98db-2316-11d2-b414-00c04fa30cc4"
#define OLD_X509_CERT_PUBLIC_KEY_NAME \
L"HYDRAPUBLICKEY_dd2d98db-2316-11d2-b414-00c04fa30cc4"
#define OLD_2_PRIVATE_KEY_NAME \
L"HYDRAENCKEY_28ada6da-d622-11d1-9cb9-00c04fb16e75"
#define OLD_2_X509_CERT_PRIVATE_KEY_NAME \
L"HYDRAENCKEY_dd2d98db-2316-11d2-b414-00c04fa30cc4"
#define OLD_2_X509_CERT_PUBLIC_KEY_NAME \
L"HYDRAENCPUBLICKEY_dd2d98db-2316-11d2-b414-00c04fa30cc4"
BOOL SubCompCoreTS::RemoveOldKeys ()
{
//
// Wipe out the secret keys in LSA for the public/private keys
//
LOGMESSAGE0(_T("Calling StoreSecretKey"));
StoreSecretKey(OLD_PRIVATE_KEY_NAME,(PBYTE) NULL,0);
StoreSecretKey(OLD_X509_CERT_PRIVATE_KEY_NAME,(PBYTE) NULL,0);
StoreSecretKey(OLD_X509_CERT_PUBLIC_KEY_NAME,(PBYTE) NULL,0);
StoreSecretKey(OLD_2_PRIVATE_KEY_NAME,(PBYTE) NULL,0);
StoreSecretKey(OLD_2_X509_CERT_PRIVATE_KEY_NAME,(PBYTE) NULL,0);
StoreSecretKey(OLD_2_X509_CERT_PUBLIC_KEY_NAME,(PBYTE) NULL,0);
return TRUE;
}
BOOL SubCompCoreTS::RemoveTSServicePackEntry ()
{
LOGMESSAGE0(_T("will delete terminal service pack uninstall keys."));
CRegistry regUninstallKey;
if (ERROR_SUCCESS != regUninstallKey.OpenKey(HKEY_LOCAL_MACHINE, SOFTWARE_UNINSTALL_KEY))
{
return(TRUE);
}
BOOL bReturn = TRUE;
DWORD dwError;
//
// now try to delete various service pack key.
// if the key does not exist its NOT an error. It means service pack was not installed at all.
//
dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_4_KEY);
if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
{
bReturn = FALSE;
LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_4_KEY, dwError);
}
dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_5_KEY);
if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
{
bReturn = FALSE;
LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_5_KEY, dwError);
}
dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_6_KEY);
if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
{
bReturn = FALSE;
LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_6_KEY, dwError);
}
dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_7_KEY);
if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
{
bReturn = FALSE;
LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_7_KEY, dwError);
}
dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_8_KEY);
if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
{
bReturn = FALSE;
LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_8_KEY, dwError);
}
return bReturn;
}
//
// #386628: we need remove metaframe executables - txlogon.exe and wfshell.exe from userinit key on TS40 upgrades,
// as these apps are broken after upgrade. // what about any other app that are appending value to userinit ? :
// BradG suggested, that we should just wack the reigsty to contain just userinit.
//
BOOL SubCompCoreTS::RemoveMetaframeFromUserinit ()
{
ASSERT( StateObject.IsUpgradeFrom40TS() );
CRegistry reg;
const TCHAR szUserInitKey[] = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon");
const TCHAR szUserInitValue[] = _T("Userinit");
const TCHAR szData[] = _T("userinit");
if (ERROR_SUCCESS == reg.OpenKey(HKEY_LOCAL_MACHINE, szUserInitKey))
{
return (ERROR_SUCCESS == reg.WriteRegString(szUserInitValue, szData));
}
else
{
LOGMESSAGE0(_T("ERROR:Failed to open userinit key"));
}
return FALSE;
}
BOOL SubCompCoreTS::UninstallTSClient ()
{
LPCTSTR SOFTWARE_MSFT = _T("Software\\Microsoft");
LPCTSTR RUNONCE = _T("Windows\\CurrentVersion\\RunOnce");
LPCTSTR TSC_UNINSTALL = _T("tscuninstall");
LPCTSTR TSC_UNINSTALL_CMD = _T("%systemroot%\\system32\\tscupgrd.exe");
CRegistry regAllUsers(HKEY_USERS);
//
// now enumerate through all the uses and Copy settings to new key.
//
DWORD dwSize;
LPTSTR szUser = NULL;
if (ERROR_SUCCESS == regAllUsers.GetFirstSubKey(&szUser, &dwSize))
{
do
{
ASSERT(szUser);
TCHAR szSrcKey[512];
_tcscpy(szSrcKey, szUser);
_tcscat(szSrcKey, _T("\\"));
_tcscat(szSrcKey, SOFTWARE_MSFT);
_tcscat(szSrcKey, _T("\\"));
_tcscat(szSrcKey, RUNONCE);
CRegistry regSrc;
DWORD dwError;
if (ERROR_SUCCESS == (dwError = regSrc.CreateKey(HKEY_USERS, szSrcKey)))
{
if (ERROR_SUCCESS == regSrc.WriteRegExpString(TSC_UNINSTALL, TSC_UNINSTALL_CMD)) {
LOGMESSAGE1(_T("Write TSC uninstall reg value to user %s"), szSrcKey);
}
else {
LOGMESSAGE1(_T("ERROR write TSC uninstall reg value, Lasterror was %d"), GetLastError());
}
}
else {
LOGMESSAGE1(_T("ERROR open user runonce key, Lasterror was %d"), dwError);
}
} while (ERROR_SUCCESS == regAllUsers.GetNextSubKey(&szUser, &dwSize));
}
else {
LOGMESSAGE1(_T("ERROR open user hive"), GetLastError());
}
return TRUE;
}
BOOL SubCompCoreTS::WriteDenyConnectionRegistry ()
{
//
// we need to write this value only for fresh installs, or if its changed.
//
DWORD dwError;
CRegistry oRegTermsrv;
dwError = oRegTermsrv.OpenKey(HKEY_LOCAL_MACHINE, REG_CONTROL_TS_KEY);
if (ERROR_SUCCESS == dwError)
{
DWORD dwDenyConnect = StateObject.GetCurrentConnAllowed() ? 0 : 1;
LOGMESSAGE1(_T("Writing dwDenyConnect = %d"), dwDenyConnect);
dwError = oRegTermsrv.WriteRegDWord(DENY_CONN_VALUE, dwDenyConnect);
if (ERROR_SUCCESS == dwError)
{
if (dwDenyConnect == 0 && StateObject.IsServer())
{
// if we are allowing connections, then we must disble CSC on server machines.
if (!DisableCSC())
{
LOGMESSAGE0(_T("ERROR: failed to disable csc"));
}
}
return TRUE;
}
else
{
LOGMESSAGE2(_T("Error (%d), Writing, %s Value"), dwError, DENY_CONN_VALUE);
return FALSE;
}
}
else
{
LOGMESSAGE2(_T("Error (%d), Opening , %s key"), dwError, REG_CONTROL_TS_KEY);
return FALSE;
}
}
void SubCompCoreTS::IsCSCEnabled()
{
CRegistry oRegCSC;
DWORD dwError = oRegCSC.OpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\NetCache"));
if (ERROR_SUCCESS == dwError)
{
DWORD dwEnabled;
dwError = oRegCSC.ReadRegDWord(_T("Enabled"), &dwEnabled);
if (dwError == ERROR_SUCCESS)
{
LOGMESSAGE1(_T("CSC is %s"), dwEnabled ? _T("enabled") : _T("disabled"));
return;
}
}
LOGMESSAGE1(_T("Error reading CSC/Enabled value"), dwError);
}
bool SubCompCoreTS::DisableCSC()
{
CRegistry oRegCSC;
DWORD dwError = oRegCSC.CreateKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\NetCache"));
if (ERROR_SUCCESS == dwError)
{
dwError = oRegCSC.WriteRegDWord(_T("Enabled"), 0);
if (ERROR_SUCCESS != dwError)
{
LOGMESSAGE1(_T("Error: writing netcache/enabled(%d)"), dwError);
return false;
}
else
{
LOGMESSAGE0(_T("Disabled CSC!"));
}
}
else
{
LOGMESSAGE1(_T("Error: opening netcache registry(%d)"), dwError);
return false;
}
return true;
}
LPCTSTR SERVICES_TERMDD_KEY = _T("SYSTEM\\CurrentControlSet\\Services\\TermDD");
void SubCompCoreTS::SetConsoleShadowInstalled (BOOL bInstalled)
{
// ; HKLM, "SYSTEM\CurrentControlSet\Services\TermDD", "PortDriverEnable", 0x00010001, 0x1
CRegistry Reg;
if (ERROR_SUCCESS == Reg.CreateKey(HKEY_LOCAL_MACHINE, SERVICES_TERMDD_KEY))
{
if (ERROR_SUCCESS != Reg.WriteRegDWord(_T("PortDriverEnable"), bInstalled ? 1 : 0))
{
LOGMESSAGE0(_T("ERROR, Failed to write to PortDriverEnable"));
}
}
else
{
LOGMESSAGE1(_T("ERROR, Failed to Create/Open %s"), SERVICES_TERMDD_KEY);
}
}
BOOL SubCompCoreTS::IsConsoleShadowInstalled ()
{
// ; HKLM, "SYSTEM\CurrentControlSet\Services\TermDD", "PortDriverEnable", 0x00010001, 0x1
CRegistry Reg;
if (ERROR_SUCCESS == Reg.OpenKey(HKEY_LOCAL_MACHINE, SERVICES_TERMDD_KEY))
{
DWORD dwPortDriverEnable;
if (ERROR_SUCCESS == Reg.ReadRegDWord(_T("PortDriverEnable"), &dwPortDriverEnable))
{
return (dwPortDriverEnable == 1);
}
else
{
LOGMESSAGE0(_T("Failed to read from PortDriverEnable, Maybe Console Shadow is not installed yet."));
}
}
else
{
LOGMESSAGE1(_T("ERROR, Failed to Open %s"), SERVICES_TERMDD_KEY);
}
return FALSE;
}
#ifdef TSOC_CONSOLE_SHADOWING
BOOL SubCompCoreTS::SetupConsoleShadow ()
{
if (IsConsoleShadowInstalled () == StateObject.IsTSEnableSelected())
{
return TRUE;
}
if (StateObject.IsTSEnableSelected())
{
LOGMESSAGE0(_T("Installing RDP Keyboard/Mouse drivers!"));
//
// this code is new to install Mouse Device for console shadowing.
//
if (!RDPDRINST_GUIModeSetupInstall(NULL, RDPMOUPNPID, RDPMOUDEVICEID))
{
LOGMESSAGE0(_T("ERROR:Could not create mouse devnode"));
}
//
// this code is new to install Kbd Device for console shadowing.
//
if (!RDPDRINST_GUIModeSetupInstall(NULL, RDPKBDPNPID, RDPKBDDEVICEID))
{
LOGMESSAGE0(_T("ERROR:Could not create kbd devnode"));
}
//
// this code is new to install RDPCDD chained driver
//
/*
TCHAR szInfFile[MAX_PATH];
ExpandEnvironmentStrings(szRDPCDDInfFile, szInfFile, MAX_PATH);
LOGMESSAGE1(_T("Inf file for RDPCDD is %s"), szInfFile);
BOOL bRebootRequired = TRUE;
if (NO_ERROR != InstallRootEnumeratedDevice( NULL, szRDPCDDDeviceName, szRDPCDDHardwareID, szInfFile, &bRebootRequired))
{
LOGMESSAGE0(_T("InstallRootEnumeratedDevice failed"));
}
*/
}
else
{
GUID *pGuid=(GUID *)&GUID_DEVCLASS_SYSTEM;
if (!RDPDRINST_GUIModeSetupUninstall(NULL, RDPMOUPNPID, pGuid))
{
LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupUninstall failed for RDP Mouse device"));
}
pGuid=(GUID *)&GUID_DEVCLASS_SYSTEM;
if (!RDPDRINST_GUIModeSetupUninstall(NULL, RDPKBDPNPID, pGuid))
{
LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupUninstall failed for RDP KBD device"));
}
/*
pGuid=(GUID *)&GUID_DEVCLASS_DISPLAY;
if (!RDPDRINST_GUIModeSetupUninstall(NULL, (WCHAR *)T2W(szRDPCDDHardwareID), pGuid)) {
LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupUninstall failed for Chained Display device"));
}
*/
CRegistry Reg;
if (ERROR_SUCCESS == Reg.OpenKey(HKEY_LOCAL_MACHINE, SERVICES_TERMDD_KEY))
{
if (ERROR_SUCCESS != Reg.WriteRegDWord(_T("Start"), 4))
{
LOGMESSAGE0(_T("ERROR, Failed to write to TermDD\\Start"));
}
}
else
{
LOGMESSAGE1(_T("ERROR, Failed to Open %s"), SERVICES_TERMDD_KEY);
}
}
SetConsoleShadowInstalled( StateObject.IsTSEnableSelected() );
return( TRUE );
}
#endif // TSOC_CONSOLE_SHADOWING
DWORD SubCompCoreTS::LoadOrUnloadPerf ()
{
BOOL bLoad = StateObject.IsTSEnableSelected();
LPCTSTR TERMSRV_SERVICE_PATH = _T("SYSTEM\\CurrentControlSet\\Services\\TermService");
LPCTSTR TERMSRV_PERF_NAME = _T("Performance");
LPCTSTR TERMSRV_PERF_COUNTERS = _T("SYSTEM\\CurrentControlSet\\Services\\TermService\\Performance");
LPCTSTR TERMSRV_PERF_COUNTERS_FIRST_COUNTER = _T("First Counter");
LPCTSTR TERMSRV_PERF_COUNTERS_LAST_COUNTER = _T("Last Counter");
LPCTSTR TERMSRV_PERF_COUNTERS_FIRST_HELP = _T("First Help");
LPCTSTR TERMSRV_PERF_COUNTERS_LAST_HELP = _T("Last Help");
LPCTSTR TERMSRV_PERF_COUNTERS_LIBRARY = _T("Library");
LPCTSTR TERMSRV_PERF_COUNTERS_LIBRARY_VALUE = _T("perfts.dll");
LPCTSTR TERMSRV_PERF_CLOSE = _T("Close");
LPCTSTR TERMSRV_PERF_CLOSE_VALUE = _T("CloseTSObject");
LPCTSTR TERMSRV_PERF_COLLECT_TIMEOUT = _T("Collect Timeout");
const DWORD TERMSRV_PERF_COLLECT_TIMEOUT_VALUE = 1000;
LPCTSTR TERMSRV_PERF_COLLECT = _T("Collect");
LPCTSTR TERMSRV_PERF_COLLECT_VALUE = _T("CollectTSObjectData");
LPCTSTR TERMSRV_PERF_OPEN_TIMEOUT = _T("Open Timeout");
const DWORD TERMSRV_PERF_OPEN_TIMEOUT_VALUE = 1000;
LPCTSTR TERMSRV_PERF_OPEN = _T("Open");
LPCTSTR TERMSRV_PERF_OPEN_VALUE = _T("OpenTSObject");
TCHAR PerfArg[MAX_PATH + 10];
CRegistry reg;
DWORD RetVal;
LOGMESSAGE1(_T("Entered LoadOrUnloadPerfCounters, load=%u"), bLoad);
if (bLoad)
{
//
// As a first step to installing, first clean out any existing
// entries by unloading the counters
//
LOGMESSAGE0(_T("Unloading counters before install"));
UnloadPerf();
RetVal = reg.CreateKey(HKEY_LOCAL_MACHINE, TERMSRV_PERF_COUNTERS);
if (RetVal == ERROR_SUCCESS)
{
TCHAR SystemDir[MAX_PATH];
// On load we create and populate the entire Performance key.
// This key must not be present when we are unloaded because
// the WMI provider enumerates service performance DLLs
// according to the presence of the Perf key. If it is present
// but not fully filled in then an error log is generated.
if (GetSystemDirectory(SystemDir, MAX_PATH))
{
// Just in case they are present, delete the counter number
// entries to make sure we regenerate them correctly below.
reg.DeleteValue(TERMSRV_PERF_COUNTERS_FIRST_COUNTER);
reg.DeleteValue(TERMSRV_PERF_COUNTERS_LAST_COUNTER);
reg.DeleteValue(TERMSRV_PERF_COUNTERS_FIRST_HELP);
reg.DeleteValue(TERMSRV_PERF_COUNTERS_LAST_HELP);
// Generate the static values.
reg.WriteRegString(TERMSRV_PERF_CLOSE, TERMSRV_PERF_CLOSE_VALUE);
reg.WriteRegDWord(TERMSRV_PERF_COLLECT_TIMEOUT, TERMSRV_PERF_COLLECT_TIMEOUT_VALUE);
reg.WriteRegString(TERMSRV_PERF_COLLECT, TERMSRV_PERF_COLLECT_VALUE);
reg.WriteRegDWord(TERMSRV_PERF_OPEN_TIMEOUT, TERMSRV_PERF_OPEN_TIMEOUT_VALUE);
reg.WriteRegString(TERMSRV_PERF_OPEN, TERMSRV_PERF_OPEN_VALUE);
reg.WriteRegString(TERMSRV_PERF_COUNTERS_LIBRARY, TERMSRV_PERF_COUNTERS_LIBRARY_VALUE);
_stprintf(PerfArg, _T("%s %s\\%s"), _T("lodctr"), SystemDir, _T("tslabels.ini"));
LOGMESSAGE1(_T("Arg is %s"), PerfArg);
return DWORD(LoadPerfCounterTextStrings(PerfArg, FALSE));
}
else
{
unsigned LastErr = GetLastError();
LOGMESSAGE1(_T("GetSystemDirectory Failure is %ld"), LastErr);
return LastErr;
}
}
else
{
LOGMESSAGE1(_T("Perf regkey create failure, err=%ld"), RetVal);
return RetVal;
}
}
else
{
return UnloadPerf();
}
}
//
// Unload perf ctrs
//
DWORD SubCompCoreTS::UnloadPerf()
{
TCHAR PerfArg[MAX_PATH + 10];
CRegistry reg;
DWORD RetVal;
LPCTSTR TERMSRV_SERVICE_PATH = _T("SYSTEM\\CurrentControlSet\\Services\\TermService");
LPCTSTR TERMSRV_PERF_NAME = _T("Performance");
// On unload, first unload the counters we should have in the system.
_stprintf(PerfArg, _T("%s %s"), _T("unlodctr"), _T("TermService"));
LOGMESSAGE1(_T("Arg is %s"), PerfArg);
UnloadPerfCounterTextStrings(PerfArg, FALSE);
// Delete the entire Performance key and all its descendants. We have
// to first open the ancestor key (TermService).
RetVal = reg.OpenKey(HKEY_LOCAL_MACHINE, TERMSRV_SERVICE_PATH);
if (RetVal == ERROR_SUCCESS)
{
RetVal = reg.RecurseDeleteKey(TERMSRV_PERF_NAME);
if (RetVal != ERROR_SUCCESS)
{
LOGMESSAGE1(_T("ERROR deleting Performance key: %ld"), RetVal);
}
}
else
{
LOGMESSAGE1(_T("Err opening Performance key, err=%ld"), RetVal);
}
return RetVal;
}
void SubCompCoreTS::AddRDPNP(LPTSTR szOldValue, LPTSTR szNewValue)
{
TCHAR RDPNP_ENTRY[] = _T("RDPNP");
const TCHAR SZ_SEP[] = _T(" \t");
//
// We are adding our rdpnp entry to the beginning of the list
//
// we dont want to add comma if original value is empty.
//
if (_tcslen(szOldValue) != 0 && _tcstok(szOldValue, SZ_SEP))
{
_tcscpy(szNewValue, RDPNP_ENTRY);
_tcscat(szNewValue, _T(","));
_tcscat(szNewValue, szOldValue);
}
else {
_tcscpy(szNewValue, RDPNP_ENTRY);
}
}
void SubCompCoreTS::RemoveRDPNP(LPTSTR szOldValue, LPTSTR szNewValue)
{
TCHAR RDPNP_ENTRY[] = _T("RDPNP");
//
// this is little complicated,
// we need to remove RDPNP from , seperated list.
//
// so lets get tokens.
//
TCHAR *szToken = NULL;
const TCHAR SZ_SEP[] = _T(",");
_tcscpy(szNewValue, _T(""));
szToken = _tcstok(szOldValue, SZ_SEP);
BOOL bFirstPass = TRUE;
while (szToken)
{
// if the token is RDPNP, skip it.
if (_tcsstr(szToken, RDPNP_ENTRY) == 0)
{
if (!bFirstPass)
{
_tcscat(szNewValue, _T(","));
}
_tcscat(szNewValue, szToken);
bFirstPass = FALSE;
}
szToken = _tcstok(NULL, SZ_SEP);
}
}
BOOL SubCompCoreTS::AddRemoveRDPNP ()
{
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order
BOOL bAdd = StateObject.IsTSEnableSelected();
TCHAR NEWORK_PROVIDER_ORDER_KEY[] = _T("SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order");
TCHAR PROVIDER_ORDER_VALUE[] = _T("ProviderOrder");
TCHAR RDPNP_ENTRY[] = _T("RDPNP");
CRegistry regNetOrder;
if (ERROR_SUCCESS == regNetOrder.OpenKey(HKEY_LOCAL_MACHINE, NEWORK_PROVIDER_ORDER_KEY))
{
LPTSTR szOldValue;
DWORD dwSize;
if (ERROR_SUCCESS == regNetOrder.ReadRegString(PROVIDER_ORDER_VALUE, &szOldValue, &dwSize))
{
//
// now we want to add or remove RDPNP_ENTRY depending on we are enabled or disabled.
//
BOOL bRdpNpExists = (_tcsstr(szOldValue, RDPNP_ENTRY) != NULL);
if (bAdd == bRdpNpExists)
{
TCHAR szNewValue[256];
//
// already exists.
//
LOGMESSAGE0(_T("AddRemoveRDPNP, no change required."));
//
// Need to move to the right location
//
RemoveRDPNP(szOldValue, szNewValue);
_tcscpy(szOldValue, szNewValue);
AddRDPNP(szOldValue, szNewValue);
if (ERROR_SUCCESS != regNetOrder.WriteRegString(PROVIDER_ORDER_VALUE, szNewValue))
{
LOGMESSAGE2(_T("ERROR, Writing %s to %s"), szNewValue, PROVIDER_ORDER_VALUE);
}
}
else
{
TCHAR szNewValue[256];
if (bAdd)
{
//
// We are adding our rdpnp entry to the beginning of the list
//
AddRDPNP(szOldValue, szNewValue);
}
else
{
//
// this is little complicated,
// we need to remove RDPNP from , seperated list.
//
RemoveRDPNP(szOldValue, szNewValue);
}
if (ERROR_SUCCESS != regNetOrder.WriteRegString(PROVIDER_ORDER_VALUE, szNewValue))
{
LOGMESSAGE2(_T("ERROR, Writing %s to %s"), szNewValue, PROVIDER_ORDER_VALUE);
}
}
}
else
{
LOGMESSAGE1(_T("ERROR, Reading %s"), PROVIDER_ORDER_VALUE);
return FALSE;
}
}
else
{
LOGMESSAGE1(_T("ERROR, Opening %s"), NEWORK_PROVIDER_ORDER_KEY);
return FALSE;
}
return TRUE;
}
/*
bool SubCompCoreTS::InstallTermdd ()
{
// first check if termdd is installed.
bool bInstalledAlready = false;
CRegistry oRegTermsrv;
DWORD dwError = oRegTermsrv.OpenKey(HKEY_LOCAL_MACHINE,
_T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server"));
if (dwError == STATUS_SUCCESS)
{
DWORD dwTermddInstalled;
if (STATUS_SUCCESS == oRegTermsrv.ReadRegDWord(_T("TermddInstalled"), &dwTermddInstalled))
{
bInstalledAlready = (dwTermddInstalled != 0);
}
}
if (!bInstalledAlready)
{
LOGMESSAGE0(_T("Installing TERMDD"));
if (RDPDRINST_GUIModeSetupInstall(NULL, TERMDDPNPID, TERMDDDEVICEID))
{
LOGMESSAGE0(_T("RDPDRINST_GUIModeSetupInstall succeeded for TERMDD"));
oRegTermsrv.WriteRegDWord(_T("TermddInstalled"), 1);
}
else
{
LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupInstall failed for TERMDD"));
return false;
}
}
else
{
LOGMESSAGE0(_T("ERROR:termdd is already installed."));
return false;
}
return true;
}
*/
BOOL SubCompCoreTS::InstallUninstallRdpDr ()
{
//
// This code shouldn't run on Personal. Device redirection isn't
// supported for Personal.
//
if (StateObject.IsPersonal()) {
return TRUE;
}
//
// Installing RDPDR over itself is bad. Hence, only (un)install on
// a state change or an upgrade from TS40, but don't do unnecessary
// uninstalls. These are when coming from TS40, but using an unattended
// file to turn TS off. Therefore, RDPDR installation is the XOR of
// HasStateChanged() and IsUpgradeFromTS40().
//
// if state has changed.
if (StateObject.IsUpgradeFrom40TS() || (StateObject.WasTSEnabled() != StateObject.IsTSEnableSelected())
|| !IsRDPDrInstalled() ) // last case checks for Personal -> Pro upgrades, we want to instsall rdpdr in those cases.
{
if (StateObject.IsTSEnableSelected())
{
LOGMESSAGE0(_T("Installing RDPDR"));
if (!RDPDRINST_GUIModeSetupInstall(NULL, RDPDRPNPID, RDPDRDEVICEID))
{
LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupInstall failed"));
}
}
else
{
LOGMESSAGE0(_T("Uninstalling RDPDR"));
GUID *pGuid=(GUID *)&GUID_DEVCLASS_SYSTEM;
if (!RDPDRINST_GUIModeSetupUninstall(NULL, RDPDRPNPID, pGuid))
{
LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupUninstall failed"));
}
}
}
return TRUE;
}
BOOL SubCompCoreTS::HandleHotkey ()
{
if (StateObject.IsTSEnableSelected())
{
CRegistry pRegToggle;
//
// Install Hotkey if not exist key value in HKU/.Default/Keyboard Layout/Toggle!Hotkey
//
#define REG_TOGGLE_KEY _T(".Default\\Keyboard Layout\\Toggle")
#define REG_HOT_KEY _T("Hotkey")
#define DEFAULT_HOT_KEY _T("1")
DWORD dwRet;
dwRet = pRegToggle.CreateKey(HKEY_USERS, REG_TOGGLE_KEY);
if (dwRet == ERROR_SUCCESS)
{
LPTSTR pszHotkey;
DWORD cbSize;
dwRet = pRegToggle.ReadRegString(REG_HOT_KEY, &pszHotkey, &cbSize);
if (dwRet != ERROR_SUCCESS)
{
dwRet = pRegToggle.WriteRegString(REG_HOT_KEY, DEFAULT_HOT_KEY);
if (dwRet != ERROR_SUCCESS)
{
LOGMESSAGE2(_T("ERROR:CRegistry::WriteRegString (%s=%s)"), REG_HOT_KEY, DEFAULT_HOT_KEY);
}
}
}
else
{
LOGMESSAGE1(_T("ERROR:CRegistry::CreateKey (%s)"), REG_TOGGLE_KEY);
}
}
return TRUE;
}
/*
* UpdateAudioCodecs - populates all audio codecs for RDP session
*/
#define DRIVERS32 _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32")
#define RDPDRV ( DRIVERS32 _T("\\Terminal Server\\RDP") )
#ifdef _WIN64
#define RDPDRVWOW64 _T("SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32\\Terminal Server\\RDP")
#endif // _WIN64
BOOL UpdateAudioCodecs (BOOL bIsProfessional)
{
BOOL rv = TRUE;
LPTSTR szBuff;
DWORD status;
CRegistry regKey;
CRegistry regDestKey;
DWORD size;
#ifdef _WIN64
CRegistry regWow64;
#endif // _WIN64
//
// copy keys from
// HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32
// wavemapper
// midimapper
// EnableMP3Codec (Professional only)
//
status = regKey.OpenKey(
HKEY_LOCAL_MACHINE,
DRIVERS32
);
if ( ERROR_SUCCESS != status )
goto exitpt;
//
// Create the destination
//
status = regDestKey.CreateKey(
HKEY_LOCAL_MACHINE,
RDPDRV
);
if ( ERROR_SUCCESS != status )
goto exitpt;
//
// query for wavemapper
//
status = regKey.ReadRegString(
_T("wavemapper"),
&szBuff,
&size
);
if ( ERROR_SUCCESS != status )
goto exitpt;
status = regDestKey.WriteRegString(
_T("wavemapper"),
szBuff
);
if ( ERROR_SUCCESS != status )
goto exitpt;
if ( bIsProfessional )
{
status = regDestKey.WriteRegDWord(
_T("EnableMP3Codec"),
1
);
if ( ERROR_SUCCESS != status )
goto exitpt;
}
//
// query for midimapper
//
status = regKey.ReadRegString(
_T("midimapper"),
&szBuff,
&size
);
if ( ERROR_SUCCESS != status )
goto exitpt;
status = regDestKey.WriteRegString(
_T("midimapper"),
szBuff
);
if ( ERROR_SUCCESS != status )
goto exitpt;
#ifdef _WIN64
//
// Populate the wow64 keys
//
status = regWow64.CreateKey(
HKEY_LOCAL_MACHINE,
RDPDRVWOW64
);
if ( ERROR_SUCCESS != status )
{
goto exitpt;
}
status = regDestKey.ReadRegString(
_T("wavemapper"),
&szBuff,
&size
);
if ( ERROR_SUCCESS != status )
{
goto exitpt;
}
status = regWow64.WriteRegString(
_T("wavemapper"),
szBuff
);
if ( ERROR_SUCCESS != status )
{
goto exitpt;
}
status = regDestKey.ReadRegString(
_T("midimapper"),
&szBuff,
&size
);
if ( ERROR_SUCCESS != status )
{
goto exitpt;
}
status = regWow64.WriteRegString(
_T("midimapper"),
szBuff
);
if ( ERROR_SUCCESS != status )
{
goto exitpt;
}
status = regDestKey.ReadRegString(
_T("wave"),
&szBuff,
&size
);
if ( ERROR_SUCCESS != status )
{
goto exitpt;
}
status = regWow64.WriteRegString(
_T("wave"),
szBuff
);
if ( ERROR_SUCCESS != status )
{
goto exitpt;
}
#endif // _WIN64
rv = TRUE;
exitpt:
return rv;
}