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.

1446 lines
37 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. RDFilter
  5. Abstract:
  6. API's for filtering desktop visual elements for remote connections of
  7. varying connection speeds for performance reasons.
  8. Author:
  9. Tad Brockway 02/00
  10. Revision History:
  11. --*/
  12. #include <windows.h>
  13. #include <windowsx.h>
  14. #include <winuser.h>
  15. #include <winuserp.h>
  16. #include <shlobj.h>
  17. #include <shlwapi.h>
  18. #include <ocidl.h>
  19. #include <uxthemep.h>
  20. #include "rdfilter.h"
  21. #if DBG
  22. #include <stdio.h>
  23. #include <stdarg.h>
  24. #include <tchar.h>
  25. #endif
  26. //
  27. // Toggle Unit-Test
  28. //
  29. //#define UNIT_TEST
  30. #ifdef UNIT_TEST
  31. #include <winsta.h>
  32. #endif
  33. #ifdef UNIT_TEST
  34. #include "resource.h"
  35. #endif
  36. //
  37. // Internal Defines
  38. //
  39. #define REFRESHTHEMESFORTS_ORDINAL 36
  40. #define NUM_TSPERFFLAGS 10
  41. #define BLINK_OFF TEXT("-1")
  42. ////////////////////////////////////////////////////////////
  43. //
  44. // SystemParametersInfo UserPreferences manipulation macros
  45. // stolen from userk.h.
  46. //
  47. #define UPBOOLIndex(uSetting) \
  48. (((uSetting) - SPI_STARTBOOLRANGE) / 2)
  49. #define UPBOOLPointer(pdw, uSetting) \
  50. (pdw + (UPBOOLIndex(uSetting) / 32))
  51. #define UPBOOLMask(uSetting) \
  52. (1 << (UPBOOLIndex(uSetting) - ((UPBOOLIndex(uSetting) / 32) * 32)))
  53. #define ClearUPBOOL(pdw, uSetting) \
  54. (*UPBOOLPointer(pdw, uSetting) &= ~(UPBOOLMask(uSetting)))
  55. ////////////////////////////////////////////////////////////
  56. //
  57. // Debugging
  58. //
  59. #if DBG
  60. extern "C" ULONG DbgPrint(PCH Format, ...);
  61. #define DBGMSG(MsgAndArgs) \
  62. { \
  63. DbgPrint MsgAndArgs; \
  64. }
  65. #else
  66. #define DBGMSG
  67. #endif
  68. //
  69. // Route ASSERT.
  70. //
  71. #undef ASSERT
  72. #if DBG
  73. #define ASSERT(expr) if (!(expr)) \
  74. { DBGMSG(("Failure at Line %d in %s\n",__LINE__, TEXT##(__FILE__))); \
  75. DebugBreak(); }
  76. #else
  77. #define ASSERT(expr)
  78. #endif
  79. //
  80. // Internal Prototypes
  81. //
  82. DWORD NotifyThemes();
  83. DWORD NotifyGdiPlus();
  84. DWORD CreateSystemSid(PSID *ppSystemSid);
  85. DWORD SetRegKeyAcls(HANDLE hTokenForLoggedOnUser, HKEY hKey);
  86. //
  87. // Internal Types
  88. //
  89. typedef struct
  90. {
  91. BOOL pfEnabled;
  92. LPCTSTR pszRegKey;
  93. LPCTSTR pszRegValue;
  94. LPCTSTR pszRegData;
  95. DWORD cbSize;
  96. DWORD dwType;
  97. } TSPERFFLAG;
  98. //
  99. // Globals
  100. //
  101. const LPTSTR g_ActiveDesktopKey = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Remote\\%d");
  102. const LPTSTR g_ThemesKey = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager\\Remote\\%d");
  103. const LPTSTR g_UserKey = TEXT("Remote\\%d\\Control Panel\\Desktop");
  104. const LPTSTR g_GdiPlusKey = TEXT("Remote\\%d\\GdiPlus");
  105. UINT g_GdiPlusNotifyMsg = 0;
  106. const LPTSTR g_GdiPlusNotifyMsgStr = TS_GDIPLUS_NOTIFYMSG_STR;
  107. static const DWORD g_dwZeroValue = 0;
  108. static const DWORD g_dwFontTypeStandard = 1; //Cleartype is 2
  109. DWORD
  110. SetPerfFlagInReg(
  111. HANDLE hTokenForLoggedOnUser,
  112. HKEY userHiveKey,
  113. DWORD sessionID,
  114. LPCTSTR pszRegKey,
  115. LPCTSTR pszRegValue,
  116. DWORD dwType,
  117. void * pData,
  118. DWORD cbSize,
  119. BOOL fEnable
  120. )
  121. /*++
  122. Routine Description:
  123. Set a single perf flag, if enabled.
  124. Arguments:
  125. Return Value:
  126. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  127. --*/
  128. {
  129. TCHAR szRegKey[MAX_PATH+64]; // 64 characters for the session ID, just to be safe.
  130. DWORD result = ERROR_SUCCESS;
  131. HKEY hKey = NULL;
  132. DWORD disposition;
  133. if (!fEnable) {
  134. goto CLEANUPANDEXIT;
  135. }
  136. //
  137. // Create or open the key.
  138. //
  139. wsprintf(szRegKey, pszRegKey, sessionID);
  140. result = RegCreateKeyEx(userHiveKey, szRegKey, 0, L"",
  141. REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
  142. &hKey, &disposition);
  143. if (result != ERROR_SUCCESS) {
  144. DBGMSG(("RegCreateKeyEx: %08X\n", result));
  145. goto CLEANUPANDEXIT;
  146. }
  147. #ifdef UNIT_TEST
  148. goto CLEANUPANDEXIT;
  149. #endif
  150. //
  151. // Make it available to SYSTEM, only.
  152. //
  153. if (disposition == REG_CREATED_NEW_KEY) {
  154. result = SetRegKeyAcls(hTokenForLoggedOnUser, hKey);
  155. if (result != ERROR_SUCCESS) {
  156. DBGMSG(("RegAcls: %08X\n", result));
  157. goto CLEANUPANDEXIT;
  158. }
  159. }
  160. //
  161. // Set the reg value.
  162. //
  163. result = RegSetValueEx(hKey, pszRegValue, 0, dwType, (PBYTE)pData, cbSize);
  164. if (result != ERROR_SUCCESS) {
  165. DBGMSG(("RegSetValue: %08X\n", result));
  166. }
  167. CLEANUPANDEXIT:
  168. if (hKey != NULL) {
  169. RegCloseKey(hKey);
  170. }
  171. return result;
  172. }
  173. DWORD
  174. SetPerfFlags(
  175. HANDLE hTokenForLoggedOnUser,
  176. HKEY userHiveKey,
  177. DWORD sessionID,
  178. DWORD filter,
  179. TSPERFFLAG flags[],
  180. DWORD count
  181. )
  182. /*++
  183. Routine Description:
  184. Set all perf flags.
  185. Arguments:
  186. Return Value:
  187. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  188. --*/
  189. {
  190. DWORD nIndex;
  191. DWORD result = ERROR_SUCCESS;
  192. for (nIndex = 0; (result==ERROR_SUCCESS) && (nIndex<count); nIndex++) {
  193. result = SetPerfFlagInReg(
  194. hTokenForLoggedOnUser,
  195. userHiveKey,
  196. sessionID,
  197. flags[nIndex].pszRegKey, flags[nIndex].pszRegValue,
  198. flags[nIndex].dwType, (void *) flags[nIndex].pszRegData,
  199. flags[nIndex].cbSize, flags[nIndex].pfEnabled
  200. );
  201. }
  202. return result;
  203. }
  204. DWORD
  205. BuildPerfFlagArray(
  206. HKEY hkcu,
  207. DWORD filter,
  208. OUT TSPERFFLAG **flagArray,
  209. OUT DWORD *count,
  210. DWORD **userPreferencesMask
  211. )
  212. /*++
  213. Routine Description:
  214. Generate the perf flag array from the filter.
  215. Arguments:
  216. hkcu - Logged on user's HKCU.
  217. filter - Filter
  218. flagArray - Array returned here. Should be free'd with LocalFree
  219. count - Number of elements in returned array.
  220. userPreferencesMask - User preferences mask buffer.
  221. Return Value:
  222. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  223. --*/
  224. {
  225. DWORD result = ERROR_SUCCESS;
  226. DWORD ofs;
  227. HKEY hkey = NULL;
  228. DWORD sz;
  229. ofs = 0;
  230. //
  231. // Need to increase this if any new elements are added!
  232. //
  233. *flagArray = (TSPERFFLAG *)LocalAlloc(LPTR, sizeof(TSPERFFLAG) * NUM_TSPERFFLAGS);
  234. if (*flagArray == NULL) {
  235. result = GetLastError();
  236. DBGMSG(("LocalAlloc: %08X\n", result));
  237. goto CLEANUPANDEXIT;
  238. }
  239. //
  240. // Active Desktop
  241. //
  242. (*flagArray)[ofs].pfEnabled = filter & TS_PERF_DISABLE_WALLPAPER;
  243. (*flagArray)[ofs].pszRegKey = g_ActiveDesktopKey;
  244. (*flagArray)[ofs].pszRegValue = TEXT("ActiveDesktop");
  245. (*flagArray)[ofs].pszRegData = TEXT("Force Blank");
  246. (*flagArray)[ofs].cbSize = sizeof(TEXT("Force Blank"));
  247. (*flagArray)[ofs].dwType = REG_SZ; ofs++;
  248. //
  249. // TaskbarAnimations
  250. //
  251. (*flagArray)[ofs].pfEnabled = filter & TS_PERF_DISABLE_MENUANIMATIONS;
  252. (*flagArray)[ofs].pszRegKey = g_ActiveDesktopKey;
  253. (*flagArray)[ofs].pszRegValue = TEXT("TaskbarAnimations");
  254. (*flagArray)[ofs].pszRegData = (LPWSTR)&g_dwZeroValue;
  255. (*flagArray)[ofs].cbSize = sizeof(DWORD);
  256. (*flagArray)[ofs].dwType = REG_DWORD; ofs++;
  257. //
  258. // Wallpaper
  259. //
  260. (*flagArray)[ofs].pfEnabled = filter & TS_PERF_DISABLE_WALLPAPER;
  261. (*flagArray)[ofs].pszRegKey = g_UserKey;
  262. (*flagArray)[ofs].pszRegValue = TEXT("Wallpaper");
  263. (*flagArray)[ofs].pszRegData = TEXT("");
  264. (*flagArray)[ofs].cbSize = sizeof(TEXT(""));
  265. (*flagArray)[ofs].dwType = REG_SZ; ofs++;
  266. //
  267. // Themes
  268. //
  269. (*flagArray)[ofs].pfEnabled = filter & TS_PERF_DISABLE_THEMING;
  270. (*flagArray)[ofs].pszRegKey = g_ThemesKey;
  271. (*flagArray)[ofs].pszRegValue = TEXT("ThemeActive");
  272. (*flagArray)[ofs].pszRegData = TEXT("0");
  273. (*flagArray)[ofs].cbSize = sizeof(TEXT("0"));
  274. (*flagArray)[ofs].dwType = REG_SZ; ofs++;
  275. //
  276. // Full Window Drag
  277. //
  278. (*flagArray)[ofs].pfEnabled = filter & TS_PERF_DISABLE_FULLWINDOWDRAG;
  279. (*flagArray)[ofs].pszRegKey = g_UserKey;
  280. (*flagArray)[ofs].pszRegValue = TEXT("DragFullWindows");
  281. (*flagArray)[ofs].pszRegData = TEXT("0");
  282. (*flagArray)[ofs].cbSize = sizeof(TEXT("0"));
  283. (*flagArray)[ofs].dwType = REG_SZ; ofs++;
  284. //
  285. // Smooth Scroll
  286. //
  287. (*flagArray)[ofs].pfEnabled = filter & TS_PERF_DISABLE_MENUANIMATIONS;
  288. (*flagArray)[ofs].pszRegKey = g_UserKey;
  289. (*flagArray)[ofs].pszRegValue = TEXT("SmoothScroll");
  290. (*flagArray)[ofs].pszRegData = TEXT("No");
  291. (*flagArray)[ofs].cbSize = sizeof(TEXT("No"));
  292. (*flagArray)[ofs].dwType = REG_SZ; ofs++;
  293. //
  294. // Cursor Blinking
  295. //
  296. (*flagArray)[ofs].pfEnabled = filter & TS_PERF_DISABLE_CURSORSETTINGS;
  297. (*flagArray)[ofs].pszRegKey = g_UserKey;
  298. (*flagArray)[ofs].pszRegValue = TEXT("CursorBlinkRate");
  299. (*flagArray)[ofs].pszRegData = BLINK_OFF;
  300. (*flagArray)[ofs].cbSize = sizeof(BLINK_OFF);
  301. (*flagArray)[ofs].dwType = REG_SZ; ofs++;
  302. //
  303. // Font smoothing type
  304. //
  305. (*flagArray)[ofs].pfEnabled = filter & TS_PERF_DISABLE_CURSOR_SHADOW;
  306. (*flagArray)[ofs].pszRegKey = g_UserKey;
  307. (*flagArray)[ofs].pszRegValue = TEXT("FontSmoothingType");
  308. (*flagArray)[ofs].pszRegData = (LPWSTR)&g_dwFontTypeStandard;
  309. (*flagArray)[ofs].cbSize = sizeof(DWORD);
  310. (*flagArray)[ofs].dwType = REG_DWORD; ofs++;
  311. //
  312. // Enhanced graphics rendering
  313. //
  314. (*flagArray)[ofs].pfEnabled = filter & TS_PERF_ENABLE_ENHANCED_GRAPHICS;
  315. (*flagArray)[ofs].pszRegKey = g_GdiPlusKey;
  316. (*flagArray)[ofs].pszRegValue = TEXT("HighQualityRender");
  317. (*flagArray)[ofs].pszRegData = TEXT("Yes");
  318. (*flagArray)[ofs].cbSize = sizeof(TEXT("Yes"));
  319. (*flagArray)[ofs].dwType = REG_SZ; ofs++;
  320. //
  321. // Set the User Preference Mask
  322. // (We won't consider any failures to read reg keys, etc. below to be fatal.)
  323. //
  324. if ((filter & TS_PERF_DISABLE_MENUANIMATIONS) || (filter & TS_PERF_DISABLE_CURSOR_SHADOW)) {
  325. DWORD err = RegOpenKey(
  326. hkcu,
  327. TEXT("Control Panel\\Desktop"),
  328. &hkey
  329. );
  330. if (err != ERROR_SUCCESS) {
  331. DBGMSG(("RegOpenKey: %08X\n", err));
  332. goto CLEANUPANDEXIT;
  333. }
  334. //
  335. // Get the size of the UserPreferences mask
  336. //
  337. err = RegQueryValueEx(
  338. hkey,
  339. TEXT("UserPreferencesMask"),
  340. NULL,
  341. NULL,
  342. NULL,
  343. &sz
  344. );
  345. if (err != ERROR_SUCCESS) {
  346. DBGMSG(("RegQueryValue: %08X\n", err));
  347. goto CLEANUPANDEXIT;
  348. }
  349. //
  350. // Allocate the mask.
  351. //
  352. *userPreferencesMask = (DWORD *)LocalAlloc(LPTR, sz);
  353. if (*userPreferencesMask == NULL) {
  354. err = GetLastError();
  355. DBGMSG(("LocalAlloc: %08X\n", result));
  356. goto CLEANUPANDEXIT;
  357. }
  358. //
  359. // Fetch it.
  360. //
  361. err = RegQueryValueEx(
  362. hkey,
  363. TEXT("UserPreferencesMask"),
  364. NULL,
  365. NULL,
  366. (LPBYTE)*userPreferencesMask,
  367. &sz
  368. );
  369. if (err != ERROR_SUCCESS) {
  370. DBGMSG(("RegQueryValue: %08X\n", err));
  371. goto CLEANUPANDEXIT;
  372. }
  373. //
  374. // Modify the existing User Preference Mask
  375. //
  376. if (filter & TS_PERF_DISABLE_CURSOR_SHADOW) {
  377. ClearUPBOOL(*userPreferencesMask, SPI_GETCURSORSHADOW);
  378. ClearUPBOOL(*userPreferencesMask, SPI_SETCURSORSHADOW);
  379. }
  380. if (filter & TS_PERF_DISABLE_MENUANIMATIONS) {
  381. ClearUPBOOL(*userPreferencesMask, SPI_GETMENUANIMATION);
  382. ClearUPBOOL(*userPreferencesMask, SPI_SETMENUANIMATION);
  383. ClearUPBOOL(*userPreferencesMask, SPI_GETMENUFADE);
  384. ClearUPBOOL(*userPreferencesMask, SPI_SETMENUFADE);
  385. ClearUPBOOL(*userPreferencesMask, SPI_GETTOOLTIPANIMATION);
  386. ClearUPBOOL(*userPreferencesMask, SPI_SETTOOLTIPANIMATION);
  387. ClearUPBOOL(*userPreferencesMask, SPI_GETTOOLTIPFADE);
  388. ClearUPBOOL(*userPreferencesMask, SPI_SETTOOLTIPFADE);
  389. ClearUPBOOL(*userPreferencesMask, SPI_GETCOMBOBOXANIMATION);
  390. ClearUPBOOL(*userPreferencesMask, SPI_SETCOMBOBOXANIMATION);
  391. ClearUPBOOL(*userPreferencesMask, SPI_GETLISTBOXSMOOTHSCROLLING);
  392. ClearUPBOOL(*userPreferencesMask, SPI_SETLISTBOXSMOOTHSCROLLING);
  393. }
  394. (*flagArray)[ofs].pfEnabled = TRUE;
  395. (*flagArray)[ofs].pszRegKey = g_UserKey;
  396. (*flagArray)[ofs].pszRegValue = TEXT("UserPreferencesMask");
  397. (*flagArray)[ofs].pszRegData = (LPWSTR)*userPreferencesMask;
  398. (*flagArray)[ofs].cbSize = sz;
  399. (*flagArray)[ofs].dwType = REG_BINARY; ofs++;
  400. }
  401. CLEANUPANDEXIT:
  402. if (hkey != NULL) {
  403. RegCloseKey(hkey);
  404. }
  405. *count = ofs;
  406. return result;
  407. }
  408. DWORD
  409. RDFilter_ApplyRemoteFilter(
  410. HANDLE hLoggedOnUserToken,
  411. DWORD filter,
  412. BOOL userLoggingOn,
  413. DWORD flags
  414. )
  415. /*++
  416. Routine Description:
  417. Applies specified filter for the active TS session by adjusting visual
  418. desktop settings. Also notifies shell, etc. that a remote filter is in place.
  419. Any previous filter settings will be destroyed and overwritten.
  420. The context for this call should be that of the logged on user and the call
  421. should be made within the session for which the filter is intended to be
  422. applied.
  423. Arguments:
  424. hLoggedOnUserToken - Token for the logged on user.
  425. filter - Visual desktop filter bits as defined in tsperf.h
  426. userLoggingOn - True if this being called in the context of a user
  427. logging on to a session.
  428. flags - Flags
  429. Return Value:
  430. ERROR_SUCCESS on success.
  431. --*/
  432. {
  433. DWORD result = ERROR_SUCCESS;
  434. HRESULT hr;
  435. DWORD ourSessionID;
  436. IPropertyBag *propBag = NULL;
  437. VARIANT vbool;
  438. DWORD tmp;
  439. TSPERFFLAG *flagArray = NULL;
  440. DWORD flagCount;
  441. TCHAR szRegKey[MAX_PATH + 64]; // For the session ID ... to be safe.
  442. HKEY hParentKey = NULL;
  443. BOOL impersonated = FALSE;
  444. DWORD *userPreferencesMask = NULL;
  445. HRESULT hrCoInit = CoInitialize(0);
  446. //
  447. // Get our session ID.
  448. //
  449. if (!ProcessIdToSessionId(GetCurrentProcessId(), &ourSessionID)) {
  450. result = GetLastError();
  451. DBGMSG(("ProcessIdToSessionId: %08X\n", result));
  452. goto CLEANUPANDEXIT;
  453. }
  454. //
  455. // Impersonate the logged on user.
  456. //
  457. if (!ImpersonateLoggedOnUser(hLoggedOnUserToken)) {
  458. result = GetLastError();
  459. DBGMSG(("ImpersonateUser1: %08X.\n", result));
  460. goto CLEANUPANDEXIT;
  461. }
  462. impersonated = TRUE;
  463. //
  464. // Open the current user's reg key.
  465. //
  466. result = RegOpenCurrentUser(KEY_ALL_ACCESS, &hParentKey);
  467. RevertToSelf();
  468. impersonated = FALSE;
  469. if (result != ERROR_SUCCESS) {
  470. DBGMSG(("RegOpenCurrentUser: %08X\n", result));
  471. goto CLEANUPANDEXIT;
  472. }
  473. //
  474. // Delete all existing filters for our session.
  475. //
  476. wsprintf(szRegKey, g_ActiveDesktopKey, ourSessionID);
  477. RegDeleteKey(hParentKey, szRegKey);
  478. wsprintf(szRegKey, g_ThemesKey, ourSessionID);
  479. RegDeleteKey(hParentKey, szRegKey);
  480. wsprintf(szRegKey, g_UserKey, ourSessionID);
  481. RegDeleteKey(hParentKey, szRegKey);
  482. wsprintf(szRegKey, g_GdiPlusKey, ourSessionID);
  483. RegDeleteKey(hParentKey, szRegKey);
  484. //
  485. // Skip setting the reg keys if there is no filter, as an optimization.
  486. //
  487. if (filter) {
  488. //
  489. // Convert the filter into reg keys and reg settings.
  490. //
  491. result = BuildPerfFlagArray(hParentKey, filter, &flagArray, &flagCount, &userPreferencesMask);
  492. if (result != ERROR_SUCCESS) {
  493. goto CLEANUPANDEXIT;
  494. }
  495. //
  496. // Apply it.
  497. //
  498. result = SetPerfFlags(hLoggedOnUserToken, hParentKey, ourSessionID,
  499. filter, flagArray, flagCount);
  500. if (result != ERROR_SUCCESS) {
  501. goto CLEANUPANDEXIT;
  502. }
  503. }
  504. //
  505. // Impersonate the logged on user.
  506. //
  507. if (!ImpersonateLoggedOnUser(hLoggedOnUserToken)) {
  508. result = GetLastError();
  509. DBGMSG(("ImpersonateUser2: %08X.\n", result));
  510. goto CLEANUPANDEXIT;
  511. }
  512. impersonated = TRUE;
  513. //
  514. // Notify USER that we are remote.
  515. //
  516. if (!(flags & RDFILTER_SKIPUSERREFRESH)) {
  517. DWORD userFlags = UPUSP_REMOTESETTINGS;
  518. if (userLoggingOn) {
  519. // USER needs to refresh all settings.
  520. userFlags|= UPUSP_USERLOGGEDON;
  521. }
  522. else {
  523. // USER should avoid a complete refresh.
  524. userFlags |= UPUSP_POLICYCHANGE;
  525. }
  526. if (!UpdatePerUserSystemParameters(NULL, userFlags)) {
  527. result = GetLastError();
  528. DBGMSG(("UpdatePerUserSystemParameters1: %08X\n", result));
  529. goto CLEANUPANDEXIT;
  530. }
  531. }
  532. //
  533. // Notify Themes that we are remote.
  534. //
  535. if (!(flags & RDFILTER_SKIPTHEMESREFRESH)) {
  536. result = NotifyThemes();
  537. if (result != ERROR_SUCCESS) {
  538. goto CLEANUPANDEXIT;
  539. }
  540. }
  541. //
  542. // Notify Active Desktop that we are remote.
  543. //
  544. if (!(flags & RDFILTER_SKIPSHELLREFRESH)) {
  545. hr = CoCreateInstance(
  546. CLSID_ActiveDesktop, NULL,
  547. CLSCTX_ALL, IID_IPropertyBag,
  548. (LPVOID*)&propBag
  549. );
  550. if (hr != S_OK) {
  551. DBGMSG(("CoCreateInstance: %08X\n", hr));
  552. DBGMSG(("Probably didn't call CoInitialize.\n"));
  553. result = HRESULT_CODE(hr);
  554. goto CLEANUPANDEXIT;
  555. }
  556. vbool.vt = VT_BOOL;
  557. vbool.boolVal = VARIANT_TRUE;
  558. hr = propBag->Write(L"TSConnectEvent", &vbool);
  559. if (hr != S_OK) {
  560. DBGMSG(("propBag->Write: %08X\n", hr));
  561. result = HRESULT_CODE(hr);
  562. goto CLEANUPANDEXIT;
  563. }
  564. }
  565. CLEANUPANDEXIT:
  566. if (impersonated) {
  567. RevertToSelf();
  568. }
  569. if (propBag != NULL) {
  570. propBag->Release();
  571. }
  572. if (flagArray != NULL) {
  573. LocalFree(flagArray);
  574. }
  575. if (hParentKey != NULL) {
  576. RegCloseKey(hParentKey);
  577. }
  578. if (userPreferencesMask != NULL) {
  579. LocalFree(userPreferencesMask);
  580. }
  581. //
  582. // On failure, we need to clear any remote filter settings that may
  583. // have succeeded.
  584. //
  585. if (result != ERROR_SUCCESS) {
  586. RDFilter_ClearRemoteFilter(hLoggedOnUserToken, userLoggingOn, flags);
  587. }
  588. if ((hrCoInit == S_OK) || (hrCoInit == S_FALSE)) {
  589. CoUninitialize();
  590. }
  591. return result;
  592. }
  593. VOID
  594. RDFilter_ClearRemoteFilter(
  595. HANDLE hLoggedOnUserToken,
  596. BOOL userLoggingOn,
  597. DWORD flags
  598. )
  599. /*++
  600. Routine Description:
  601. Removes existing remote filter settings and notifies shell, etc. that
  602. a remote filter is no longer in place for the active TS session.
  603. The context for this call should be that of the session for which the
  604. filter is intended to be applied.
  605. Arguments:
  606. hLoggedOnUserToken - Token for logged fon user.
  607. userLoggingOn - True if the user is actively logging on.
  608. Return Value:
  609. This function will continuing attempting to clear the filter for
  610. all associated components even on failure cases, so we cannot
  611. say definitively whether we have failed or succeeded to clear the
  612. filter.
  613. --*/
  614. {
  615. DWORD result = ERROR_SUCCESS;
  616. HRESULT hr;
  617. IPropertyBag *propBag = NULL;
  618. VARIANT vbool;
  619. DWORD ourSessionID;
  620. TCHAR szRegKey[MAX_PATH + 64]; // +64 for the session ID to be safe.
  621. HKEY hParentKey = NULL;
  622. HANDLE hImp = NULL;
  623. BOOL impersonated = FALSE;
  624. HRESULT hrCoInit = CoInitialize(0);
  625. //
  626. // Get our session ID.
  627. //
  628. if (!ProcessIdToSessionId(GetCurrentProcessId(), &ourSessionID)) {
  629. result = GetLastError();
  630. DBGMSG(("ProcessIdToSessionId: %08X\n", result));
  631. goto CLEANUPANDEXIT;
  632. }
  633. //
  634. // Impersonate the logged on user.
  635. //
  636. if (!ImpersonateLoggedOnUser(hLoggedOnUserToken)) {
  637. result = GetLastError();
  638. DBGMSG(("ImpersonateUser3: %08X.\n", result));
  639. goto CLEANUPANDEXIT;
  640. }
  641. impersonated = TRUE;
  642. //
  643. // Open the current user's reg key.
  644. //
  645. result = RegOpenCurrentUser(KEY_ALL_ACCESS, &hParentKey);
  646. RevertToSelf();
  647. impersonated = FALSE;
  648. if (result != ERROR_SUCCESS) {
  649. DBGMSG(("RegOpenCurrentUser: %08X\n", result));
  650. goto CLEANUPANDEXIT;
  651. }
  652. //
  653. // Whack the relevant remote key.
  654. //
  655. wsprintf(szRegKey, g_ActiveDesktopKey, ourSessionID);
  656. RegDeleteKey(hParentKey, szRegKey);
  657. wsprintf(szRegKey, g_ThemesKey, ourSessionID);
  658. RegDeleteKey(hParentKey, szRegKey);
  659. wsprintf(szRegKey, g_UserKey, ourSessionID);
  660. RegDeleteKey(hParentKey, szRegKey);
  661. wsprintf(szRegKey, g_GdiPlusKey, ourSessionID);
  662. RegDeleteKey(hParentKey, szRegKey);
  663. //
  664. // Impersonate the logged on user.
  665. //
  666. if (!ImpersonateLoggedOnUser(hLoggedOnUserToken)) {
  667. result = GetLastError();
  668. DBGMSG(("ImpersonateUser4: %08X.\n", result));
  669. goto CLEANUPANDEXIT;
  670. }
  671. impersonated = TRUE;
  672. //
  673. // Notify USER that we are not remote. The Policy Change flag indicates that
  674. // a complete refresh should not be performed.
  675. //
  676. if (!(flags & RDFILTER_SKIPUSERREFRESH)) {
  677. DWORD userFlags = UPUSP_REMOTESETTINGS;
  678. if (userLoggingOn) {
  679. // USER needs to refresh all settings.
  680. userFlags |= UPUSP_USERLOGGEDON;
  681. }
  682. else {
  683. // USER should avoid a complete refresh.
  684. userFlags |= UPUSP_POLICYCHANGE;
  685. }
  686. if (!UpdatePerUserSystemParameters(NULL, userFlags)) {
  687. result = GetLastError();
  688. DBGMSG(("UpdatePerUserSystemParameters2: %08X\n", result));
  689. }
  690. }
  691. //
  692. // Notify Themes that we are not remote.
  693. //
  694. if (!(flags & RDFILTER_SKIPTHEMESREFRESH)) {
  695. NotifyThemes();
  696. }
  697. //
  698. // Notify Active Desktop that we are not remote.
  699. //
  700. if (!(flags & RDFILTER_SKIPSHELLREFRESH)) {
  701. hr = CoCreateInstance(
  702. CLSID_ActiveDesktop, NULL,
  703. CLSCTX_ALL, IID_IPropertyBag,
  704. (LPVOID*)&propBag
  705. );
  706. if (hr != S_OK) {
  707. DBGMSG(("CoCreateInstance: %08X\n", hr));
  708. DBGMSG(("Probably didn't call CoInitialize.\n"));
  709. result = HRESULT_CODE(hr);
  710. goto CLEANUPANDEXIT;
  711. }
  712. vbool.vt = VT_BOOL;
  713. vbool.boolVal = VARIANT_FALSE;
  714. hr = propBag->Write(L"TSConnectEvent", &vbool);
  715. if (hr != S_OK) {
  716. DBGMSG(("propBag->Write: %08X\n", hr));
  717. }
  718. }
  719. CLEANUPANDEXIT:
  720. if (impersonated) {
  721. RevertToSelf();
  722. }
  723. if (propBag != NULL) {
  724. propBag->Release();
  725. }
  726. if (hParentKey != NULL) {
  727. RegCloseKey(hParentKey);
  728. }
  729. if ((hrCoInit == S_OK) || (hrCoInit == S_FALSE)) {
  730. CoUninitialize();
  731. }
  732. }
  733. DWORD
  734. NotifyThemes()
  735. /*++
  736. Routine Description:
  737. Notify themes that our remote state has changed.
  738. Arguments:
  739. Return Value:
  740. --*/
  741. {
  742. HMODULE uxthemeLibHandle = NULL;
  743. FARPROC func;
  744. DWORD result = ERROR_SUCCESS;
  745. HRESULT hr;
  746. LPSTR procAddress;
  747. uxthemeLibHandle = LoadLibrary(L"uxtheme.dll");
  748. if (uxthemeLibHandle == NULL) {
  749. result = GetLastError();
  750. DBGMSG(("LoadLibrary: %08X\n", result));
  751. goto CLEANUPANDEXIT;
  752. }
  753. //
  754. // Pass the RefreshThemeForTS func id as an ordinal since it's private.
  755. //
  756. procAddress = (LPSTR)REFRESHTHEMESFORTS_ORDINAL;
  757. func = GetProcAddress(uxthemeLibHandle, (LPCSTR)procAddress);
  758. if (func != NULL) {
  759. hr = (HRESULT) func();
  760. if (hr != S_OK) {
  761. DBGMSG(("RefreshThemeForTS: %08X\n", hr));
  762. result = HRESULT_CODE(hr);
  763. }
  764. }
  765. else {
  766. result = GetLastError();
  767. DBGMSG(("GetProcAddress: %08X\n", result));
  768. }
  769. FreeLibrary(uxthemeLibHandle);
  770. CLEANUPANDEXIT:
  771. return result;
  772. }
  773. DWORD
  774. NotifyGdiPlus()
  775. /*++
  776. Routine Description:
  777. Notify GdiPlus that our remote state has changed.
  778. Arguments:
  779. filter -
  780. Return Value:
  781. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  782. --*/
  783. {
  784. DWORD result = ERROR_SUCCESS;
  785. if (g_GdiPlusNotifyMsg != 0) {
  786. g_GdiPlusNotifyMsg = RegisterWindowMessage(g_GdiPlusNotifyMsgStr);
  787. }
  788. if (g_GdiPlusNotifyMsg != 0) {
  789. PostMessage(HWND_BROADCAST, g_GdiPlusNotifyMsg, 0, 0);
  790. }
  791. else {
  792. result = GetLastError();
  793. }
  794. return result;
  795. }
  796. PSID
  797. GetUserSid(
  798. IN HANDLE hTokenForLoggedOnUser
  799. )
  800. {
  801. /*++
  802. Routine Description:
  803. Allocates memory for psid and returns the psid for the current user
  804. The caller should call FREEMEM to free the memory.
  805. Arguments:
  806. Access Token for the User
  807. Return Value:
  808. if successful, returns the PSID
  809. else, returns NULL
  810. --*/
  811. TOKEN_USER * ptu = NULL;
  812. BOOL bResult;
  813. PSID psid = NULL;
  814. DWORD defaultSize = sizeof(TOKEN_USER);
  815. DWORD Size;
  816. DWORD dwResult;
  817. ptu = (TOKEN_USER *)LocalAlloc(LPTR, defaultSize);
  818. if (ptu == NULL) {
  819. goto CLEANUPANDEXIT;
  820. }
  821. bResult = GetTokenInformation(
  822. hTokenForLoggedOnUser, // Handle to Token
  823. TokenUser, // Token Information Class
  824. ptu, // Buffer for Token Information
  825. defaultSize, // Size of Buffer
  826. &Size); // Return length
  827. if (bResult == FALSE) {
  828. dwResult = GetLastError();
  829. if (dwResult == ERROR_INSUFFICIENT_BUFFER) {
  830. //
  831. //Allocate required memory
  832. //
  833. LocalFree(ptu);
  834. ptu = (TOKEN_USER *)LocalAlloc(LPTR, Size);
  835. if (ptu == NULL) {
  836. goto CLEANUPANDEXIT;
  837. }
  838. else {
  839. defaultSize = Size;
  840. bResult = GetTokenInformation(
  841. hTokenForLoggedOnUser,
  842. TokenUser,
  843. ptu,
  844. defaultSize,
  845. &Size);
  846. if (bResult == FALSE) { //Still failed
  847. DBGMSG(("UMRDPDR:GetTokenInformation Failed, Error: %ld\n", GetLastError()));
  848. goto CLEANUPANDEXIT;
  849. }
  850. }
  851. }
  852. else {
  853. DBGMSG(("UMRDPDR:GetTokenInformation Failed, Error: %ld\n", dwResult));
  854. goto CLEANUPANDEXIT;
  855. }
  856. }
  857. Size = GetLengthSid(ptu->User.Sid);
  858. //
  859. // Allocate memory. This will be freed by the caller.
  860. //
  861. psid = (PSID) LocalAlloc(LPTR, Size);
  862. if (psid != NULL) { // Make sure the allocation succeeded
  863. CopySid(Size, psid, ptu->User.Sid);
  864. }
  865. CLEANUPANDEXIT:
  866. if (ptu != NULL)
  867. LocalFree(ptu);
  868. return psid;
  869. }
  870. DWORD
  871. CreateSystemSid(
  872. PSID *ppSystemSid
  873. )
  874. /*++
  875. Routine Description:
  876. Create a SYSTEM SID.
  877. Arguments:
  878. Return Value:
  879. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  880. --*/
  881. {
  882. DWORD dwStatus = ERROR_SUCCESS;
  883. PSID pSid;
  884. SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_NT_AUTHORITY;
  885. if(AllocateAndInitializeSid(
  886. &SidAuthority,
  887. 1,
  888. SECURITY_LOCAL_SYSTEM_RID,
  889. 0, 0, 0, 0, 0, 0, 0,
  890. &pSid)) {
  891. *ppSystemSid = pSid;
  892. }
  893. else {
  894. dwStatus = GetLastError();
  895. }
  896. return dwStatus;
  897. }
  898. DWORD
  899. SetRegKeyAcls(
  900. HANDLE hTokenForLoggedOnUser,
  901. HKEY hKey
  902. )
  903. /*++
  904. Routine Description:
  905. Set a reg key so that only SYSTEM can modify.
  906. Arguments:
  907. hTokenForLoggedOnUser - Logged on use token.
  908. hKey - Key to set.
  909. Return Value:
  910. ERROR_SUCCESS on success. Otherwise, an error code is returned.
  911. --*/
  912. {
  913. PACL pAcl=NULL;
  914. DWORD result = ERROR_SUCCESS;
  915. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  916. DWORD cbAcl = 0;
  917. PSID pSidSystem = NULL;
  918. PSID pUserSid = NULL;
  919. pSecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(
  920. LPTR, sizeof(SECURITY_DESCRIPTOR)
  921. );
  922. if (pSecurityDescriptor == NULL) {
  923. DBGMSG(("Can't alloc memory for SECURITY_DESCRIPTOR\n"));
  924. result = GetLastError();
  925. goto CLEANUPANDEXIT;
  926. }
  927. //
  928. // Initialize the security descriptor.
  929. //
  930. if (!InitializeSecurityDescriptor(
  931. pSecurityDescriptor,
  932. SECURITY_DESCRIPTOR_REVISION
  933. )) {
  934. result = GetLastError();
  935. DBGMSG(("InitializeSecurityDescriptor: %08X\n", result));
  936. goto CLEANUPANDEXIT;
  937. }
  938. //
  939. // Create the system SID.
  940. //
  941. result = CreateSystemSid(&pSidSystem);
  942. if (result != ERROR_SUCCESS) {
  943. DBGMSG(("CreateSystemSid: %08X\n", result));
  944. goto CLEANUPANDEXIT;
  945. }
  946. //
  947. // Get the user's SID.
  948. //
  949. pUserSid = GetUserSid(hTokenForLoggedOnUser);
  950. if (pUserSid == NULL) {
  951. goto CLEANUPANDEXIT;
  952. }
  953. //
  954. // Get size of memory needed for new DACL.
  955. //
  956. cbAcl = sizeof(ACL);
  957. cbAcl += 1 * (sizeof(ACCESS_ALLOWED_ACE) - // For SYSTEM ACE
  958. sizeof(DWORD) + GetLengthSid(pSidSystem));
  959. cbAcl += 1 * (sizeof(ACCESS_ALLOWED_ACE) - // For User ACE
  960. sizeof(DWORD) + GetLengthSid(pUserSid));
  961. pAcl = (PACL) LocalAlloc(LPTR, cbAcl);
  962. if (pAcl == NULL) {
  963. DBGMSG(("Can't alloc memory for ACL\n"));
  964. result = GetLastError();
  965. goto CLEANUPANDEXIT;
  966. }
  967. //
  968. // Initialize the ACL.
  969. //
  970. if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) {
  971. result = GetLastError();
  972. DBGMSG(("InitializeAcl(): %08X\n", result));
  973. goto CLEANUPANDEXIT;
  974. }
  975. //
  976. // Add the ACE's.
  977. //
  978. if (!AddAccessAllowedAceEx(pAcl,
  979. ACL_REVISION,
  980. //INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  981. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  982. GENERIC_READ | GENERIC_WRITE | GENERIC_ALL,
  983. pSidSystem
  984. )) {
  985. result = GetLastError();
  986. DBGMSG(("AddAccessAllowedAce: %08X\n", result));
  987. goto CLEANUPANDEXIT;
  988. }
  989. if (!AddAccessAllowedAceEx(pAcl,
  990. ACL_REVISION,
  991. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  992. KEY_READ,
  993. pUserSid
  994. )) {
  995. result = GetLastError();
  996. DBGMSG(("AddAccessAllowedAce2: %08X\n", result));
  997. goto CLEANUPANDEXIT;
  998. }
  999. //
  1000. // Add the DACL to the SD
  1001. //
  1002. if (!SetSecurityDescriptorDacl(pSecurityDescriptor,
  1003. TRUE, pAcl, FALSE)) {
  1004. result = GetLastError();
  1005. DBGMSG(("SetSecurityDescriptorDacl: %08X\n", result));
  1006. goto CLEANUPANDEXIT;
  1007. }
  1008. //
  1009. // Set the registry DACL
  1010. //
  1011. result = RegSetKeySecurity(
  1012. hKey,
  1013. DACL_SECURITY_INFORMATION,
  1014. pSecurityDescriptor
  1015. );
  1016. if (result != ERROR_SUCCESS) {
  1017. DBGMSG(("RegSetKeySecurity: %08X\n", result));
  1018. goto CLEANUPANDEXIT;
  1019. }
  1020. CLEANUPANDEXIT:
  1021. if (pUserSid != NULL) {
  1022. LocalFree(pUserSid);
  1023. }
  1024. if (pSidSystem != NULL) {
  1025. FreeSid(pSidSystem);
  1026. }
  1027. if (pAcl != NULL) {
  1028. LocalFree(pAcl);
  1029. }
  1030. if (pSecurityDescriptor != NULL) {
  1031. LocalFree(pSecurityDescriptor);
  1032. }
  1033. return result;
  1034. }
  1035. #if DBG
  1036. ULONG
  1037. DbgPrint(
  1038. LPTSTR Format,
  1039. ...
  1040. )
  1041. {
  1042. va_list arglist;
  1043. WCHAR Buffer[512];
  1044. INT cb;
  1045. //
  1046. // Format the output into a buffer and then print it.
  1047. //
  1048. va_start(arglist, Format);
  1049. cb = _vsntprintf(Buffer, sizeof(Buffer), Format, arglist);
  1050. if (cb == -1) { // detect buffer overflow
  1051. Buffer[sizeof(Buffer) - 3] = 0;
  1052. }
  1053. wcscat(Buffer, L"\r\n");
  1054. OutputDebugString(Buffer);
  1055. va_end(arglist);
  1056. return 0;
  1057. }
  1058. #endif
  1059. ////////////////////////////////////////////////////////////////////////////////
  1060. //
  1061. // Unit-Test
  1062. //
  1063. #ifdef UNIT_TEST
  1064. BOOL
  1065. GetCheckBox(
  1066. HWND hwndDlg,
  1067. UINT idControl
  1068. )
  1069. {
  1070. return (BST_CHECKED == SendMessage((HWND)GetDlgItem(hwndDlg, idControl), BM_GETCHECK, 0, 0));
  1071. }
  1072. INT_PTR OnCommand(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  1073. {
  1074. BOOL fHandled = FALSE; // Not handled
  1075. UINT idControl = LOWORD(wParam);
  1076. UINT idAction = HIWORD(wParam);
  1077. DWORD result;
  1078. DWORD filter;
  1079. static HANDLE tokenHandle = NULL;
  1080. if (tokenHandle == NULL) {
  1081. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS,
  1082. &tokenHandle)) {
  1083. ASSERT(FALSE);
  1084. return FALSE;
  1085. }
  1086. }
  1087. switch(idControl)
  1088. {
  1089. case ID_QUIT:
  1090. RDFilter_ClearRemoteFilter(tokenHandle, FALSE);
  1091. EndDialog(hDlg, 0);
  1092. break;
  1093. case ID_APPLYFILTER:
  1094. filter = 0;
  1095. if (GetCheckBox(hDlg, IDC_DISABLEBACKGROUND)) {
  1096. filter |= TS_PERF_DISABLE_WALLPAPER;
  1097. }
  1098. if (GetCheckBox(hDlg, IDC_DISABLEFULLWINDOWDRAG)) {
  1099. filter |= TS_PERF_DISABLE_FULLWINDOWDRAG;
  1100. }
  1101. if (GetCheckBox(hDlg, IDC_DISABLEMENUFADEANDSLIDE)) {
  1102. filter |= TS_PERF_DISABLE_MENUANIMATIONS;
  1103. }
  1104. if (GetCheckBox(hDlg, IDC_DISABLETHEMES)) {
  1105. filter |= TS_PERF_DISABLE_THEMING;
  1106. }
  1107. result = RDFilter_ApplyRemoteFilter(tokenHandle, filter, FALSE);
  1108. ASSERT(result == ERROR_SUCCESS);
  1109. break;
  1110. case ID_REMOVEFILTER:
  1111. RDFilter_ClearRemoteFilter(tokenHandle, FALSE);
  1112. break;
  1113. default:
  1114. break;
  1115. }
  1116. return fHandled;
  1117. }
  1118. INT_PTR
  1119. TSPerfDialogProc(
  1120. HWND hDlg,
  1121. UINT wMsg,
  1122. WPARAM wParam,
  1123. LPARAM lParam
  1124. )
  1125. {
  1126. INT_PTR fHandled = TRUE; // handled
  1127. DWORD result;
  1128. static HANDLE tokenHandle = NULL;
  1129. if (tokenHandle == NULL) {
  1130. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS,
  1131. &tokenHandle)) {
  1132. ASSERT(FALSE);
  1133. return FALSE;
  1134. }
  1135. }
  1136. switch (wMsg)
  1137. {
  1138. case WM_INITDIALOG:
  1139. break;
  1140. case WM_COMMAND:
  1141. fHandled = OnCommand(hDlg, wMsg, wParam, lParam);
  1142. break;
  1143. case WM_CLOSE:
  1144. RDFilter_ClearRemoteFilter(tokenHandle, FALSE);
  1145. EndDialog(hDlg, 0);
  1146. fHandled = TRUE;
  1147. break;
  1148. default:
  1149. fHandled = FALSE; // Not handled
  1150. break;
  1151. }
  1152. return fHandled;
  1153. }
  1154. int PASCAL WinMain(
  1155. HINSTANCE hInstCurrent,
  1156. HINSTANCE hInstPrev,
  1157. LPSTR pszCmdLine,
  1158. int nCmdShow
  1159. )
  1160. {
  1161. WINSTATIONCLIENT ClientData;
  1162. DWORD Length;
  1163. DWORD result;
  1164. WCHAR buf[MAX_PATH];
  1165. //
  1166. // Get the Remote Desktop (TS) visual filter, if it is defined.
  1167. //
  1168. if (!WinStationQueryInformationW(
  1169. SERVERNAME_CURRENT,
  1170. LOGONID_CURRENT,
  1171. WinStationClient,
  1172. &ClientData,
  1173. sizeof(ClientData),
  1174. &Length)) {
  1175. MessageBox(NULL, L"WinStationQueryInformation failed.", L"Message", MB_OK);
  1176. }
  1177. else {
  1178. wsprintf(buf, L"Filter for this TS session is: %08X", ClientData.PerformanceFlags);
  1179. MessageBox(NULL, buf, L"Message", MB_OK);
  1180. }
  1181. INT_PTR nResult = DialogBox(hInstCurrent,
  1182. MAKEINTRESOURCE(IDD_DISABLEDIALOG),
  1183. NULL, TSPerfDialogProc);
  1184. return 0;
  1185. }
  1186. #endif