// //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; }