Leaked source code of windows server 2003
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

  1. //
  2. //Copyright (c) 1998 - 1999 Microsoft Corporation
  3. //
  4. //
  5. // SubCore.cpp
  6. // subcomponent Core terminal server implementation.
  7. //
  8. #include "stdafx.h"
  9. #include "SubCore.h"
  10. #include "acl.h"
  11. #include "rdpdrstp.h"
  12. BOOL UpdateAudioCodecs (BOOL bIsProfessional);
  13. LPCTSTR SubCompCoreTS::GetSubCompID () const
  14. {
  15. return BASE_COMPONENT_NAME;
  16. }
  17. DWORD SubCompCoreTS::GetStepCount () const
  18. {
  19. return 18;
  20. }
  21. DWORD SubCompCoreTS::OnQueryState ( UINT /* uiWhichState */)
  22. {
  23. AssertFalse(); // since this is our internal component.
  24. return SubcompUseOcManagerDefault;
  25. }
  26. DWORD SubCompCoreTS::OnQuerySelStateChange (BOOL /*bNewState*/, BOOL /*bDirectSelection*/) const
  27. {
  28. // we are not a real sub comp.
  29. ASSERT(FALSE);
  30. return TRUE;
  31. }
  32. LPCTSTR SubCompCoreTS::GetSectionToBeProcessed (ESections /* eSection */) const
  33. {
  34. LPCTSTR sectionname = NULL;
  35. if (StateObject.IsGuiModeSetup()) // core installation is only for gui-mode.
  36. {
  37. ETSInstallType eInstallType = StateObject.GetInstalltype();
  38. switch (eInstallType)
  39. {
  40. case eFreshInstallTS:
  41. if (StateObject.IsX86())
  42. {
  43. sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_X86 : FRESH_INSTALL_SERVER_X86;
  44. }
  45. else
  46. {
  47. if (StateObject.IsAMD64())
  48. {
  49. sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_AMD64 : FRESH_INSTALL_SERVER_AMD64;
  50. }
  51. else
  52. {
  53. sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_IA64 : FRESH_INSTALL_SERVER_IA64;
  54. }
  55. }
  56. break;
  57. case eUpgradeFrom40TS:
  58. ASSERT(StateObject.IsServer());
  59. if (StateObject.IsX86())
  60. {
  61. sectionname = UPGRADE_FROM_40_SERVER_X86;
  62. }
  63. else
  64. {
  65. ASSERT(FALSE); // we did not have ts4 on ia64
  66. sectionname = UPGRADE_FROM_40_SERVER_IA64;
  67. }
  68. break;
  69. case eUpgradeFrom50TS:
  70. //
  71. // we dont really have a upgrade from 50 case for Professional, But to support old 51 (pre 2220) builds)
  72. // of pro which think that they are 50, we need to check for professional here.
  73. //
  74. if (StateObject.IsX86())
  75. {
  76. sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_51_PRO_X86 : UPGRADE_FROM_50_SERVER_X86;
  77. }
  78. else
  79. {
  80. sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_51_PRO_IA64 : UPGRADE_FROM_50_SERVER_IA64;
  81. }
  82. break;
  83. case eUpgradeFrom51TS:
  84. if (StateObject.IsX86())
  85. {
  86. sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_51_PRO_X86 : UPGRADE_FROM_51_SERVER_X86;
  87. }
  88. else
  89. {
  90. sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_51_PRO_IA64 : UPGRADE_FROM_51_SERVER_IA64;
  91. }
  92. break;
  93. case eUpgradeFrom52TS:
  94. if (StateObject.IsX86())
  95. {
  96. sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_52_PRO_X86 : UPGRADE_FROM_52_SERVER_X86;
  97. }
  98. else
  99. {
  100. if (StateObject.IsAMD64()) {
  101. sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_52_PRO_AMD64 : UPGRADE_FROM_52_SERVER_AMD64;
  102. }
  103. else
  104. {
  105. sectionname = StateObject.IsWorkstation() ? UPGRADE_FROM_52_PRO_IA64 : UPGRADE_FROM_52_SERVER_IA64;
  106. }
  107. }
  108. break;
  109. case eStandAloneSetup:
  110. ASSERT(FALSE);
  111. sectionname = NULL;
  112. break;
  113. default:
  114. ASSERT(FALSE);
  115. if (StateObject.IsX86())
  116. {
  117. sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_X86 : FRESH_INSTALL_SERVER_X86;
  118. }
  119. else
  120. {
  121. if (StateObject.IsAMD64())
  122. {
  123. sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_AMD64 : FRESH_INSTALL_SERVER_AMD64;
  124. }
  125. else
  126. {
  127. sectionname = StateObject.IsWorkstation() ? FRESH_INSTALL_PRO_IA64 : FRESH_INSTALL_SERVER_IA64;
  128. }
  129. }
  130. }
  131. }
  132. return sectionname;
  133. }
  134. BOOL SubCompCoreTS::BeforeCompleteInstall ()
  135. {
  136. IsCSCEnabled();
  137. return(TRUE);
  138. }
  139. BOOL SubCompCoreTS::AfterCompleteInstall ()
  140. {
  141. IsCSCEnabled();
  142. //
  143. // This is core TS subcomponent.
  144. // It has nothing to do with standalone seutp.
  145. // so if we are in standalone setup. just return.
  146. //
  147. //
  148. // Deny Connections registry
  149. //
  150. WriteDenyConnectionRegistry ();
  151. Tick();
  152. if (!StateObject.IsGuiModeSetup())
  153. {
  154. return TRUE;
  155. }
  156. SetProgressText(IDS_STRING_PROGRESS_CORE_TS);
  157. //
  158. // add ts product suite to registry.
  159. //
  160. AddRemoveTSProductSuite();
  161. Tick();
  162. #ifndef TERMSRV_PROC
  163. //
  164. // add termsrv to netsvcs group.
  165. //
  166. AddTermSrvToNetSVCS ();
  167. Tick();
  168. #endif
  169. //
  170. // apply hydra security to registry.
  171. //
  172. DoHydraRegistrySecurityChanges();
  173. Tick();
  174. //
  175. // Audio Redirection
  176. //
  177. UpdateAudioCodecs( StateObject.IsWorkstation() );
  178. Tick();
  179. //
  180. // Client Drive Mappings.
  181. //
  182. AddRemoveRDPNP();
  183. Tick();
  184. //
  185. // Hot key for Local Language change.
  186. //
  187. // We dont need to do this.
  188. // HandleHotkey ();
  189. // Tick();
  190. //
  191. // Printer Redirection.
  192. //
  193. InstallUninstallRdpDr ();
  194. Tick();
  195. #ifdef TSOC_CONSOLE_SHADOWING
  196. //
  197. // Console Shadowing.
  198. //
  199. SetupConsoleShadow();
  200. Tick();
  201. #endif // TSOC_CONSOLE_SHADOWING
  202. //InstallTermdd();
  203. //Tick();
  204. //
  205. // Performance monitors for TS. BUGBUG - check with ErikMa - do they work when TS is not started ?
  206. //
  207. LoadOrUnloadPerf();
  208. Tick();
  209. //
  210. // If this were a real subcomponent, one that the OC manager knew
  211. // about and handled, the following call would be to
  212. // GetOriginalSubCompState().
  213. //
  214. if (StateObject.WasTSInstalled())
  215. {
  216. UpgradeRdpWinstations();
  217. Tick();
  218. //
  219. // This no longer exists in Whistler
  220. //
  221. DisableInternetConnector();
  222. Tick();
  223. if (StateObject.IsUpgradeFrom40TS())
  224. {
  225. //
  226. // this is upgrade from TS4
  227. // we want to remove service pack key in uninstall. this is to
  228. // ensure that service pack do not appear in Add/Remove Programs
  229. // and in our incompatible applications list.
  230. //
  231. RemoveTSServicePackEntry();
  232. Tick();
  233. //
  234. // There are some metaframe components in user init,
  235. // we need to remove thouse as we upgrade ts40
  236. //
  237. RemoveMetaframeFromUserinit ();
  238. Tick();
  239. }
  240. //
  241. // we need to reset Win2000 ts grace period for licenses on upgrades
  242. // Whistler uses a different location, so this won't affect RTM to
  243. // RTM upgrades
  244. //
  245. ResetTermServGracePeriod();
  246. Tick();
  247. //
  248. // Delete old LSA secrets used by public/private keys
  249. //
  250. RemoveOldKeys();
  251. Tick();
  252. }
  253. // some new code to uninstall TSClient.
  254. if (!UninstallTSClient())
  255. {
  256. LOGMESSAGE0(_T("ERROR: Could not uninstall tsclient."));
  257. }
  258. IsCSCEnabled();
  259. Tick();
  260. return TRUE;
  261. }
  262. BOOL SubCompCoreTS::IsTermSrvInNetSVCS ()
  263. {
  264. BOOL bStringExists = FALSE;
  265. DWORD dw = IsStringInMultiString(
  266. HKEY_LOCAL_MACHINE,
  267. SVCHOSST_KEY,
  268. NETSVCS_VAL,
  269. TERMSERVICE,
  270. &bStringExists);
  271. return (dw == ERROR_SUCCESS) && bStringExists;
  272. }
  273. BOOL SubCompCoreTS::AddTermSrvToNetSVCS ()
  274. {
  275. DWORD dw = NO_ERROR;
  276. if (StateObject.IsWorkstation())
  277. {
  278. //
  279. // for workstations, we want to share process with netsvcs group
  280. //
  281. if (!IsTermSrvInNetSVCS())
  282. {
  283. dw = AppendStringToMultiString(
  284. HKEY_LOCAL_MACHINE,
  285. SVCHOSST_KEY,
  286. NETSVCS_VAL,
  287. TERMSERVICE
  288. );
  289. if (dw != NO_ERROR)
  290. {
  291. LOGMESSAGE1(_T("Error, appending TermService to netsvcs, Errorcode = %u"), dw);
  292. }
  293. }
  294. }
  295. //
  296. // for servers we want to have our own svchost for termsrv.
  297. // lets create the necessary entries for pro as well, so that for debugging termsrv it'll be easier to switch to own svchost.
  298. //
  299. {
  300. //
  301. // for servers we want to have our own svchost process.
  302. //
  303. CRegistry oReg;
  304. dw = oReg.OpenKey(HKEY_LOCAL_MACHINE, SVCHOSST_KEY);
  305. if (ERROR_SUCCESS == dw)
  306. {
  307. dw = oReg.WriteRegMultiString(TERMSVCS_VAL, TERMSERVICE_MULTISZ, (_tcslen(TERMSERVICE) + 2) * sizeof(TCHAR));
  308. if (ERROR_SUCCESS == dw)
  309. {
  310. // add CoInitializeSecurityParam, so that CoInitialize gets called in main thread for this svc group.
  311. CRegistry termsvcKey;
  312. dw = termsvcKey.CreateKey(HKEY_LOCAL_MACHINE, SVCHOSST_TERMSRV_KEY );
  313. if (ERROR_SUCCESS == dw)
  314. {
  315. dw = termsvcKey.WriteRegDWord(TERMSVCS_PARMS, 1);
  316. if (ERROR_SUCCESS != dw)
  317. {
  318. LOGMESSAGE1(_T("Failed to write termsvc coinit params, Error = %d"), dw);
  319. }
  320. }
  321. else
  322. {
  323. LOGMESSAGE1(_T("Error, Failed to create svchost\termsrv key, Error = %d"), dw);
  324. }
  325. }
  326. else
  327. {
  328. LOGMESSAGE1(_T("Error, Writing termsrv value, Error = %d"), dw);
  329. }
  330. }
  331. else
  332. {
  333. LOGMESSAGE1(_T("Error, Opening Svchost key, Error = %d"), dw);
  334. }
  335. }
  336. return dw == NO_ERROR;
  337. }
  338. /*--------------------------------------------------------------------------------------------------------
  339. * DWORD AddRemoveTSProductSuite (BOOL bAddRemove)
  340. * does the necessary changes for installing hydra specific registry keys which are not done from inf.
  341. * parameter state decides if key is to be added or removed.
  342. * returns success
  343. * -------------------------------------------------------------------------------------------------------*/
  344. BOOL SubCompCoreTS::AddRemoveTSProductSuite ()
  345. {
  346. //
  347. // add product suite key only for servers.
  348. // This is required only for TS4 compatibility.
  349. // TS4 applications detect if machine is terminal server using this key.
  350. //
  351. DWORD dw = NO_ERROR;
  352. if (StateObject.IsServer())
  353. {
  354. // installing/upgrading.
  355. if (!DoesHydraKeysExists())
  356. {
  357. ASSERT(FALSE == StateObject.WasTSInstalled());
  358. // now read the original data in this product suite value.
  359. dw = AppendStringToMultiString(
  360. HKEY_LOCAL_MACHINE,
  361. PRODUCT_SUITE_KEY,
  362. PRODUCT_SUITE_VALUE,
  363. TS_PRODUCT_SUITE_STRING
  364. );
  365. if (dw != NO_ERROR)
  366. LOGMESSAGE1(_T("ERROR:DoHydraRegistryChanges : Error Appending String = <%lu>"), dw);
  367. }
  368. }
  369. dw = SetTSVersion(TERMINAL_SERVER_THIS_VERSION);
  370. if (ERROR_SUCCESS != dw)
  371. {
  372. LOGMESSAGE1(_T("ERROR, Setting TS version, ErrorCode = %u "), dw);
  373. }
  374. return dw == NO_ERROR;
  375. }
  376. BOOL SubCompCoreTS::DisableWinStation (CRegistry *pRegWinstation)
  377. {
  378. ASSERT(pRegWinstation);
  379. #ifdef DBG
  380. // the value must be there already.
  381. DWORD dwValue;
  382. ASSERT(ERROR_SUCCESS == pRegWinstation->ReadRegDWord(_T("fEnableWinStation"), &dwValue));
  383. #endif
  384. VERIFY(ERROR_SUCCESS == pRegWinstation->WriteRegDWord(_T("fEnableWinStation"), 0));
  385. return TRUE;
  386. }
  387. BOOL SubCompCoreTS::DoesLanaTableExist ()
  388. {
  389. static fValueDetermined = FALSE;
  390. static fRet;
  391. if (fValueDetermined)
  392. {
  393. return(fRet);
  394. }
  395. else
  396. {
  397. CRegistry Reg;
  398. fRet = Reg.OpenKey(HKEY_LOCAL_MACHINE, TS_LANATABLE_KEY) == ERROR_SUCCESS;
  399. fValueDetermined = TRUE;
  400. LOGMESSAGE1(_T("DoesLanaTableExist: %s"), fRet ? _T("Yes") : _T("No"));
  401. return(fRet);
  402. }
  403. }
  404. void SubCompCoreTS::VerifyLanAdapters (CRegistry *pRegWinstation, LPTSTR pszWinstation)
  405. {
  406. DWORD dwLana = 0;
  407. static BOOL fErrorLogged = FALSE;
  408. LOGMESSAGE1(_T("Verifying lan adapters for %s"), pszWinstation);
  409. if (DoesLanaTableExist())
  410. {
  411. LOGMESSAGE0(_T("OK: GuidTable already exists."));
  412. return;
  413. }
  414. if (pRegWinstation->ReadRegDWord(_T("LanAdapter"), &dwLana) == ERROR_SUCCESS)
  415. {
  416. if (dwLana == 0)
  417. {
  418. LOGMESSAGE0(_T("OK: using all adapters"));
  419. }
  420. else
  421. {
  422. LPTSTR lpStrings[1] = { NULL };
  423. LOGMESSAGE0(_T("ERROR: using custom bindings"));
  424. LOGMESSAGE1(_T("%s will be disabled and bindings reset"), pszWinstation);
  425. VERIFY(ERROR_SUCCESS == pRegWinstation->WriteRegDWord(_T("LanAdapter"), (DWORD)-1));
  426. VERIFY(ERROR_SUCCESS == pRegWinstation->WriteRegDWord(_T("fEnableWinStation"), 0));
  427. //
  428. // Log error to setuperr.txt once. Log error to eventlog
  429. // each time.
  430. //
  431. if (!fErrorLogged)
  432. {
  433. fErrorLogged = TRUE;
  434. LogErrorToSetupLog(OcErrLevWarning, IDS_STRING_GENERIC_LANA_WARNING);
  435. }
  436. lpStrings[0] = pszWinstation;
  437. LogErrorToEventLog(
  438. EVENTLOG_WARNING_TYPE,
  439. CATEGORY_NOTIFY_EVENTS,
  440. EVENT_WINSTA_DISABLED_DUE_TO_LANA,
  441. 1,
  442. 0,
  443. (LPCTSTR *)lpStrings,
  444. NULL
  445. );
  446. }
  447. }
  448. else
  449. {
  450. LOGMESSAGE0(_T("OK: No LanAdapter value"));
  451. }
  452. }
  453. BOOL SubCompCoreTS::UpdateRDPWinstation (CRegistry *pRegWinstation, LPTSTR lpWinStationName)
  454. {
  455. // BUG WARNING: ALL OF THESE VALUES MUST BE KEPT IN SYNC WITH TSOC.INX!!!
  456. //
  457. // These entries will be modified on upgrades.
  458. //
  459. LOGMESSAGE1(_T("Updating Winstation - %s"), lpWinStationName);
  460. ASSERT(pRegWinstation);
  461. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableClip"), 0) );
  462. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableCpm"), 0) );
  463. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableLPT"), 0) );
  464. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fInheritAutoClient"), 1) );
  465. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fAutoClientLpts"), 1) );
  466. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fForceClientLptDef"), 1) );
  467. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegString(_T("WdName"), _T("Microsoft RDP 5.2")));
  468. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWord(_T("WdFlag"), 0x36) );
  469. // per JoyC updated for RDPWD, RDP-TCP winstations.
  470. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableCcm"), 0x0) );
  471. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableCdm"), 0x0) );
  472. // enable audio redirection for Professional, disable for server
  473. //
  474. if ( StateObject.IsWorkstation() )
  475. {
  476. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fDisableCam"), 0x0 ));
  477. }
  478. // Per AraBern, updated for RDPWD, RDP-TCP winstations.
  479. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("ColorDepth"), StateObject.IsWorkstation() ? 0x4 : 0x3) );
  480. VERIFY( ERROR_SUCCESS == pRegWinstation->WriteRegDWordNoOverWrite(_T("fInheritColorDepth"), 0x0) );
  481. // HKLM ,"SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\UserOverride\Control Panel\Desktop","Wallpaper",STRIG_RETAIN,""
  482. // To address bug 727650 (appcompat problem if cursorblink is set to -1_, remove the following regvalue:
  483. // Remove HKLM ,"SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\UserOverride\Control Panel\Desktop","DisableCursorBlink"
  484. CRegistry oReg;
  485. if (ERROR_SUCCESS == oReg.CreateKey(*pRegWinstation, _T("UserOverride\\Control Panel\\Desktop")))
  486. {
  487. //
  488. // set cursor blink and wallpaper off on servers.
  489. //
  490. if (!StateObject.IsWorkstation())
  491. {
  492. oReg.DeleteValue(_T("DisableCursorBlink"));
  493. oReg.WriteRegString(_T("Wallpaper"), _T(""));
  494. }
  495. }
  496. // Move old autologon password into LSA (a-sajara)
  497. // We only want to move the password if a valid winstation name is provided
  498. if (lpWinStationName != NULL)
  499. {
  500. MoveWinStationPassword(pRegWinstation, lpWinStationName);
  501. }
  502. return TRUE;
  503. }
  504. /*****************************************************************************
  505. * Method: MoveWinStationPassword
  506. *
  507. * Overview: For security reasons the lightly encrypted password that is
  508. * stored in the winstation registry key is being moved to LSA
  509. * secret. We are going to keep the password in it's encrypted
  510. * form so we can just copy it over as is.
  511. *
  512. * Parameters: pRegWinstation (IN) - pointer to winstation registry key
  513. * strWinStationName (IN) - Winstation name we are looking at
  514. *
  515. *****************************************************************************/
  516. BOOL
  517. SubCompCoreTS::MoveWinStationPassword(CRegistry *pRegWinstation,
  518. LPTSTR strWinStationName)
  519. {
  520. USES_CONVERSION;
  521. DWORD dwRet;
  522. LPTSTR strKeyName = NULL;
  523. LPTSTR strPassword = NULL;
  524. DWORD dwKeyLength;
  525. DWORD dwPasswordLength;
  526. // Make sure a Winstation name is provided this is used for a unique LSA key
  527. if (strWinStationName == NULL)
  528. {
  529. LOGMESSAGE0(_T("ERROR, Winstation name not provided."));
  530. return FALSE;
  531. }
  532. // Read password from the registry
  533. dwRet = pRegWinstation->ReadRegString(OLD_PASSWORD_VALUE_NAME,
  534. &strPassword,
  535. &dwPasswordLength);
  536. if (dwRet != ERROR_SUCCESS)
  537. {
  538. LOGMESSAGE0(_T("Failed to read Password value for Winstation"));
  539. return FALSE;
  540. }
  541. LOGMESSAGE1(_T("Password for this winstation = %s"), strPassword);
  542. // Build LSA key name by appending the Winstation Name to the static KeyName
  543. dwKeyLength = _tcslen(LSA_PSWD_KEYNAME_T) + _tcslen(strWinStationName) + 1;
  544. // Allocate memory for the password KEY
  545. strKeyName = (LPTSTR)LocalAlloc(LMEM_FIXED, dwKeyLength * sizeof(TCHAR));
  546. if (strKeyName == NULL)
  547. {
  548. LOGMESSAGE0(_T("ERROR, Failed to allocate memory for LSA password key"));
  549. return FALSE;
  550. }
  551. _tcscpy(strKeyName, LSA_PSWD_KEYNAME_T);
  552. _tcscat(strKeyName, strWinStationName);
  553. strKeyName[dwKeyLength - 1] = _T('\0');
  554. LOGMESSAGE1(_T("Storing the password in LSA key:%s"), strKeyName);
  555. // Store the password in LSA
  556. dwRet = StoreSecretKey(T2W(strKeyName),
  557. (PBYTE)strPassword,
  558. dwPasswordLength);
  559. if (dwRet != ERROR_SUCCESS)
  560. {
  561. LOGMESSAGE1(_T("StoreSecretKey(strKeyName) failed. Reason %ld"), dwRet);
  562. }
  563. LocalFree(strKeyName);
  564. LOGMESSAGE1(_T("Deleting password key:%s"),strKeyName);
  565. // Delete the password key
  566. dwRet = pRegWinstation->DeleteValue(OLD_PASSWORD_VALUE_NAME);
  567. if (dwRet != ERROR_SUCCESS)
  568. {
  569. LOGMESSAGE0(_T("ERROR, Failed to delete Password value for Winstation"));
  570. return FALSE;
  571. }
  572. return TRUE;
  573. }
  574. BOOL SubCompCoreTS::IsRdpWinStation(CRegistry *pRegWinstation)
  575. {
  576. ASSERT(pRegWinstation);
  577. DWORD dwWdFlag;
  578. if (ERROR_SUCCESS == pRegWinstation->ReadRegDWord(_T("WdFlag"), &dwWdFlag))
  579. {
  580. #ifdef DBG
  581. // if this is an RDP winstation,
  582. // we must have Microsoft in the WdName string
  583. if (WDF_TSHARE & dwWdFlag)
  584. {
  585. LPTSTR strWdName;
  586. DWORD dwSize;
  587. if (ERROR_SUCCESS == pRegWinstation->ReadRegString(_T("WdName"), &strWdName, &dwSize))
  588. {
  589. ASSERT(_tcsstr(strWdName,_T("Microsoft")) && _tcsstr(strWdName, _T("RDP")));
  590. }
  591. else
  592. {
  593. //
  594. // we failed to read strWdName.
  595. // it shouldn't have happened.
  596. ASSERT(FALSE);
  597. }
  598. }
  599. #endif
  600. return WDF_TSHARE & dwWdFlag;
  601. }
  602. else
  603. {
  604. //
  605. // we failed to read WdFlag, it should not have happened.
  606. //
  607. LOGMESSAGE0(_T("ERROR, Failed to read WdFlag for winstation"));
  608. ASSERT(FALSE);
  609. return FALSE;
  610. }
  611. }
  612. BOOL SubCompCoreTS::IsConsoleWinStation(CRegistry *pRegWinstation)
  613. {
  614. ASSERT(pRegWinstation);
  615. LPTSTR strWdName;
  616. DWORD dwSize;
  617. if (ERROR_SUCCESS == pRegWinstation->ReadRegString(_T("WdName"), &strWdName, &dwSize))
  618. {
  619. // if the value wdname contains the string "Console"
  620. // this is console winstation subkey
  621. LOGMESSAGE1(_T("WdName for this winstation = %s"), strWdName);
  622. #ifdef DBG
  623. // if this is console winstation
  624. if (_tcsicmp(strWdName,_T("Console")) == 0)
  625. {
  626. // then it cannot be either RDP or MetaFrame winstation
  627. ASSERT(!IsMetaFrameWinstation(pRegWinstation) && !IsRdpWinStation(pRegWinstation));
  628. }
  629. #endif
  630. return _tcsicmp(strWdName,_T("Console")) == 0;
  631. }
  632. else
  633. {
  634. LOGMESSAGE0(_T("ERROR, Failed to read Wdname for winstation"));
  635. ASSERT(FALSE);
  636. return FALSE;
  637. }
  638. }
  639. // returns true if this is non-rdp and non-console winstation subkey.
  640. BOOL SubCompCoreTS::IsMetaFrameWinstation(CRegistry *pRegWinstation)
  641. {
  642. ASSERT(pRegWinstation);
  643. DWORD dwWdFlag;
  644. if (ERROR_SUCCESS == pRegWinstation->ReadRegDWord(_T("WdFlag"), &dwWdFlag))
  645. {
  646. return WDF_ICA & dwWdFlag;
  647. }
  648. else
  649. {
  650. //
  651. // we could not read WdFlag value.
  652. //
  653. LOGMESSAGE0(_T("ERROR, Failed to read WdFlag for winstation"));
  654. ASSERT(FALSE);
  655. return TRUE;
  656. }
  657. }
  658. BOOL SubCompCoreTS::UpgradeRdpWinstations ()
  659. {
  660. // we need to upgrade RDP capabilities for RDPWD and existing RDP winstations.
  661. // see also #240925
  662. // also if during upgrades we found any non-rdp winstations
  663. // we must disable them as they are not compatible with NT5.
  664. // #240905
  665. CRegistry reg;
  666. if (ERROR_SUCCESS == reg.OpenKey(HKEY_LOCAL_MACHINE, REG_WINSTATION_KEY))
  667. {
  668. LPTSTR lpStr = NULL;
  669. DWORD dwSize = 0;
  670. if (ERROR_SUCCESS == reg.GetFirstSubKey(&lpStr, &dwSize))
  671. {
  672. do
  673. {
  674. ASSERT(lpStr);
  675. ASSERT(dwSize > 0);
  676. // check if the current key is on rdp winstation
  677. CRegistry regSubKey;
  678. if ( ERROR_SUCCESS == regSubKey.OpenKey(reg, lpStr) )
  679. {
  680. if (IsRdpWinStation(&regSubKey))
  681. {
  682. LOGMESSAGE1(_T("Updating Winstation - %s"), lpStr);
  683. UpdateRDPWinstation(&regSubKey, lpStr);
  684. VerifyLanAdapters(&regSubKey, lpStr);
  685. }
  686. else if (IsMetaFrameWinstation(&regSubKey))
  687. {
  688. LOGMESSAGE1(_T("Disabling winstaion - %s"), lpStr);
  689. DisableWinStation(&regSubKey);
  690. VerifyLanAdapters(&regSubKey, lpStr);
  691. }
  692. else
  693. {
  694. LOGMESSAGE1(_T("Found a Console Winstation - %s"), lpStr);
  695. // this must be console winstation
  696. // do nothing for this.
  697. }
  698. }
  699. else
  700. {
  701. AssertFalse();
  702. LOGMESSAGE1(_T("ERROR:Failed to Open Winstation Key %s"), lpStr);
  703. }
  704. }
  705. while (ERROR_SUCCESS == reg.GetNextSubKey(&lpStr, &dwSize ));
  706. }
  707. else
  708. {
  709. // since this is upgrade we must find key under Winstations.
  710. AssertFalse();
  711. return FALSE;
  712. }
  713. }
  714. else
  715. {
  716. AssertFalse();
  717. return FALSE;
  718. }
  719. // we need to upgrade Wds\rdpwd as well.
  720. if ( ERROR_SUCCESS == reg.OpenKey(HKEY_LOCAL_MACHINE, SYSTEM_RDPWD_KEY))
  721. {
  722. //
  723. // this is not really a winstation.
  724. // but this call will upgrade the required entries.
  725. //
  726. UpdateRDPWinstation(&reg, NULL);
  727. }
  728. else
  729. {
  730. AssertFalse();
  731. return FALSE;
  732. }
  733. return TRUE;
  734. }
  735. /*--------------------------------------------------------------------------------------------------------
  736. * BOOL DoHydraRegistrySecurityChanges ()
  737. * does the necessary security changes for installing hydra
  738. * that is Adds/remove LogOnLocall rights to EveryOne group.
  739. * returns success
  740. * Parameter decides if hydra is getting enabled or disabled.
  741. * -------------------------------------------------------------------------------------------------------*/
  742. BOOL SubCompCoreTS::DoHydraRegistrySecurityChanges ()
  743. {
  744. BOOL bAddRemove = StateObject.IsTSEnableSelected();
  745. DWORD dwError = NO_ERROR;
  746. if (bAddRemove)
  747. {
  748. CRegistry reg;
  749. dwError = reg.OpenKey(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software"));
  750. if (ERROR_SUCCESS == dwError)
  751. {
  752. PSECURITY_DESCRIPTOR pSecDec, pSecDecNew;
  753. DWORD dwSize;
  754. dwError = reg.GetSecurity(&pSecDec, DACL_SECURITY_INFORMATION, &dwSize);
  755. if (dwError != ERROR_SUCCESS)
  756. {
  757. LOGMESSAGE1(_T("ERROR:GetSecurity failed with %u"), dwError);
  758. }
  759. else
  760. {
  761. ASSERT(pSecDec);
  762. ASSERT(IsValidSecurityDescriptor(pSecDec));
  763. pSecDecNew = pSecDec;
  764. PACL pNewDacl = NULL;
  765. if (!AddTerminalServerUserToSD(&pSecDecNew, GENERIC_WRITE, &pNewDacl ))
  766. {
  767. LOGMESSAGE1(_T("ERROR:AddUserToSD failed with %u"), GetLastError());
  768. }
  769. else
  770. {
  771. // due to a bug in RegSetKeySecurity(), existing children of this key
  772. // will not get the new SID, hence, we must use MARTA calls intead.
  773. dwError = SetNamedSecurityInfo(
  774. _T("Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\Software"),
  775. SE_REGISTRY_KEY,
  776. DACL_SECURITY_INFORMATION,
  777. NULL,
  778. NULL,
  779. pNewDacl,
  780. NULL);
  781. if (dwError != ERROR_SUCCESS)
  782. {
  783. LOGMESSAGE1(_T("ERROR:SetNamedSecurityInfo failed with %u"), dwError);
  784. }
  785. }
  786. // if new sec desciptor been allocated
  787. if (pSecDecNew != pSecDec)
  788. LocalFree(pSecDecNew);
  789. }
  790. }
  791. else
  792. {
  793. LOGMESSAGE1(_T("ERROR, OpenKey failed, error = %d"), dwError);
  794. }
  795. }
  796. else
  797. {
  798. ASSERT(FALSE);
  799. }
  800. return dwError == NO_ERROR;
  801. }
  802. #define INTERNET_CONNECTOR_LICENSE_STORE L"INET_LICENSE_STORE_2_60e55c11-a780-11d2-b1a0-00c04fa30cc4"
  803. #define INTERNET_CONNECTOR_LSERVER_STORE L"INET_LSERVER_STORE_2_341D3DAB-BD58-11d2-B130-00C04FB16103"
  804. #define INTERNET_CONNECTOR_LSERVER_STORE2 L"INET_LSERVER_STORE_3_341D3DAB-BD58-11d2-B130-00C04FB16103"
  805. #define HYDRA_SERVER_PARAM _T("SYSTEM\\CurrentControlSet\\Services\\TermService\\Parameters")
  806. #define HS_PARAM_INTERNET_CONNECTOR_FLAG _T("fInternetConnector")
  807. BOOL SubCompCoreTS::DisableInternetConnector ()
  808. {
  809. LOGMESSAGE0(_T("DisableInternetConnector"));
  810. // Wipe out the secret keys in LSA, regarding to Internet Connector
  811. DWORD dwStatus = StoreSecretKey(INTERNET_CONNECTOR_LICENSE_STORE,(PBYTE) NULL,0);
  812. if (dwStatus == ERROR_SUCCESS)
  813. {
  814. LOGMESSAGE0(_T("StoreSecretKey succeeded for INTERNET_CONNECTOR_LICENSE_STORE"));
  815. }
  816. else
  817. {
  818. LOGMESSAGE1(_T("StoreSecretKey(INTERNET_CONNECTOR_LICENSE_STORE) failed. Reason %ld"),dwStatus);
  819. }
  820. dwStatus = StoreSecretKey(INTERNET_CONNECTOR_LSERVER_STORE,(PBYTE) NULL,0);
  821. if (dwStatus == ERROR_SUCCESS)
  822. {
  823. LOGMESSAGE0(_T("StoreSecretKey succeeded for INTERNET_CONNECTOR_LSERVER_STORE"));
  824. }
  825. else
  826. {
  827. LOGMESSAGE1(_T("StoreSecretKey(INTERNET_CONNECTOR_LSERVER_STORE) failed. Reason %ld"),dwStatus);
  828. }
  829. dwStatus = StoreSecretKey(INTERNET_CONNECTOR_LSERVER_STORE2,(PBYTE) NULL,0);
  830. if (dwStatus == ERROR_SUCCESS)
  831. {
  832. LOGMESSAGE0(_T("StoreSecretKey succeeded for INTERNET_CONNECTOR_LSERVER_STORE2"));
  833. }
  834. else
  835. {
  836. LOGMESSAGE1(_T("StoreSecretKey(INTERNET_CONNECTOR_LSERVER_STORE2) failed. Reason %ld"),dwStatus);
  837. }
  838. NET_API_STATUS dwNtStatus = NetUserDel(NULL,L"TsInternetUser");
  839. if (dwNtStatus == NERR_Success)
  840. {
  841. LOGMESSAGE0(_T("NetUserDel succeeded for TsInternetUser"));
  842. }
  843. else
  844. {
  845. LOGMESSAGE1(_T("NetUserDel(TsInternetUser) failed. Reason %ld"),dwNtStatus);
  846. }
  847. return FALSE;
  848. }
  849. #define LICENSING_TIME_BOMB_5_0 L"TIMEBOMB_832cc540-3244-11d2-b416-00c04fa30cc4"
  850. #define RTMLICENSING_TIME_BOMB_5_0 L"RTMTSTB_832cc540-3244-11d2-b416-00c04fa30cc4"
  851. BOOL SubCompCoreTS::ResetTermServGracePeriod ()
  852. {
  853. //
  854. // Wipe out the secret keys in LSA for the Win2000 grace period
  855. //
  856. LOGMESSAGE0(_T("Calling StoreSecretKey"));
  857. StoreSecretKey(LICENSING_TIME_BOMB_5_0,(PBYTE) NULL,0);
  858. StoreSecretKey(RTMLICENSING_TIME_BOMB_5_0,(PBYTE) NULL,0);
  859. return TRUE;
  860. }
  861. // Old LSA key names:
  862. #define OLD_PRIVATE_KEY_NAME \
  863. L"HYDRAKEY_28ada6da-d622-11d1-9cb9-00c04fb16e75"
  864. #define OLD_X509_CERT_PRIVATE_KEY_NAME \
  865. L"HYDRAKEY_dd2d98db-2316-11d2-b414-00c04fa30cc4"
  866. #define OLD_X509_CERT_PUBLIC_KEY_NAME \
  867. L"HYDRAPUBLICKEY_dd2d98db-2316-11d2-b414-00c04fa30cc4"
  868. #define OLD_2_PRIVATE_KEY_NAME \
  869. L"HYDRAENCKEY_28ada6da-d622-11d1-9cb9-00c04fb16e75"
  870. #define OLD_2_X509_CERT_PRIVATE_KEY_NAME \
  871. L"HYDRAENCKEY_dd2d98db-2316-11d2-b414-00c04fa30cc4"
  872. #define OLD_2_X509_CERT_PUBLIC_KEY_NAME \
  873. L"HYDRAENCPUBLICKEY_dd2d98db-2316-11d2-b414-00c04fa30cc4"
  874. BOOL SubCompCoreTS::RemoveOldKeys ()
  875. {
  876. //
  877. // Wipe out the secret keys in LSA for the public/private keys
  878. //
  879. LOGMESSAGE0(_T("Calling StoreSecretKey"));
  880. StoreSecretKey(OLD_PRIVATE_KEY_NAME,(PBYTE) NULL,0);
  881. StoreSecretKey(OLD_X509_CERT_PRIVATE_KEY_NAME,(PBYTE) NULL,0);
  882. StoreSecretKey(OLD_X509_CERT_PUBLIC_KEY_NAME,(PBYTE) NULL,0);
  883. StoreSecretKey(OLD_2_PRIVATE_KEY_NAME,(PBYTE) NULL,0);
  884. StoreSecretKey(OLD_2_X509_CERT_PRIVATE_KEY_NAME,(PBYTE) NULL,0);
  885. StoreSecretKey(OLD_2_X509_CERT_PUBLIC_KEY_NAME,(PBYTE) NULL,0);
  886. return TRUE;
  887. }
  888. BOOL SubCompCoreTS::RemoveTSServicePackEntry ()
  889. {
  890. LOGMESSAGE0(_T("will delete terminal service pack uninstall keys."));
  891. CRegistry regUninstallKey;
  892. if (ERROR_SUCCESS != regUninstallKey.OpenKey(HKEY_LOCAL_MACHINE, SOFTWARE_UNINSTALL_KEY))
  893. {
  894. return(TRUE);
  895. }
  896. BOOL bReturn = TRUE;
  897. DWORD dwError;
  898. //
  899. // now try to delete various service pack key.
  900. // if the key does not exist its NOT an error. It means service pack was not installed at all.
  901. //
  902. dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_4_KEY);
  903. if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
  904. {
  905. bReturn = FALSE;
  906. LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_4_KEY, dwError);
  907. }
  908. dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_5_KEY);
  909. if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
  910. {
  911. bReturn = FALSE;
  912. LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_5_KEY, dwError);
  913. }
  914. dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_6_KEY);
  915. if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
  916. {
  917. bReturn = FALSE;
  918. LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_6_KEY, dwError);
  919. }
  920. dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_7_KEY);
  921. if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
  922. {
  923. bReturn = FALSE;
  924. LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_7_KEY, dwError);
  925. }
  926. dwError = RegDeleteKey(regUninstallKey, TERMSRV_PACK_8_KEY);
  927. if ((ERROR_SUCCESS != dwError) && (ERROR_FILE_NOT_FOUND != dwError))
  928. {
  929. bReturn = FALSE;
  930. LOGMESSAGE2(_T("Error deleting subkey %s (%d)"), TERMSRV_PACK_8_KEY, dwError);
  931. }
  932. return bReturn;
  933. }
  934. //
  935. // #386628: we need remove metaframe executables - txlogon.exe and wfshell.exe from userinit key on TS40 upgrades,
  936. // as these apps are broken after upgrade. // what about any other app that are appending value to userinit ? :
  937. // BradG suggested, that we should just wack the reigsty to contain just userinit.
  938. //
  939. BOOL SubCompCoreTS::RemoveMetaframeFromUserinit ()
  940. {
  941. ASSERT( StateObject.IsUpgradeFrom40TS() );
  942. CRegistry reg;
  943. const TCHAR szUserInitKey[] = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon");
  944. const TCHAR szUserInitValue[] = _T("Userinit");
  945. const TCHAR szData[] = _T("userinit");
  946. if (ERROR_SUCCESS == reg.OpenKey(HKEY_LOCAL_MACHINE, szUserInitKey))
  947. {
  948. return (ERROR_SUCCESS == reg.WriteRegString(szUserInitValue, szData));
  949. }
  950. else
  951. {
  952. LOGMESSAGE0(_T("ERROR:Failed to open userinit key"));
  953. }
  954. return FALSE;
  955. }
  956. BOOL SubCompCoreTS::UninstallTSClient ()
  957. {
  958. LPCTSTR SOFTWARE_MSFT = _T("Software\\Microsoft");
  959. LPCTSTR RUNONCE = _T("Windows\\CurrentVersion\\RunOnce");
  960. LPCTSTR TSC_UNINSTALL = _T("tscuninstall");
  961. LPCTSTR TSC_UNINSTALL_CMD = _T("%systemroot%\\system32\\tscupgrd.exe");
  962. CRegistry regAllUsers(HKEY_USERS);
  963. //
  964. // now enumerate through all the uses and Copy settings to new key.
  965. //
  966. DWORD dwSize;
  967. LPTSTR szUser = NULL;
  968. if (ERROR_SUCCESS == regAllUsers.GetFirstSubKey(&szUser, &dwSize))
  969. {
  970. do
  971. {
  972. ASSERT(szUser);
  973. TCHAR szSrcKey[512];
  974. _tcscpy(szSrcKey, szUser);
  975. _tcscat(szSrcKey, _T("\\"));
  976. _tcscat(szSrcKey, SOFTWARE_MSFT);
  977. _tcscat(szSrcKey, _T("\\"));
  978. _tcscat(szSrcKey, RUNONCE);
  979. CRegistry regSrc;
  980. DWORD dwError;
  981. if (ERROR_SUCCESS == (dwError = regSrc.CreateKey(HKEY_USERS, szSrcKey)))
  982. {
  983. if (ERROR_SUCCESS == regSrc.WriteRegExpString(TSC_UNINSTALL, TSC_UNINSTALL_CMD)) {
  984. LOGMESSAGE1(_T("Write TSC uninstall reg value to user %s"), szSrcKey);
  985. }
  986. else {
  987. LOGMESSAGE1(_T("ERROR write TSC uninstall reg value, Lasterror was %d"), GetLastError());
  988. }
  989. }
  990. else {
  991. LOGMESSAGE1(_T("ERROR open user runonce key, Lasterror was %d"), dwError);
  992. }
  993. } while (ERROR_SUCCESS == regAllUsers.GetNextSubKey(&szUser, &dwSize));
  994. }
  995. else {
  996. LOGMESSAGE1(_T("ERROR open user hive"), GetLastError());
  997. }
  998. return TRUE;
  999. }
  1000. BOOL SubCompCoreTS::WriteDenyConnectionRegistry ()
  1001. {
  1002. //
  1003. // we need to write this value only for fresh installs, or if its changed.
  1004. //
  1005. DWORD dwError;
  1006. CRegistry oRegTermsrv;
  1007. dwError = oRegTermsrv.OpenKey(HKEY_LOCAL_MACHINE, REG_CONTROL_TS_KEY);
  1008. if (ERROR_SUCCESS == dwError)
  1009. {
  1010. DWORD dwDenyConnect = StateObject.GetCurrentConnAllowed() ? 0 : 1;
  1011. LOGMESSAGE1(_T("Writing dwDenyConnect = %d"), dwDenyConnect);
  1012. dwError = oRegTermsrv.WriteRegDWord(DENY_CONN_VALUE, dwDenyConnect);
  1013. if (ERROR_SUCCESS == dwError)
  1014. {
  1015. if (dwDenyConnect == 0 && StateObject.IsServer())
  1016. {
  1017. // if we are allowing connections, then we must disble CSC on server machines.
  1018. if (!DisableCSC())
  1019. {
  1020. LOGMESSAGE0(_T("ERROR: failed to disable csc"));
  1021. }
  1022. }
  1023. return TRUE;
  1024. }
  1025. else
  1026. {
  1027. LOGMESSAGE2(_T("Error (%d), Writing, %s Value"), dwError, DENY_CONN_VALUE);
  1028. return FALSE;
  1029. }
  1030. }
  1031. else
  1032. {
  1033. LOGMESSAGE2(_T("Error (%d), Opening , %s key"), dwError, REG_CONTROL_TS_KEY);
  1034. return FALSE;
  1035. }
  1036. }
  1037. void SubCompCoreTS::IsCSCEnabled()
  1038. {
  1039. CRegistry oRegCSC;
  1040. DWORD dwError = oRegCSC.OpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\NetCache"));
  1041. if (ERROR_SUCCESS == dwError)
  1042. {
  1043. DWORD dwEnabled;
  1044. dwError = oRegCSC.ReadRegDWord(_T("Enabled"), &dwEnabled);
  1045. if (dwError == ERROR_SUCCESS)
  1046. {
  1047. LOGMESSAGE1(_T("CSC is %s"), dwEnabled ? _T("enabled") : _T("disabled"));
  1048. return;
  1049. }
  1050. }
  1051. LOGMESSAGE1(_T("Error reading CSC/Enabled value"), dwError);
  1052. }
  1053. bool SubCompCoreTS::DisableCSC()
  1054. {
  1055. CRegistry oRegCSC;
  1056. DWORD dwError = oRegCSC.CreateKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\NetCache"));
  1057. if (ERROR_SUCCESS == dwError)
  1058. {
  1059. dwError = oRegCSC.WriteRegDWord(_T("Enabled"), 0);
  1060. if (ERROR_SUCCESS != dwError)
  1061. {
  1062. LOGMESSAGE1(_T("Error: writing netcache/enabled(%d)"), dwError);
  1063. return false;
  1064. }
  1065. else
  1066. {
  1067. LOGMESSAGE0(_T("Disabled CSC!"));
  1068. }
  1069. }
  1070. else
  1071. {
  1072. LOGMESSAGE1(_T("Error: opening netcache registry(%d)"), dwError);
  1073. return false;
  1074. }
  1075. return true;
  1076. }
  1077. LPCTSTR SERVICES_TERMDD_KEY = _T("SYSTEM\\CurrentControlSet\\Services\\TermDD");
  1078. void SubCompCoreTS::SetConsoleShadowInstalled (BOOL bInstalled)
  1079. {
  1080. // ; HKLM, "SYSTEM\CurrentControlSet\Services\TermDD", "PortDriverEnable", 0x00010001, 0x1
  1081. CRegistry Reg;
  1082. if (ERROR_SUCCESS == Reg.CreateKey(HKEY_LOCAL_MACHINE, SERVICES_TERMDD_KEY))
  1083. {
  1084. if (ERROR_SUCCESS != Reg.WriteRegDWord(_T("PortDriverEnable"), bInstalled ? 1 : 0))
  1085. {
  1086. LOGMESSAGE0(_T("ERROR, Failed to write to PortDriverEnable"));
  1087. }
  1088. }
  1089. else
  1090. {
  1091. LOGMESSAGE1(_T("ERROR, Failed to Create/Open %s"), SERVICES_TERMDD_KEY);
  1092. }
  1093. }
  1094. BOOL SubCompCoreTS::IsConsoleShadowInstalled ()
  1095. {
  1096. // ; HKLM, "SYSTEM\CurrentControlSet\Services\TermDD", "PortDriverEnable", 0x00010001, 0x1
  1097. CRegistry Reg;
  1098. if (ERROR_SUCCESS == Reg.OpenKey(HKEY_LOCAL_MACHINE, SERVICES_TERMDD_KEY))
  1099. {
  1100. DWORD dwPortDriverEnable;
  1101. if (ERROR_SUCCESS == Reg.ReadRegDWord(_T("PortDriverEnable"), &dwPortDriverEnable))
  1102. {
  1103. return (dwPortDriverEnable == 1);
  1104. }
  1105. else
  1106. {
  1107. LOGMESSAGE0(_T("Failed to read from PortDriverEnable, Maybe Console Shadow is not installed yet."));
  1108. }
  1109. }
  1110. else
  1111. {
  1112. LOGMESSAGE1(_T("ERROR, Failed to Open %s"), SERVICES_TERMDD_KEY);
  1113. }
  1114. return FALSE;
  1115. }
  1116. #ifdef TSOC_CONSOLE_SHADOWING
  1117. BOOL SubCompCoreTS::SetupConsoleShadow ()
  1118. {
  1119. if (IsConsoleShadowInstalled () == StateObject.IsTSEnableSelected())
  1120. {
  1121. return TRUE;
  1122. }
  1123. if (StateObject.IsTSEnableSelected())
  1124. {
  1125. LOGMESSAGE0(_T("Installing RDP Keyboard/Mouse drivers!"));
  1126. //
  1127. // this code is new to install Mouse Device for console shadowing.
  1128. //
  1129. if (!RDPDRINST_GUIModeSetupInstall(NULL, RDPMOUPNPID, RDPMOUDEVICEID))
  1130. {
  1131. LOGMESSAGE0(_T("ERROR:Could not create mouse devnode"));
  1132. }
  1133. //
  1134. // this code is new to install Kbd Device for console shadowing.
  1135. //
  1136. if (!RDPDRINST_GUIModeSetupInstall(NULL, RDPKBDPNPID, RDPKBDDEVICEID))
  1137. {
  1138. LOGMESSAGE0(_T("ERROR:Could not create kbd devnode"));
  1139. }
  1140. //
  1141. // this code is new to install RDPCDD chained driver
  1142. //
  1143. /*
  1144. TCHAR szInfFile[MAX_PATH];
  1145. ExpandEnvironmentStrings(szRDPCDDInfFile, szInfFile, MAX_PATH);
  1146. LOGMESSAGE1(_T("Inf file for RDPCDD is %s"), szInfFile);
  1147. BOOL bRebootRequired = TRUE;
  1148. if (NO_ERROR != InstallRootEnumeratedDevice( NULL, szRDPCDDDeviceName, szRDPCDDHardwareID, szInfFile, &bRebootRequired))
  1149. {
  1150. LOGMESSAGE0(_T("InstallRootEnumeratedDevice failed"));
  1151. }
  1152. */
  1153. }
  1154. else
  1155. {
  1156. GUID *pGuid=(GUID *)&GUID_DEVCLASS_SYSTEM;
  1157. if (!RDPDRINST_GUIModeSetupUninstall(NULL, RDPMOUPNPID, pGuid))
  1158. {
  1159. LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupUninstall failed for RDP Mouse device"));
  1160. }
  1161. pGuid=(GUID *)&GUID_DEVCLASS_SYSTEM;
  1162. if (!RDPDRINST_GUIModeSetupUninstall(NULL, RDPKBDPNPID, pGuid))
  1163. {
  1164. LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupUninstall failed for RDP KBD device"));
  1165. }
  1166. /*
  1167. pGuid=(GUID *)&GUID_DEVCLASS_DISPLAY;
  1168. if (!RDPDRINST_GUIModeSetupUninstall(NULL, (WCHAR *)T2W(szRDPCDDHardwareID), pGuid)) {
  1169. LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupUninstall failed for Chained Display device"));
  1170. }
  1171. */
  1172. CRegistry Reg;
  1173. if (ERROR_SUCCESS == Reg.OpenKey(HKEY_LOCAL_MACHINE, SERVICES_TERMDD_KEY))
  1174. {
  1175. if (ERROR_SUCCESS != Reg.WriteRegDWord(_T("Start"), 4))
  1176. {
  1177. LOGMESSAGE0(_T("ERROR, Failed to write to TermDD\\Start"));
  1178. }
  1179. }
  1180. else
  1181. {
  1182. LOGMESSAGE1(_T("ERROR, Failed to Open %s"), SERVICES_TERMDD_KEY);
  1183. }
  1184. }
  1185. SetConsoleShadowInstalled( StateObject.IsTSEnableSelected() );
  1186. return( TRUE );
  1187. }
  1188. #endif // TSOC_CONSOLE_SHADOWING
  1189. DWORD SubCompCoreTS::LoadOrUnloadPerf ()
  1190. {
  1191. BOOL bLoad = StateObject.IsTSEnableSelected();
  1192. LPCTSTR TERMSRV_SERVICE_PATH = _T("SYSTEM\\CurrentControlSet\\Services\\TermService");
  1193. LPCTSTR TERMSRV_PERF_NAME = _T("Performance");
  1194. LPCTSTR TERMSRV_PERF_COUNTERS = _T("SYSTEM\\CurrentControlSet\\Services\\TermService\\Performance");
  1195. LPCTSTR TERMSRV_PERF_COUNTERS_FIRST_COUNTER = _T("First Counter");
  1196. LPCTSTR TERMSRV_PERF_COUNTERS_LAST_COUNTER = _T("Last Counter");
  1197. LPCTSTR TERMSRV_PERF_COUNTERS_FIRST_HELP = _T("First Help");
  1198. LPCTSTR TERMSRV_PERF_COUNTERS_LAST_HELP = _T("Last Help");
  1199. LPCTSTR TERMSRV_PERF_COUNTERS_LIBRARY = _T("Library");
  1200. LPCTSTR TERMSRV_PERF_COUNTERS_LIBRARY_VALUE = _T("perfts.dll");
  1201. LPCTSTR TERMSRV_PERF_CLOSE = _T("Close");
  1202. LPCTSTR TERMSRV_PERF_CLOSE_VALUE = _T("CloseTSObject");
  1203. LPCTSTR TERMSRV_PERF_COLLECT_TIMEOUT = _T("Collect Timeout");
  1204. const DWORD TERMSRV_PERF_COLLECT_TIMEOUT_VALUE = 1000;
  1205. LPCTSTR TERMSRV_PERF_COLLECT = _T("Collect");
  1206. LPCTSTR TERMSRV_PERF_COLLECT_VALUE = _T("CollectTSObjectData");
  1207. LPCTSTR TERMSRV_PERF_OPEN_TIMEOUT = _T("Open Timeout");
  1208. const DWORD TERMSRV_PERF_OPEN_TIMEOUT_VALUE = 1000;
  1209. LPCTSTR TERMSRV_PERF_OPEN = _T("Open");
  1210. LPCTSTR TERMSRV_PERF_OPEN_VALUE = _T("OpenTSObject");
  1211. TCHAR PerfArg[MAX_PATH + 10];
  1212. CRegistry reg;
  1213. DWORD RetVal;
  1214. LOGMESSAGE1(_T("Entered LoadOrUnloadPerfCounters, load=%u"), bLoad);
  1215. if (bLoad)
  1216. {
  1217. //
  1218. // As a first step to installing, first clean out any existing
  1219. // entries by unloading the counters
  1220. //
  1221. LOGMESSAGE0(_T("Unloading counters before install"));
  1222. UnloadPerf();
  1223. RetVal = reg.CreateKey(HKEY_LOCAL_MACHINE, TERMSRV_PERF_COUNTERS);
  1224. if (RetVal == ERROR_SUCCESS)
  1225. {
  1226. TCHAR SystemDir[MAX_PATH];
  1227. // On load we create and populate the entire Performance key.
  1228. // This key must not be present when we are unloaded because
  1229. // the WMI provider enumerates service performance DLLs
  1230. // according to the presence of the Perf key. If it is present
  1231. // but not fully filled in then an error log is generated.
  1232. if (GetSystemDirectory(SystemDir, MAX_PATH))
  1233. {
  1234. // Just in case they are present, delete the counter number
  1235. // entries to make sure we regenerate them correctly below.
  1236. reg.DeleteValue(TERMSRV_PERF_COUNTERS_FIRST_COUNTER);
  1237. reg.DeleteValue(TERMSRV_PERF_COUNTERS_LAST_COUNTER);
  1238. reg.DeleteValue(TERMSRV_PERF_COUNTERS_FIRST_HELP);
  1239. reg.DeleteValue(TERMSRV_PERF_COUNTERS_LAST_HELP);
  1240. // Generate the static values.
  1241. reg.WriteRegString(TERMSRV_PERF_CLOSE, TERMSRV_PERF_CLOSE_VALUE);
  1242. reg.WriteRegDWord(TERMSRV_PERF_COLLECT_TIMEOUT, TERMSRV_PERF_COLLECT_TIMEOUT_VALUE);
  1243. reg.WriteRegString(TERMSRV_PERF_COLLECT, TERMSRV_PERF_COLLECT_VALUE);
  1244. reg.WriteRegDWord(TERMSRV_PERF_OPEN_TIMEOUT, TERMSRV_PERF_OPEN_TIMEOUT_VALUE);
  1245. reg.WriteRegString(TERMSRV_PERF_OPEN, TERMSRV_PERF_OPEN_VALUE);
  1246. reg.WriteRegString(TERMSRV_PERF_COUNTERS_LIBRARY, TERMSRV_PERF_COUNTERS_LIBRARY_VALUE);
  1247. _stprintf(PerfArg, _T("%s %s\\%s"), _T("lodctr"), SystemDir, _T("tslabels.ini"));
  1248. LOGMESSAGE1(_T("Arg is %s"), PerfArg);
  1249. return DWORD(LoadPerfCounterTextStrings(PerfArg, FALSE));
  1250. }
  1251. else
  1252. {
  1253. unsigned LastErr = GetLastError();
  1254. LOGMESSAGE1(_T("GetSystemDirectory Failure is %ld"), LastErr);
  1255. return LastErr;
  1256. }
  1257. }
  1258. else
  1259. {
  1260. LOGMESSAGE1(_T("Perf regkey create failure, err=%ld"), RetVal);
  1261. return RetVal;
  1262. }
  1263. }
  1264. else
  1265. {
  1266. return UnloadPerf();
  1267. }
  1268. }
  1269. //
  1270. // Unload perf ctrs
  1271. //
  1272. DWORD SubCompCoreTS::UnloadPerf()
  1273. {
  1274. TCHAR PerfArg[MAX_PATH + 10];
  1275. CRegistry reg;
  1276. DWORD RetVal;
  1277. LPCTSTR TERMSRV_SERVICE_PATH = _T("SYSTEM\\CurrentControlSet\\Services\\TermService");
  1278. LPCTSTR TERMSRV_PERF_NAME = _T("Performance");
  1279. // On unload, first unload the counters we should have in the system.
  1280. _stprintf(PerfArg, _T("%s %s"), _T("unlodctr"), _T("TermService"));
  1281. LOGMESSAGE1(_T("Arg is %s"), PerfArg);
  1282. UnloadPerfCounterTextStrings(PerfArg, FALSE);
  1283. // Delete the entire Performance key and all its descendants. We have
  1284. // to first open the ancestor key (TermService).
  1285. RetVal = reg.OpenKey(HKEY_LOCAL_MACHINE, TERMSRV_SERVICE_PATH);
  1286. if (RetVal == ERROR_SUCCESS)
  1287. {
  1288. RetVal = reg.RecurseDeleteKey(TERMSRV_PERF_NAME);
  1289. if (RetVal != ERROR_SUCCESS)
  1290. {
  1291. LOGMESSAGE1(_T("ERROR deleting Performance key: %ld"), RetVal);
  1292. }
  1293. }
  1294. else
  1295. {
  1296. LOGMESSAGE1(_T("Err opening Performance key, err=%ld"), RetVal);
  1297. }
  1298. return RetVal;
  1299. }
  1300. void SubCompCoreTS::AddRDPNP(LPTSTR szOldValue, LPTSTR szNewValue)
  1301. {
  1302. TCHAR RDPNP_ENTRY[] = _T("RDPNP");
  1303. const TCHAR SZ_SEP[] = _T(" \t");
  1304. //
  1305. // We are adding our rdpnp entry to the beginning of the list
  1306. //
  1307. // we dont want to add comma if original value is empty.
  1308. //
  1309. if (_tcslen(szOldValue) != 0 && _tcstok(szOldValue, SZ_SEP))
  1310. {
  1311. _tcscpy(szNewValue, RDPNP_ENTRY);
  1312. _tcscat(szNewValue, _T(","));
  1313. _tcscat(szNewValue, szOldValue);
  1314. }
  1315. else {
  1316. _tcscpy(szNewValue, RDPNP_ENTRY);
  1317. }
  1318. }
  1319. void SubCompCoreTS::RemoveRDPNP(LPTSTR szOldValue, LPTSTR szNewValue)
  1320. {
  1321. TCHAR RDPNP_ENTRY[] = _T("RDPNP");
  1322. //
  1323. // this is little complicated,
  1324. // we need to remove RDPNP from , seperated list.
  1325. //
  1326. // so lets get tokens.
  1327. //
  1328. TCHAR *szToken = NULL;
  1329. const TCHAR SZ_SEP[] = _T(",");
  1330. _tcscpy(szNewValue, _T(""));
  1331. szToken = _tcstok(szOldValue, SZ_SEP);
  1332. BOOL bFirstPass = TRUE;
  1333. while (szToken)
  1334. {
  1335. // if the token is RDPNP, skip it.
  1336. if (_tcsstr(szToken, RDPNP_ENTRY) == 0)
  1337. {
  1338. if (!bFirstPass)
  1339. {
  1340. _tcscat(szNewValue, _T(","));
  1341. }
  1342. _tcscat(szNewValue, szToken);
  1343. bFirstPass = FALSE;
  1344. }
  1345. szToken = _tcstok(NULL, SZ_SEP);
  1346. }
  1347. }
  1348. BOOL SubCompCoreTS::AddRemoveRDPNP ()
  1349. {
  1350. // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order
  1351. BOOL bAdd = StateObject.IsTSEnableSelected();
  1352. TCHAR NEWORK_PROVIDER_ORDER_KEY[] = _T("SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order");
  1353. TCHAR PROVIDER_ORDER_VALUE[] = _T("ProviderOrder");
  1354. TCHAR RDPNP_ENTRY[] = _T("RDPNP");
  1355. CRegistry regNetOrder;
  1356. if (ERROR_SUCCESS == regNetOrder.OpenKey(HKEY_LOCAL_MACHINE, NEWORK_PROVIDER_ORDER_KEY))
  1357. {
  1358. LPTSTR szOldValue;
  1359. DWORD dwSize;
  1360. if (ERROR_SUCCESS == regNetOrder.ReadRegString(PROVIDER_ORDER_VALUE, &szOldValue, &dwSize))
  1361. {
  1362. //
  1363. // now we want to add or remove RDPNP_ENTRY depending on we are enabled or disabled.
  1364. //
  1365. BOOL bRdpNpExists = (_tcsstr(szOldValue, RDPNP_ENTRY) != NULL);
  1366. if (bAdd == bRdpNpExists)
  1367. {
  1368. TCHAR szNewValue[256];
  1369. //
  1370. // already exists.
  1371. //
  1372. LOGMESSAGE0(_T("AddRemoveRDPNP, no change required."));
  1373. //
  1374. // Need to move to the right location
  1375. //
  1376. RemoveRDPNP(szOldValue, szNewValue);
  1377. _tcscpy(szOldValue, szNewValue);
  1378. AddRDPNP(szOldValue, szNewValue);
  1379. if (ERROR_SUCCESS != regNetOrder.WriteRegString(PROVIDER_ORDER_VALUE, szNewValue))
  1380. {
  1381. LOGMESSAGE2(_T("ERROR, Writing %s to %s"), szNewValue, PROVIDER_ORDER_VALUE);
  1382. }
  1383. }
  1384. else
  1385. {
  1386. TCHAR szNewValue[256];
  1387. if (bAdd)
  1388. {
  1389. //
  1390. // We are adding our rdpnp entry to the beginning of the list
  1391. //
  1392. AddRDPNP(szOldValue, szNewValue);
  1393. }
  1394. else
  1395. {
  1396. //
  1397. // this is little complicated,
  1398. // we need to remove RDPNP from , seperated list.
  1399. //
  1400. RemoveRDPNP(szOldValue, szNewValue);
  1401. }
  1402. if (ERROR_SUCCESS != regNetOrder.WriteRegString(PROVIDER_ORDER_VALUE, szNewValue))
  1403. {
  1404. LOGMESSAGE2(_T("ERROR, Writing %s to %s"), szNewValue, PROVIDER_ORDER_VALUE);
  1405. }
  1406. }
  1407. }
  1408. else
  1409. {
  1410. LOGMESSAGE1(_T("ERROR, Reading %s"), PROVIDER_ORDER_VALUE);
  1411. return FALSE;
  1412. }
  1413. }
  1414. else
  1415. {
  1416. LOGMESSAGE1(_T("ERROR, Opening %s"), NEWORK_PROVIDER_ORDER_KEY);
  1417. return FALSE;
  1418. }
  1419. return TRUE;
  1420. }
  1421. /*
  1422. bool SubCompCoreTS::InstallTermdd ()
  1423. {
  1424. // first check if termdd is installed.
  1425. bool bInstalledAlready = false;
  1426. CRegistry oRegTermsrv;
  1427. DWORD dwError = oRegTermsrv.OpenKey(HKEY_LOCAL_MACHINE,
  1428. _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server"));
  1429. if (dwError == STATUS_SUCCESS)
  1430. {
  1431. DWORD dwTermddInstalled;
  1432. if (STATUS_SUCCESS == oRegTermsrv.ReadRegDWord(_T("TermddInstalled"), &dwTermddInstalled))
  1433. {
  1434. bInstalledAlready = (dwTermddInstalled != 0);
  1435. }
  1436. }
  1437. if (!bInstalledAlready)
  1438. {
  1439. LOGMESSAGE0(_T("Installing TERMDD"));
  1440. if (RDPDRINST_GUIModeSetupInstall(NULL, TERMDDPNPID, TERMDDDEVICEID))
  1441. {
  1442. LOGMESSAGE0(_T("RDPDRINST_GUIModeSetupInstall succeeded for TERMDD"));
  1443. oRegTermsrv.WriteRegDWord(_T("TermddInstalled"), 1);
  1444. }
  1445. else
  1446. {
  1447. LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupInstall failed for TERMDD"));
  1448. return false;
  1449. }
  1450. }
  1451. else
  1452. {
  1453. LOGMESSAGE0(_T("ERROR:termdd is already installed."));
  1454. return false;
  1455. }
  1456. return true;
  1457. }
  1458. */
  1459. BOOL SubCompCoreTS::InstallUninstallRdpDr ()
  1460. {
  1461. //
  1462. // This code shouldn't run on Personal. Device redirection isn't
  1463. // supported for Personal.
  1464. //
  1465. if (StateObject.IsPersonal()) {
  1466. return TRUE;
  1467. }
  1468. //
  1469. // Installing RDPDR over itself is bad. Hence, only (un)install on
  1470. // a state change or an upgrade from TS40, but don't do unnecessary
  1471. // uninstalls. These are when coming from TS40, but using an unattended
  1472. // file to turn TS off. Therefore, RDPDR installation is the XOR of
  1473. // HasStateChanged() and IsUpgradeFromTS40().
  1474. //
  1475. // if state has changed.
  1476. if (StateObject.IsUpgradeFrom40TS() || (StateObject.WasTSEnabled() != StateObject.IsTSEnableSelected())
  1477. || !IsRDPDrInstalled() ) // last case checks for Personal -> Pro upgrades, we want to instsall rdpdr in those cases.
  1478. {
  1479. if (StateObject.IsTSEnableSelected())
  1480. {
  1481. LOGMESSAGE0(_T("Installing RDPDR"));
  1482. if (!RDPDRINST_GUIModeSetupInstall(NULL, RDPDRPNPID, RDPDRDEVICEID))
  1483. {
  1484. LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupInstall failed"));
  1485. }
  1486. }
  1487. else
  1488. {
  1489. LOGMESSAGE0(_T("Uninstalling RDPDR"));
  1490. GUID *pGuid=(GUID *)&GUID_DEVCLASS_SYSTEM;
  1491. if (!RDPDRINST_GUIModeSetupUninstall(NULL, RDPDRPNPID, pGuid))
  1492. {
  1493. LOGMESSAGE0(_T("ERROR:RDPDRINST_GUIModeSetupUninstall failed"));
  1494. }
  1495. }
  1496. }
  1497. return TRUE;
  1498. }
  1499. BOOL SubCompCoreTS::HandleHotkey ()
  1500. {
  1501. if (StateObject.IsTSEnableSelected())
  1502. {
  1503. CRegistry pRegToggle;
  1504. //
  1505. // Install Hotkey if not exist key value in HKU/.Default/Keyboard Layout/Toggle!Hotkey
  1506. //
  1507. #define REG_TOGGLE_KEY _T(".Default\\Keyboard Layout\\Toggle")
  1508. #define REG_HOT_KEY _T("Hotkey")
  1509. #define DEFAULT_HOT_KEY _T("1")
  1510. DWORD dwRet;
  1511. dwRet = pRegToggle.CreateKey(HKEY_USERS, REG_TOGGLE_KEY);
  1512. if (dwRet == ERROR_SUCCESS)
  1513. {
  1514. LPTSTR pszHotkey;
  1515. DWORD cbSize;
  1516. dwRet = pRegToggle.ReadRegString(REG_HOT_KEY, &pszHotkey, &cbSize);
  1517. if (dwRet != ERROR_SUCCESS)
  1518. {
  1519. dwRet = pRegToggle.WriteRegString(REG_HOT_KEY, DEFAULT_HOT_KEY);
  1520. if (dwRet != ERROR_SUCCESS)
  1521. {
  1522. LOGMESSAGE2(_T("ERROR:CRegistry::WriteRegString (%s=%s)"), REG_HOT_KEY, DEFAULT_HOT_KEY);
  1523. }
  1524. }
  1525. }
  1526. else
  1527. {
  1528. LOGMESSAGE1(_T("ERROR:CRegistry::CreateKey (%s)"), REG_TOGGLE_KEY);
  1529. }
  1530. }
  1531. return TRUE;
  1532. }
  1533. /*
  1534. * UpdateAudioCodecs - populates all audio codecs for RDP session
  1535. */
  1536. #define DRIVERS32 _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32")
  1537. #define RDPDRV ( DRIVERS32 _T("\\Terminal Server\\RDP") )
  1538. #ifdef _WIN64
  1539. #define RDPDRVWOW64 _T("SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32\\Terminal Server\\RDP")
  1540. #endif // _WIN64
  1541. BOOL UpdateAudioCodecs (BOOL bIsProfessional)
  1542. {
  1543. BOOL rv = TRUE;
  1544. LPTSTR szBuff;
  1545. DWORD status;
  1546. CRegistry regKey;
  1547. CRegistry regDestKey;
  1548. DWORD size;
  1549. #ifdef _WIN64
  1550. CRegistry regWow64;
  1551. #endif // _WIN64
  1552. //
  1553. // copy keys from
  1554. // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32
  1555. // wavemapper
  1556. // midimapper
  1557. // EnableMP3Codec (Professional only)
  1558. //
  1559. status = regKey.OpenKey(
  1560. HKEY_LOCAL_MACHINE,
  1561. DRIVERS32
  1562. );
  1563. if ( ERROR_SUCCESS != status )
  1564. goto exitpt;
  1565. //
  1566. // Create the destination
  1567. //
  1568. status = regDestKey.CreateKey(
  1569. HKEY_LOCAL_MACHINE,
  1570. RDPDRV
  1571. );
  1572. if ( ERROR_SUCCESS != status )
  1573. goto exitpt;
  1574. //
  1575. // query for wavemapper
  1576. //
  1577. status = regKey.ReadRegString(
  1578. _T("wavemapper"),
  1579. &szBuff,
  1580. &size
  1581. );
  1582. if ( ERROR_SUCCESS != status )
  1583. goto exitpt;
  1584. status = regDestKey.WriteRegString(
  1585. _T("wavemapper"),
  1586. szBuff
  1587. );
  1588. if ( ERROR_SUCCESS != status )
  1589. goto exitpt;
  1590. if ( bIsProfessional )
  1591. {
  1592. status = regDestKey.WriteRegDWord(
  1593. _T("EnableMP3Codec"),
  1594. 1
  1595. );
  1596. if ( ERROR_SUCCESS != status )
  1597. goto exitpt;
  1598. }
  1599. //
  1600. // query for midimapper
  1601. //
  1602. status = regKey.ReadRegString(
  1603. _T("midimapper"),
  1604. &szBuff,
  1605. &size
  1606. );
  1607. if ( ERROR_SUCCESS != status )
  1608. goto exitpt;
  1609. status = regDestKey.WriteRegString(
  1610. _T("midimapper"),
  1611. szBuff
  1612. );
  1613. if ( ERROR_SUCCESS != status )
  1614. goto exitpt;
  1615. #ifdef _WIN64
  1616. //
  1617. // Populate the wow64 keys
  1618. //
  1619. status = regWow64.CreateKey(
  1620. HKEY_LOCAL_MACHINE,
  1621. RDPDRVWOW64
  1622. );
  1623. if ( ERROR_SUCCESS != status )
  1624. {
  1625. goto exitpt;
  1626. }
  1627. status = regDestKey.ReadRegString(
  1628. _T("wavemapper"),
  1629. &szBuff,
  1630. &size
  1631. );
  1632. if ( ERROR_SUCCESS != status )
  1633. {
  1634. goto exitpt;
  1635. }
  1636. status = regWow64.WriteRegString(
  1637. _T("wavemapper"),
  1638. szBuff
  1639. );
  1640. if ( ERROR_SUCCESS != status )
  1641. {
  1642. goto exitpt;
  1643. }
  1644. status = regDestKey.ReadRegString(
  1645. _T("midimapper"),
  1646. &szBuff,
  1647. &size
  1648. );
  1649. if ( ERROR_SUCCESS != status )
  1650. {
  1651. goto exitpt;
  1652. }
  1653. status = regWow64.WriteRegString(
  1654. _T("midimapper"),
  1655. szBuff
  1656. );
  1657. if ( ERROR_SUCCESS != status )
  1658. {
  1659. goto exitpt;
  1660. }
  1661. status = regDestKey.ReadRegString(
  1662. _T("wave"),
  1663. &szBuff,
  1664. &size
  1665. );
  1666. if ( ERROR_SUCCESS != status )
  1667. {
  1668. goto exitpt;
  1669. }
  1670. status = regWow64.WriteRegString(
  1671. _T("wave"),
  1672. szBuff
  1673. );
  1674. if ( ERROR_SUCCESS != status )
  1675. {
  1676. goto exitpt;
  1677. }
  1678. #endif // _WIN64
  1679. rv = TRUE;
  1680. exitpt:
  1681. return rv;
  1682. }