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.
2072 lines
61 KiB
2072 lines
61 KiB
//
|
|
//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(®SubKey))
|
|
{
|
|
LOGMESSAGE1(_T("Updating Winstation - %s"), lpStr);
|
|
UpdateRDPWinstation(®SubKey, lpStr);
|
|
VerifyLanAdapters(®SubKey, lpStr);
|
|
}
|
|
else if (IsMetaFrameWinstation(®SubKey))
|
|
{
|
|
LOGMESSAGE1(_T("Disabling winstaion - %s"), lpStr);
|
|
DisableWinStation(®SubKey);
|
|
VerifyLanAdapters(®SubKey, 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(®, 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;
|
|
}
|