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.

1805 lines
48 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. umrdpdr.c
  5. Abstract:
  6. User-Mode Component for RDP Device Management
  7. This module is included in the TermSrv tsnotify.dll, which is attached
  8. to WINLOGON.EXE. This module, after being entered, creates a background
  9. thread that is used by the RDPDR kernel-mode component (rdpdr.sys) to perform
  10. user-mode device management operations.
  11. The background thread communicates with the rdpdr.sys via IOCTL calls.
  12. Author:
  13. TadB
  14. Revision History:
  15. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include <nt.h>
  19. #include <ntioapi.h>
  20. #include <ntrtl.h>
  21. #include <nturtl.h>
  22. #include <windef.h>
  23. #include <winbase.h>
  24. #include <winuser.h>
  25. #include <string.h>
  26. #ifdef UNITTEST
  27. #include <stdio.h>
  28. #endif
  29. #include <stdlib.h>
  30. #include <winreg.h>
  31. #include <shlobj.h>
  32. #include <winspool.h>
  33. #include <rdpdr.h>
  34. #include "drdbg.h"
  35. #include "drdevlst.h"
  36. #include "umrdpprn.h"
  37. #include "umrdpdr.h"
  38. #include "umrdpdrv.h"
  39. #include <winsta.h>
  40. #include "tsnutl.h"
  41. #include "wtblobj.h"
  42. #include "errorlog.h"
  43. ////////////////////////////////////////////////////////
  44. //
  45. // Defines
  46. //
  47. //DWORD GLOBAL_DEBUG_FLAGS=0xFFFF;
  48. DWORD GLOBAL_DEBUG_FLAGS=0x0;
  49. // TS Network Provider Name
  50. WCHAR ProviderName[MAX_PATH];
  51. // Check if we are running on PTS platform
  52. BOOL fRunningOnPTS = FALSE;
  53. #ifndef BOOL
  54. #define BOOL int
  55. #endif
  56. #define PRINTUILIBNAME TEXT("printui.dll")
  57. // PrintUI "Run INF Install" wsprintf Format String. %s fields are, in order:
  58. // Printer Name, Location of INF Directory, Port Name, Driver Name
  59. #define PUI_RUNINFSTR L"/Hwzqu /if /b \"%s\" /f \"%s\\inf\\ntprint.inf\" /r \"%s\" /m \"%s\""
  60. // Console Session ID
  61. #define CONSOLESESSIONID 0
  62. // Get a numeric representation of our session ID.
  63. #if defined(UNITTEST)
  64. ULONG g_SessionId = 0;
  65. #else
  66. extern ULONG g_SessionId;
  67. #endif
  68. #define GETTHESESSIONID() g_SessionId
  69. // Initial size of IOCTL output buffer (big enough for the event header
  70. // and a "buffer too small" event.
  71. #define INITIALIOCTLOUTPUTBUFSIZE (sizeof(RDPDRDVMGR_EVENTHEADER) + \
  72. sizeof(RDPDR_BUFFERTOOSMALL))
  73. #if defined(UNITTEST)
  74. // Test driver name.
  75. #define TESTDRIVERNAME L"AGFA-AccuSet v52.3"
  76. #define TESTPNPNAME L""
  77. #define TESTPRINTERNAME TESTDRIVERNAME
  78. // Test port name.
  79. #define TESTPORTNAME L"LPT1"
  80. #endif
  81. // Number of ms to wait for background thread to exit.
  82. #define KILLTHREADTIMEOUT (1000 * 8 * 60) // 8 minutes.
  83. //#define KILLTHREADTIMEOUT (1000 * 30)
  84. //
  85. // Registry Locations
  86. //
  87. #define THISMODULEENABLEDREGKEY \
  88. L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\Wds\\rdpwd"
  89. #define THISMODULEENABLEDREGVALUE \
  90. L"fEnablePrintRDR"
  91. #define DEBUGLEVELREGKEY \
  92. L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\Wds\\rdpwd"
  93. #define TSNETWORKPROVIDER \
  94. L"SYSTEM\\CurrentControlSet\\Services\\RDPNP\\NetworkProvider"
  95. #define TSNETWORKPROVIDERNAME \
  96. L"Name"
  97. #define DEBUGLEVELREGVALUE \
  98. L"UMRDPDRDebugLevel"
  99. ////////////////////////////////////////////////////////
  100. //
  101. // Globals to this Module
  102. //
  103. // Event that we will use to terminate the background thread.
  104. HANDLE CloseThreadEvent = NULL;
  105. // Record whether shutdown is currently active.
  106. LONG ShutdownActiveCount = 0;
  107. BOOL g_UMRDPDR_Init = FALSE;
  108. ////////////////////////////////////////////////////////
  109. //
  110. // Internal Prototypes
  111. //
  112. DWORD BackgroundThread(LPVOID tag);
  113. BOOL SetToApplicationDesktop(
  114. OUT HDESK *phDesk
  115. );
  116. void DeleteInstalledDevices(
  117. IN PDRDEVLST deviceList
  118. );
  119. BOOL StopBackgroundThread(
  120. );
  121. BOOL HandleRemoveDeviceEvent(
  122. IN PRDPDR_REMOVEDEVICE evt
  123. );
  124. BOOL UMRDPDR_ResizeBuffer(
  125. IN OUT void **buffer,
  126. IN DWORD bytesRequired,
  127. IN OUT DWORD *bufferSize
  128. );
  129. VOID DispatchNextDeviceEvent(
  130. IN PDRDEVLST deviceList,
  131. IN OUT PBYTE *incomingEventBuffer,
  132. IN OUT DWORD *incomingEventBufferSize,
  133. IN DWORD incomingEventBufferValidBytes
  134. );
  135. VOID CloseThreadEventHandler(
  136. IN HANDLE waitableObject,
  137. IN PVOID tag
  138. );
  139. BOOL HandleSessionDisconnectEvent();
  140. VOID UMRDPDR_GetUserSettings();
  141. VOID MainLoop();
  142. VOID CloseWaitableObjects();
  143. VOID GetNextEvtOverlappedSignaled(
  144. IN HANDLE waitableObject,
  145. IN PVOID tag
  146. );
  147. #ifdef UNITTEST
  148. void TellDrToAddTestPrinter();
  149. #endif
  150. ////////////////////////////////////////////////////////
  151. //
  152. // Globals
  153. //
  154. BOOL g_fAutoClientLpts; // Automatically install client printers?
  155. BOOL g_fForceClientLptDef; // Force the client printer as the default printer?
  156. ////////////////////////////////////////////////////////
  157. //
  158. // Globals to this Module
  159. //
  160. HANDLE BackgroundThreadHndl = NULL;
  161. DWORD BackGroundThreadId = 0;
  162. // The waitable object manager.
  163. WTBLOBJMGR WaitableObjMgr = NULL;
  164. // True if this module is enabled.
  165. BOOL ThisModuleEnabled = FALSE;
  166. // List of installed devices.
  167. DRDEVLST InstalledDevices;
  168. // Overlapped IO structs..
  169. OVERLAPPED GetNextEvtOverlapped;
  170. OVERLAPPED SendClientMsgOverlapped;
  171. // RDPDR Incoming Event Buffer
  172. PBYTE RDPDRIncomingEventBuffer = NULL;
  173. DWORD RDPDRIncomingEventBufferSize = 0;
  174. // True if an IOCTL requesting the next device-related
  175. // event is pending.
  176. BOOL RDPDREventIOPending = FALSE;
  177. // This module should shut down.
  178. BOOL ShutdownFlag = FALSE;
  179. // Token for the currently logged in user
  180. HANDLE TokenForLoggedOnUser = NULL;
  181. // Handle to RDPDR.SYS.
  182. HANDLE RDPDRHndl = INVALID_HANDLE_VALUE;
  183. BOOL
  184. UMRDPDR_Initialize(
  185. IN HANDLE hTokenForLoggedOnUser
  186. )
  187. /*++
  188. Routine Description:
  189. Initialize function for this module. This function spawns a background
  190. thread that does most of the work.
  191. Arguments:
  192. hTokenForLoggedOnUser - Handle to logged on user.
  193. Return Value:
  194. Returns TRUE on success. FALSE, otherwise.
  195. --*/
  196. {
  197. BOOL result;
  198. NTSTATUS status;
  199. HKEY regKey;
  200. LONG sz;
  201. DWORD dwLastError;
  202. /////////////////////////////////////////////////////
  203. //
  204. // Check a reg key to see if we should be running by
  205. // reading a reg key. We are enabled by default.
  206. //
  207. DWORD enabled = TRUE;
  208. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, THISMODULEENABLEDREGKEY, 0,
  209. KEY_READ, &regKey);
  210. if (status == ERROR_SUCCESS) {
  211. sz = sizeof(enabled);
  212. RegQueryValueEx(regKey, THISMODULEENABLEDREGVALUE, NULL,
  213. NULL, (PBYTE)&enabled, &sz);
  214. RegCloseKey(regKey);
  215. }
  216. // If we are in a non-console RDP session, then we are enabled.
  217. ThisModuleEnabled = enabled && TSNUTL_IsProtocolRDP() &&
  218. (!IsActiveConsoleSession());
  219. /////////////////////////////////////////////////////
  220. //
  221. // Read the TS Network Provider out of the registry
  222. //
  223. ProviderName[0] = L'\0';
  224. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TSNETWORKPROVIDER, 0,
  225. KEY_READ, &regKey);
  226. if (status == ERROR_SUCCESS) {
  227. sz = sizeof(ProviderName);
  228. RegQueryValueEx(regKey, TSNETWORKPROVIDERNAME, NULL,
  229. NULL, (PBYTE)ProviderName, &sz);
  230. RegCloseKey(regKey);
  231. }
  232. else {
  233. // Should Assert here
  234. ProviderName[0] = L'\0';
  235. }
  236. /////////////////////////////////////////////////////
  237. //
  238. // Read the debug level out of the registry.
  239. //
  240. #if DBG
  241. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DEBUGLEVELREGKEY, 0,
  242. KEY_READ, &regKey);
  243. if (status == ERROR_SUCCESS) {
  244. sz = sizeof(GLOBAL_DEBUG_FLAGS);
  245. RegQueryValueEx(regKey, DEBUGLEVELREGVALUE, NULL,
  246. NULL, (PBYTE)&GLOBAL_DEBUG_FLAGS, &sz);
  247. RegCloseKey(regKey);
  248. }
  249. #endif
  250. #ifdef UNITTEST
  251. ThisModuleEnabled = TRUE;
  252. #endif
  253. // Just return if we are not enabled.
  254. if (!ThisModuleEnabled || g_UMRDPDR_Init) {
  255. return TRUE;
  256. }
  257. DBGMSG(DBG_TRACE, ("UMRDPDR:UMRDPDR_Initialize.\n"));
  258. //
  259. // If the background thread didn't exit properly the last time we were
  260. // shut down then we risk re-entrancy by reinitializing.
  261. //
  262. if (BackgroundThreadHndl != NULL) {
  263. ASSERT(FALSE);
  264. SetLastError(ERROR_ALREADY_INITIALIZED);
  265. return FALSE;
  266. }
  267. // Record the token for the logged on user.
  268. TokenForLoggedOnUser = hTokenForLoggedOnUser;
  269. // Reset the shutdown flag.
  270. ShutdownFlag = FALSE;
  271. // Load the global user settings for this user.
  272. UMRDPDR_GetUserSettings();
  273. // Initialize the installed device list.
  274. DRDEVLST_Create(&InstalledDevices);
  275. //
  276. // Create the waitable object manager.
  277. //
  278. WaitableObjMgr = WTBLOBJ_CreateWaitableObjectMgr();
  279. result = WaitableObjMgr != NULL;
  280. //
  281. // Initialize the supporting module for printing devices. If this module
  282. // fails to initialize, device redirection for non-port/printing devices
  283. // can continue to function.
  284. //
  285. if (result) {
  286. UMRDPPRN_Initialize(
  287. &InstalledDevices,
  288. WaitableObjMgr,
  289. TokenForLoggedOnUser
  290. );
  291. }
  292. //
  293. // Set the RDPDR incoming event buffer to the minimum starting size.
  294. //
  295. if (result) {
  296. if (!UMRDPDR_ResizeBuffer(&RDPDRIncomingEventBuffer, INITIALIOCTLOUTPUTBUFSIZE,
  297. &RDPDRIncomingEventBufferSize)) {
  298. DBGMSG(DBG_ERROR, ("UMRDPPRN:Cannot allocate input buffer. Error %ld\n",
  299. GetLastError()));
  300. result = FALSE;
  301. }
  302. }
  303. //
  304. // Init get next device management event overlapped io struct.
  305. //
  306. if (result) {
  307. RtlZeroMemory(&GetNextEvtOverlapped, sizeof(OVERLAPPED));
  308. GetNextEvtOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  309. if (GetNextEvtOverlapped.hEvent != NULL) {
  310. dwLastError = WTBLOBJ_AddWaitableObject(
  311. WaitableObjMgr, NULL,
  312. GetNextEvtOverlapped.hEvent,
  313. GetNextEvtOverlappedSignaled
  314. );
  315. if (dwLastError != ERROR_SUCCESS) {
  316. result = FALSE;
  317. }
  318. }
  319. else {
  320. dwLastError = GetLastError();
  321. DBGMSG(DBG_ERROR,
  322. ("UMRDPPRN:Error creating overlapped IO event. Error: %ld\n", dwLastError));
  323. result = FALSE;
  324. }
  325. }
  326. //
  327. // Init send device management event overlapped io struct.
  328. //
  329. RtlZeroMemory(&SendClientMsgOverlapped, sizeof(OVERLAPPED));
  330. if (result) {
  331. SendClientMsgOverlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  332. if (SendClientMsgOverlapped.hEvent == NULL) {
  333. dwLastError = GetLastError();
  334. DBGMSG(DBG_ERROR,
  335. ("UMRDPPRN:Error creating overlapped IO event. Error: %ld\n", dwLastError));
  336. result = FALSE;
  337. }
  338. }
  339. //
  340. // Create the event that we will use to synchronize shutdown of the
  341. // background thread.
  342. //
  343. if (result) {
  344. CloseThreadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  345. //
  346. // Add it to the waitable object manager.
  347. //
  348. if (CloseThreadEvent != NULL) {
  349. dwLastError = WTBLOBJ_AddWaitableObject(
  350. WaitableObjMgr, NULL,
  351. CloseThreadEvent,
  352. CloseThreadEventHandler
  353. );
  354. if (dwLastError != ERROR_SUCCESS) {
  355. result = FALSE;
  356. }
  357. }
  358. else {
  359. dwLastError = GetLastError();
  360. DBGMSG(DBG_ERROR,
  361. ("UMRDPPRN:Error creating event to synchronize thread shutdown. Error: %ld\n",
  362. dwLastError));
  363. result = FALSE;
  364. }
  365. }
  366. //
  367. // Create the background thread.
  368. //
  369. if (result) {
  370. BackgroundThreadHndl = CreateThread(
  371. NULL, 0,
  372. (LPTHREAD_START_ROUTINE )BackgroundThread,
  373. NULL,
  374. 0,&BackGroundThreadId
  375. );
  376. result = (BackgroundThreadHndl != NULL);
  377. if (!result) {
  378. dwLastError = GetLastError();
  379. DBGMSG(DBG_ERROR,
  380. ("UMRDPPRN:Error creating background thread. Error: %ld\n",
  381. dwLastError));
  382. }
  383. }
  384. if (result) {
  385. OSVERSIONINFOEX osVersionInfo;
  386. DWORDLONG dwlConditionMask = 0;
  387. BOOL fSuiteTerminal = FALSE;
  388. BOOL fSuiteSingleUserTS = FALSE;
  389. DBGMSG(DBG_INFO, ("UMRDPDR:UMRDPDR_Initialize succeeded.\n"));
  390. ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
  391. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  392. osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL;
  393. VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
  394. fSuiteTerminal = VerifyVersionInfo(&osVersionInfo,VER_SUITENAME,dwlConditionMask);
  395. osVersionInfo.wSuiteMask = VER_SUITE_SINGLEUSERTS;
  396. fSuiteSingleUserTS = VerifyVersionInfo(&osVersionInfo,VER_SUITENAME,dwlConditionMask);
  397. if( (TRUE == fSuiteSingleUserTS) && (FALSE == fSuiteTerminal) )
  398. {
  399. fRunningOnPTS = TRUE;
  400. }
  401. }
  402. else {
  403. //
  404. // Zero the token for the logged on user.
  405. //
  406. TokenForLoggedOnUser = NULL;
  407. //
  408. // Release the incoming RDPDR event buffer.
  409. //
  410. if (RDPDRIncomingEventBuffer != NULL) {
  411. FREEMEM(RDPDRIncomingEventBuffer);
  412. RDPDRIncomingEventBuffer = NULL;
  413. RDPDRIncomingEventBufferSize = 0;
  414. }
  415. //
  416. // Shut down the supporting module for printing device management.
  417. //
  418. UMRDPPRN_Shutdown();
  419. //
  420. // Close all waitable objects.
  421. //
  422. CloseWaitableObjects();
  423. //
  424. // Zero the background thread handle.
  425. //
  426. if (BackgroundThreadHndl != NULL) {
  427. CloseHandle(BackgroundThreadHndl);
  428. BackgroundThreadHndl = NULL;
  429. }
  430. SetLastError(dwLastError);
  431. }
  432. if (result) {
  433. g_UMRDPDR_Init = TRUE;
  434. }
  435. return result;
  436. }
  437. VOID
  438. CloseWaitableObjects()
  439. /*++
  440. Routine Description:
  441. Close out all waitable objects for this module.
  442. Arguments:
  443. NA
  444. Return Value:
  445. NA
  446. --*/
  447. {
  448. DBGMSG(DBG_TRACE, ("UMRDPDR:CloseWaitableObjects begin.\n"));
  449. if (CloseThreadEvent != NULL) {
  450. ASSERT(WaitableObjMgr != NULL);
  451. WTBLOBJ_RemoveWaitableObject(
  452. WaitableObjMgr,
  453. CloseThreadEvent
  454. );
  455. CloseHandle(CloseThreadEvent);
  456. CloseThreadEvent = NULL;
  457. }
  458. if (GetNextEvtOverlapped.hEvent != NULL) {
  459. ASSERT(WaitableObjMgr != NULL);
  460. WTBLOBJ_RemoveWaitableObject(
  461. WaitableObjMgr,
  462. GetNextEvtOverlapped.hEvent
  463. );
  464. CloseHandle(GetNextEvtOverlapped.hEvent);
  465. GetNextEvtOverlapped.hEvent = NULL;
  466. }
  467. if (SendClientMsgOverlapped.hEvent != NULL) {
  468. CloseHandle(SendClientMsgOverlapped.hEvent);
  469. SendClientMsgOverlapped.hEvent = NULL;
  470. }
  471. if (WaitableObjMgr != NULL) {
  472. WTBLOBJ_DeleteWaitableObjectMgr(WaitableObjMgr);
  473. WaitableObjMgr = NULL;
  474. }
  475. DBGMSG(DBG_TRACE, ("UMRDPDR:CloseWaitableObjects end.\n"));
  476. }
  477. BOOL
  478. UMRDPDR_Shutdown()
  479. /*++
  480. Routine Description:
  481. Close down this module. Right now, we just need to shut down the
  482. background thread.
  483. Arguments:
  484. Return Value:
  485. Returns TRUE on success. FALSE, otherwise.
  486. --*/
  487. {
  488. BOOL backgroundThreadShutdown;
  489. g_UMRDPDR_Init = FALSE;
  490. //
  491. // Just return if we are not enabled.
  492. //
  493. if (!ThisModuleEnabled) {
  494. return TRUE;
  495. }
  496. DBGMSG(DBG_TRACE, ("UMRDPDR:UMRDPDR_Shutdown.\n"));
  497. //
  498. // Record whether shutdown is currently active.
  499. //
  500. if (InterlockedIncrement(&ShutdownActiveCount) > 1) {
  501. DBGMSG(DBG_TRACE, ("UMRDPDR:UMRDPDR_Shutdown already busy. Exiting.\n"));
  502. InterlockedDecrement(&ShutdownActiveCount);
  503. return TRUE;
  504. }
  505. //
  506. // Terminate the background thread.
  507. //
  508. // If it won't shut down, winlogon will eventually shut it down.
  509. // Although, this should never happen.
  510. //
  511. backgroundThreadShutdown = StopBackgroundThread();
  512. if (backgroundThreadShutdown) {
  513. //
  514. // Make sure link to RDPDR.SYS is closed.
  515. //
  516. if (RDPDRHndl != INVALID_HANDLE_VALUE) {
  517. CloseHandle(RDPDRHndl);
  518. RDPDRHndl = INVALID_HANDLE_VALUE;
  519. }
  520. RDPDRHndl = INVALID_HANDLE_VALUE;
  521. //
  522. // Release the incoming RDPDR event buffer.
  523. //
  524. if (RDPDRIncomingEventBuffer != NULL) {
  525. FREEMEM(RDPDRIncomingEventBuffer);
  526. RDPDRIncomingEventBuffer = NULL;
  527. RDPDRIncomingEventBufferSize = 0;
  528. }
  529. //
  530. // Delete installed devices.
  531. //
  532. DeleteInstalledDevices(&InstalledDevices);
  533. //
  534. // Shut down the supporting module for printing device management.
  535. //
  536. UMRDPPRN_Shutdown();
  537. //
  538. // Close all waitable objects and shut down the waitable
  539. // object manager.
  540. //
  541. CloseWaitableObjects();
  542. //
  543. // Destroy the list of installed devices.
  544. //
  545. DRDEVLST_Destroy(&InstalledDevices);
  546. //
  547. // Zero the token for the logged on user.
  548. //
  549. TokenForLoggedOnUser = NULL;
  550. }
  551. InterlockedDecrement(&ShutdownActiveCount);
  552. DBGMSG(DBG_TRACE, ("UMRDPDR:UMRDPDR_Shutdown succeeded.\n"));
  553. return TRUE;
  554. }
  555. BOOL
  556. StopBackgroundThread()
  557. /*++
  558. Routine Description:
  559. This routine shuts down and cleans up after the background thread.
  560. Arguments:
  561. Return Value:
  562. Returns TRUE on success. FALSE, otherwise.
  563. --*/
  564. {
  565. DWORD waitResult;
  566. //
  567. // Set the shutdown flag.
  568. //
  569. ShutdownFlag = TRUE;
  570. //
  571. // Set the event that signals the background thread to check the
  572. // shut down flag.
  573. //
  574. if (CloseThreadEvent != NULL) {
  575. SetEvent(CloseThreadEvent);
  576. }
  577. //
  578. // Make sure it shut down.
  579. //
  580. if (BackgroundThreadHndl != NULL) {
  581. DBGMSG(DBG_TRACE, ("UMRDPDR:Waiting for background thread to shut down.\n"));
  582. waitResult = WaitForSingleObject(BackgroundThreadHndl, KILLTHREADTIMEOUT);
  583. if (waitResult != WAIT_OBJECT_0) {
  584. #if DBG
  585. if (waitResult == WAIT_FAILED) {
  586. DBGMSG(DBG_ERROR, ("UMRDPDR:Wait failed: %ld.\n", GetLastError()));
  587. }
  588. else if (waitResult == WAIT_ABANDONED) {
  589. DBGMSG(DBG_ERROR, ("UMRDPDR:Wait abandoned\n"));
  590. }
  591. else if (waitResult == WAIT_TIMEOUT) {
  592. DBGMSG(DBG_ERROR, ("UMRDPDR:Wait timed out.\n"));
  593. }
  594. else {
  595. DBGMSG(DBG_ERROR, ("UMRDPDR:Unknown wait return status: %08X.\n", waitResult));
  596. ASSERT(0);
  597. }
  598. #endif
  599. DBGMSG(DBG_ERROR, ("UMRDPDR:Error waiting for background thread to exit.\n"));
  600. ASSERT(FALSE);
  601. }
  602. else {
  603. DBGMSG(DBG_INFO, ("UMRDPDR:Background thread shut down on its own.\n"));
  604. CloseHandle(BackgroundThreadHndl);
  605. BackgroundThreadHndl = NULL;
  606. }
  607. }
  608. DBGMSG(DBG_TRACE, ("UMRDPDR:Background thread completely shutdown.\n"));
  609. return(BackgroundThreadHndl == NULL);
  610. }
  611. void DeleteInstalledDevices(
  612. IN PDRDEVLST deviceList
  613. )
  614. /*++
  615. Routine Description:
  616. Delete installed devices and release the installed device list.
  617. Arguments:
  618. devices - Devices to delete.
  619. Return Value:
  620. TRUE on success. FALSE, otherwise.
  621. --*/
  622. {
  623. DBGMSG(DBG_TRACE, ("UMRDPDR:Removing installed devices.\n"));
  624. while (deviceList->deviceCount > 0) {
  625. if (deviceList->devices[0].deviceType == RDPDR_DTYP_PRINT) {
  626. UMRDPPRN_DeleteNamedPrinterQueue(deviceList->devices[0].serverDeviceName);
  627. }
  628. else if (deviceList->devices[0].deviceType == RDPDR_DTYP_FILESYSTEM) {
  629. UMRDPDRV_DeleteDriveConnection(&(deviceList->devices[0]), TokenForLoggedOnUser);
  630. }
  631. else if (deviceList->devices[0].deviceType != RDPDR_DRYP_PRINTPORT) {
  632. UMRDPPRN_DeleteSerialLink( deviceList->devices[0].preferredDosName,
  633. deviceList->devices[0].serverDeviceName,
  634. deviceList->devices[0].clientDeviceName );
  635. }
  636. DRDEVLST_Remove(deviceList, 0);
  637. }
  638. DBGMSG(DBG_TRACE, ("UMRDPDR:Done removing installed devices.\n"));
  639. }
  640. VOID CloseThreadEventHandler(
  641. IN HANDLE waitableObject,
  642. IN PVOID tag
  643. )
  644. /*++
  645. Routine Description:
  646. Called when the shutdown waitable object is signaled.
  647. Arguments:
  648. waitableObject - Relevant waitable object.
  649. tag - Client data, ignored.
  650. Return Value:
  651. NA
  652. --*/
  653. {
  654. // Do nothing. The background thread should pick up the
  655. // shutdown flag at the top of its loop.
  656. }
  657. VOID GetNextEvtOverlappedSignaled(
  658. IN HANDLE waitableObject,
  659. IN PVOID tag
  660. )
  661. /*++
  662. Routine Description:
  663. Called by the Waitable Object Manager when a pending IO event from RDPDR.SYS
  664. has completed.
  665. Arguments:
  666. waitableObject - Relevant waitable object.
  667. tag - Client data, ignored.
  668. Return Value:
  669. NA
  670. --*/
  671. {
  672. DWORD bytesReturned;
  673. DBGMSG(DBG_TRACE, ("UMRDPDR:GetNextEvtOverlappedSignaled begin.\n"));
  674. //
  675. // IO from RDPDR.SYS is no longer pending.
  676. //
  677. RDPDREventIOPending = FALSE;
  678. //
  679. // Dispatch the event.
  680. //
  681. if (GetOverlappedResult(RDPDRHndl, &GetNextEvtOverlapped,
  682. &bytesReturned, FALSE)) {
  683. ResetEvent(GetNextEvtOverlapped.hEvent);
  684. DispatchNextDeviceEvent(
  685. &InstalledDevices,
  686. &RDPDRIncomingEventBuffer,
  687. &RDPDRIncomingEventBufferSize,
  688. bytesReturned
  689. );
  690. }
  691. else {
  692. DBGMSG(DBG_ERROR, ("UMRDPDR:GetOverlappedResult failed: %ld.\n",
  693. GetLastError()));
  694. ASSERT(0);
  695. ShutdownFlag = TRUE;
  696. }
  697. DBGMSG(DBG_TRACE, ("UMRDPDR:GetNextEvtOverlappedSignaled end.\n"));
  698. }
  699. DWORD BackgroundThread(
  700. IN PVOID tag
  701. )
  702. /*++
  703. Routine Description:
  704. This thread handles all device-install/uninstall-related issues.
  705. Arguments:
  706. tag - Ignored.
  707. Return Value:
  708. --*/
  709. {
  710. BOOL result=TRUE;
  711. HDESK hDesk = NULL;
  712. WCHAR drPath[MAX_PATH+1];
  713. DWORD dwLastError;
  714. DWORD dwFailedLineNumber;
  715. HDESK hDeskSave = NULL;
  716. DBGMSG(DBG_TRACE, ("UMRDPDR:BackgroundThread.\n"));
  717. //
  718. // Create the path to the "dr."
  719. //
  720. wsprintf(drPath, L"\\\\.\\%s%s%ld",
  721. RDPDRDVMGR_W32DEVICE_NAME_U,
  722. RDPDYN_SESSIONIDSTRING,
  723. GETTHESESSIONID());
  724. ASSERT(wcslen(drPath) <= MAX_PATH);
  725. //
  726. // Open a connection to the RDPDR.SYS device manager device.
  727. //
  728. RDPDRHndl = CreateFile(
  729. drPath,
  730. GENERIC_READ | GENERIC_WRITE,
  731. FILE_SHARE_READ | FILE_SHARE_WRITE,
  732. NULL,
  733. OPEN_EXISTING,
  734. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  735. NULL
  736. );
  737. if (RDPDRHndl == INVALID_HANDLE_VALUE) {
  738. dwLastError = GetLastError();
  739. dwFailedLineNumber = __LINE__;
  740. DBGMSG(DBG_ERROR,
  741. ("Error opening RDPDR device manager component. Error: %ld\n", dwLastError));
  742. result = FALSE;
  743. goto CleanupAndExit;
  744. }
  745. //
  746. // Save the current thread desktop.
  747. //
  748. hDeskSave = GetThreadDesktop(GetCurrentThreadId());
  749. if (hDeskSave == NULL) {
  750. dwLastError = GetLastError();
  751. dwFailedLineNumber = __LINE__;
  752. result = FALSE;
  753. DBGMSG(DBG_ERROR, ("UMRDPDR: GetThreadDesktop: %08X\n", dwLastError));
  754. goto CleanupAndExit;
  755. }
  756. //
  757. // Set the current desktop for our thread to the application desktop.
  758. //
  759. if (!SetToApplicationDesktop(&hDesk)) {
  760. dwLastError = GetLastError();
  761. dwFailedLineNumber = __LINE__;
  762. result = FALSE;
  763. goto CleanupAndExit;
  764. }
  765. DBGMSG(DBG_TRACE, ("UMRDPDR:After setting the application desktop.\n"));
  766. //
  767. // Enter the main loop until it completes, indicating time to exit.
  768. //
  769. MainLoop();
  770. DBGMSG(DBG_TRACE, ("UMDRPDR:Exiting background thread.\n"));
  771. //
  772. // Close the application desktop handle.
  773. //
  774. CleanupAndExit:
  775. if (!result) {
  776. SetLastError(dwLastError);
  777. TsLogError(EVENT_NOTIFY_PRINTER_REDIRECTION_FAILED, EVENTLOG_ERROR_TYPE,
  778. 0, NULL, dwFailedLineNumber);
  779. }
  780. if (RDPDRHndl != INVALID_HANDLE_VALUE) {
  781. DBGMSG(DBG_TRACE, ("UMRDPDR:Closing connection to RDPDR.SYS.\n"));
  782. if (!CloseHandle(RDPDRHndl)) {
  783. DBGMSG(DBG_TRACE, ("UMRDPDR:Error closing connection to RDPDR.SYS: %ld.\n",
  784. GetLastError()));
  785. }
  786. else {
  787. RDPDRHndl = INVALID_HANDLE_VALUE;
  788. DBGMSG(DBG_TRACE, ("UMRDPDR:Connection to RDPDR.SYS successfully closed\n"));
  789. }
  790. }
  791. if (hDeskSave != NULL) {
  792. if (!SetThreadDesktop(hDeskSave)) {
  793. DBGMSG(DBG_ERROR, ("UMRDPDR:SetThreadDesktop: %08X\n", GetLastError()));
  794. }
  795. }
  796. if (hDesk != NULL) {
  797. if (!CloseDesktop(hDesk)) {
  798. DBGMSG(DBG_ERROR, ("UMRDPDR:CloseDesktop: %08X\n", GetLastError()));
  799. }
  800. else {
  801. DBGMSG(DBG_TRACE, ("UMRDPDR:CloseDesktop succeeded.\n"));
  802. }
  803. }
  804. DBGMSG(DBG_TRACE, ("UMDRPDR:Done exiting background thread.\n"));
  805. return result;
  806. }
  807. VOID
  808. MainLoop()
  809. /*++
  810. Routine Description:
  811. Main loop for the background thread.
  812. Arguments:
  813. Return Value:
  814. NA
  815. --*/
  816. {
  817. DWORD waitResult;
  818. BOOL result;
  819. DWORD bytesReturned;
  820. //
  821. // Reset the flag, indicating that IO to RDPDR is not yet pending.
  822. //
  823. RDPDREventIOPending = FALSE;
  824. //
  825. // Loop until the background thread should exit and this module should
  826. // shut down.
  827. //
  828. while (!ShutdownFlag) {
  829. //
  830. // Send an IOCTL to RDPDR.SYS to get the next "device management event."
  831. //
  832. if (!RDPDREventIOPending) {
  833. DBGMSG(DBG_TRACE, ("UMRDPDR:Sending IOCTL to RDPDR.\n"));
  834. result = DeviceIoControl(
  835. RDPDRHndl,
  836. IOCTL_RDPDR_GETNEXTDEVMGMTEVENT,
  837. NULL,
  838. 0,
  839. RDPDRIncomingEventBuffer,
  840. RDPDRIncomingEventBufferSize,
  841. &bytesReturned, &GetNextEvtOverlapped
  842. );
  843. //
  844. // If the IOCTL finished.
  845. //
  846. if (result && !ShutdownFlag) {
  847. DBGMSG(DBG_TRACE, ("UMRDPDR:DeviceIoControl no pending IO. Data ready.\n"));
  848. if (!ResetEvent(GetNextEvtOverlapped.hEvent)) {
  849. DBGMSG(DBG_ERROR, ("UMRDPDR: ResetEvent: %08X\n",
  850. GetLastError()));
  851. ASSERT(FALSE);
  852. }
  853. DispatchNextDeviceEvent(
  854. &InstalledDevices,
  855. &RDPDRIncomingEventBuffer,
  856. &RDPDRIncomingEventBufferSize,
  857. bytesReturned
  858. );
  859. }
  860. else if (!result && (GetLastError() != ERROR_IO_PENDING)) {
  861. DBGMSG(DBG_ERROR, ("UMRDPPRN:DeviceIoControl failed. Error: %ld\n",
  862. GetLastError()));
  863. TsLogError(
  864. EVENT_NOTIFY_PRINTER_REDIRECTION_FAILED, EVENTLOG_ERROR_TYPE,
  865. 0, NULL, __LINE__
  866. );
  867. //
  868. // Shut down the background thread and the module, in general.
  869. //
  870. ShutdownFlag = TRUE;
  871. }
  872. else {
  873. DBGMSG(DBG_TRACE, ("UMRDPDR:DeviceIoControl indicated IO pending.\n"));
  874. RDPDREventIOPending = TRUE;
  875. }
  876. }
  877. //
  878. // If IO to RDPDR.SYS is pending, then wait for one of our waitable objects to
  879. // become signaled. This way, the shutdown event and data from RDPDR.SYS gets
  880. // priority.
  881. //
  882. if (!ShutdownFlag && RDPDREventIOPending) {
  883. if (WTBLOBJ_PollWaitableObjects(WaitableObjMgr) != ERROR_SUCCESS) {
  884. ShutdownFlag = TRUE;
  885. }
  886. }
  887. }
  888. }
  889. VOID
  890. DispatchNextDeviceEvent(
  891. IN PDRDEVLST deviceList,
  892. IN OUT PBYTE *incomingEventBuffer,
  893. IN OUT DWORD *incomingEventBufferSize,
  894. IN DWORD incomingEventBufferValidBytes
  895. )
  896. /*++
  897. Routine Description:
  898. Dispatch the next device-related event from RDPDR.SYS.
  899. Arguments:
  900. deviceList - Master list of installed devices.
  901. incomingEventBuffer - Incoming event buffer.
  902. incomingEventBufferSize - Incoming event buffer size
  903. incomingEventBufferValidBytes - Number of valid bytes in the event
  904. buffer.
  905. Return Value:
  906. NA
  907. --*/
  908. {
  909. PRDPDR_PRINTERDEVICE_SUB printerAnnounceEvent;
  910. PRDPDR_PORTDEVICE_SUB portAnnounceEvent;
  911. PRDPDR_DRIVEDEVICE_SUB driveAnnounceEvent;
  912. PRDPDR_REMOVEDEVICE removeDeviceEvent;
  913. PRDPDRDVMGR_EVENTHEADER eventHeader;
  914. PRDPDR_BUFFERTOOSMALL bufferTooSmallEvent;
  915. DWORD eventDataSize;
  916. PBYTE eventData;
  917. DWORD lastError = ERROR_SUCCESS;
  918. DWORD dwFailedLineNumber;
  919. DWORD errorEventCode;
  920. DBGMSG(DBG_TRACE, ("UMRDPDR:DispatchNextDeviceEvent.\n"));
  921. //
  922. // The first few bytes of the result buffer are the header.
  923. //
  924. ASSERT(incomingEventBufferValidBytes >= sizeof(RDPDRDVMGR_EVENTHEADER));
  925. eventHeader = (PRDPDRDVMGR_EVENTHEADER)(*incomingEventBuffer);
  926. eventData = *incomingEventBuffer + sizeof(RDPDRDVMGR_EVENTHEADER);
  927. eventDataSize = incomingEventBufferValidBytes - sizeof(RDPDRDVMGR_EVENTHEADER);
  928. //
  929. // Dispatch the event.
  930. //
  931. switch(eventHeader->EventType) {
  932. case RDPDREVT_BUFFERTOOSMALL :
  933. DBGMSG(DBG_TRACE, ("UMRDPDR:Buffer too small msg received.\n"));
  934. ASSERT((incomingEventBufferValidBytes - sizeof(RDPDRDVMGR_EVENTHEADER)) >=
  935. sizeof(RDPDR_BUFFERTOOSMALL));
  936. bufferTooSmallEvent = (PRDPDR_BUFFERTOOSMALL)(*incomingEventBuffer +
  937. sizeof(RDPDRDVMGR_EVENTHEADER));
  938. if (!UMRDPDR_ResizeBuffer(incomingEventBuffer, bufferTooSmallEvent->RequiredSize,
  939. incomingEventBufferSize)) {
  940. ShutdownFlag = TRUE;
  941. lastError = ERROR_INSUFFICIENT_BUFFER;
  942. errorEventCode = EVENT_NOTIFY_INSUFFICIENTRESOURCES;
  943. dwFailedLineNumber = __LINE__;
  944. }
  945. break;
  946. case RDPDREVT_PRINTERANNOUNCE :
  947. DBGMSG(DBG_TRACE, ("UMRDPDR:Printer announce msg received.\n"));
  948. ASSERT(eventDataSize >= sizeof(RDPDR_PRINTERDEVICE_SUB));
  949. printerAnnounceEvent = (PRDPDR_PRINTERDEVICE_SUB)eventData;
  950. if (!UMRDPPRN_HandlePrinterAnnounceEvent(
  951. printerAnnounceEvent
  952. )) {
  953. }
  954. break;
  955. case RDPDREVT_PORTANNOUNCE :
  956. DBGMSG(DBG_TRACE, ("UMRDPDR:Port announce event received.\n"));
  957. ASSERT(eventDataSize >= sizeof(PRDPDR_PORTDEVICE_SUB));
  958. portAnnounceEvent = (PRDPDR_PORTDEVICE_SUB)eventData;
  959. UMRDPPRN_HandlePrintPortAnnounceEvent(portAnnounceEvent);
  960. break;
  961. case RDPDREVT_DRIVEANNOUNCE :
  962. DBGMSG(DBG_TRACE, ("UMRDPDR:Drive announce event received.\n"));
  963. ASSERT(eventDataSize >= sizeof(PRDPDR_DRIVEDEVICE_SUB));
  964. driveAnnounceEvent = (PRDPDR_DRIVEDEVICE_SUB)eventData;
  965. UMRDPDRV_HandleDriveAnnounceEvent(deviceList, driveAnnounceEvent,
  966. TokenForLoggedOnUser);
  967. break;
  968. case RDPDREVT_REMOVEDEVICE :
  969. DBGMSG(DBG_TRACE, ("UMRDPDR:Remove device event received.\n"));
  970. ASSERT(eventDataSize >= sizeof(RDPDR_REMOVEDEVICE));
  971. removeDeviceEvent = (PRDPDR_REMOVEDEVICE)eventData;
  972. HandleRemoveDeviceEvent(removeDeviceEvent);
  973. break;
  974. case RDPDREVT_SESSIONDISCONNECT :
  975. DBGMSG(DBG_TRACE, ("UMRDPDR:Session disconnected event received.\n"));
  976. // There isn't any event data associated with a session disconnect event.
  977. ASSERT(eventDataSize == 0);
  978. HandleSessionDisconnectEvent();
  979. break;
  980. default :
  981. DBGMSG(DBG_WARN, ("UMRDPDR:Unrecognized msg from RDPDR.SYS.\n"));
  982. }
  983. //
  984. // Log an error if there is one to be logged.
  985. //
  986. if (lastError != ERROR_SUCCESS) {
  987. SetLastError(lastError);
  988. TsLogError(
  989. errorEventCode,
  990. EVENTLOG_ERROR_TYPE,
  991. 0,
  992. NULL,
  993. dwFailedLineNumber
  994. );
  995. }
  996. }
  997. BOOL
  998. HandleSessionDisconnectEvent()
  999. /*++
  1000. Routine Description:
  1001. Handles session disconnect device management by deleting all known
  1002. session devices.
  1003. Arguments:
  1004. Return Value:
  1005. Return TRUE on success. FALSE, otherwise.
  1006. --*/
  1007. {
  1008. DBGMSG(DBG_TRACE, ("UMRDPDR:HandleSessionDisconnectEvent.\n"));
  1009. //
  1010. // Delete installed devices.
  1011. //
  1012. DeleteInstalledDevices(&InstalledDevices);
  1013. return TRUE;
  1014. }
  1015. BOOL
  1016. HandleRemoveDeviceEvent(
  1017. IN PRDPDR_REMOVEDEVICE evt
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. Handle a device removal component from RDPDR.SYS.
  1022. Arguments:
  1023. removeDeviceEvent - Device removal event.
  1024. Return Value:
  1025. Return TRUE on success. FALSE, otherwise.
  1026. --*/
  1027. {
  1028. DWORD ofs;
  1029. BOOL result;
  1030. DBGMSG(DBG_TRACE, ("UMRDPDR:HandleRemoveDeviceEvent.\n"));
  1031. // Find the device in our device list via the client-assigned device ID.
  1032. if (DRDEVLST_FindByClientDeviceID(&InstalledDevices, evt->deviceID, &ofs)) {
  1033. //
  1034. // Switch on the type of device being removed.
  1035. //
  1036. switch(InstalledDevices.devices[ofs].deviceType)
  1037. {
  1038. case RDPDR_DTYP_PRINT :
  1039. DBGMSG(DBG_WARN, ("UMRDPDR:Printer queue %ws removed.\n",
  1040. InstalledDevices.devices[ofs].serverDeviceName));
  1041. if (UMRDPPRN_DeleteNamedPrinterQueue(
  1042. InstalledDevices.devices[ofs].serverDeviceName)) {
  1043. DRDEVLST_Remove(&InstalledDevices, ofs);
  1044. result = TRUE;
  1045. }
  1046. else {
  1047. result = FALSE;
  1048. }
  1049. break;
  1050. case RDPDR_DTYP_SERIAL :
  1051. case RDPDR_DTYP_PARALLEL :
  1052. DBGMSG(DBG_WARN, ("UMRDPDR:Serial port %ws removed.\n",
  1053. InstalledDevices.devices[ofs].serverDeviceName));
  1054. if (UMRDPPRN_DeleteSerialLink( InstalledDevices.devices[ofs].preferredDosName,
  1055. InstalledDevices.devices[ofs].serverDeviceName,
  1056. InstalledDevices.devices[ofs].clientDeviceName )) {
  1057. DRDEVLST_Remove(&InstalledDevices, ofs);
  1058. result = TRUE;
  1059. }
  1060. else {
  1061. result = FALSE;
  1062. }
  1063. break;
  1064. case RDPDR_DRYP_PRINTPORT :
  1065. DBGMSG(DBG_WARN, ("UMRDPDR:Parallel port %ws removed.\n",
  1066. InstalledDevices.devices[ofs].serverDeviceName));
  1067. DRDEVLST_Remove(&InstalledDevices, ofs);
  1068. result = TRUE;
  1069. break;
  1070. case RDPDR_DTYP_FILESYSTEM:
  1071. DBGMSG(DBG_WARN, ("UMRDPDR:Redirected drive %ws removed.\n",
  1072. InstalledDevices.devices[ofs].serverDeviceName));
  1073. if (UMRDPDRV_DeleteDriveConnection(&(InstalledDevices.devices[ofs]),
  1074. TokenForLoggedOnUser)) {
  1075. DRDEVLST_Remove(&InstalledDevices, ofs);
  1076. result = TRUE;
  1077. }
  1078. else {
  1079. result = FALSE;
  1080. }
  1081. break;
  1082. default:
  1083. result = FALSE;
  1084. DBGMSG(DBG_WARN, ("UMRDPDR:Remove event received for unknown device type %ld.\n",
  1085. InstalledDevices.devices[ofs].deviceType));
  1086. }
  1087. }
  1088. else {
  1089. result = FALSE;
  1090. DBGMSG(DBG_ERROR, ("UMRDPDR:Cannot find device with id %ld for removal.\n",
  1091. evt->deviceID));
  1092. }
  1093. return result;
  1094. }
  1095. BOOL
  1096. UMRDPDR_SendMessageToClient(
  1097. IN PVOID msg,
  1098. IN DWORD msgSize
  1099. )
  1100. /*++
  1101. Routine Description:
  1102. Send a message to the TS client corresponding to this session, via the kernel
  1103. mode component.
  1104. Arguments:
  1105. msg - The message.
  1106. msgSize - Size (in bytes) of message.
  1107. Return Value:
  1108. TRUE on success. FALSE otherwise.
  1109. --*/
  1110. {
  1111. BOOL result;
  1112. BYTE outBuf[MAX_PATH];
  1113. DWORD bytesReturned;
  1114. BOOL wait;
  1115. DWORD waitResult;
  1116. DBGMSG(DBG_TRACE, ("UMRDPDR:UMRDPDR_SendMessageToClient.\n"));
  1117. //
  1118. // Send the "client message" IOCTL to RDPDR.
  1119. //
  1120. result = DeviceIoControl(
  1121. RDPDRHndl,
  1122. IOCTL_RDPDR_CLIENTMSG,
  1123. msg,
  1124. msgSize,
  1125. outBuf,
  1126. sizeof(outBuf),
  1127. &bytesReturned,
  1128. &SendClientMsgOverlapped
  1129. );
  1130. //
  1131. // See if we need to wait for the IO complete. RDPDR.SYS is designed to
  1132. // return immediately, in response to this IOCTL.
  1133. //
  1134. if (result) {
  1135. DBGMSG(DBG_TRACE, ("UMRDPDR:DeviceIoControl no pending IO. Data ready.\n"));
  1136. wait = FALSE;
  1137. result = TRUE;
  1138. }
  1139. else if (!result && (GetLastError() != ERROR_IO_PENDING)) {
  1140. DBGMSG(DBG_ERROR, ("UMRDPPRN:DeviceIoControl Failed. Error: %ld\n",
  1141. GetLastError()));
  1142. TsLogError(EVENT_NOTIFY_PRINTER_REDIRECTION_FAILED, EVENTLOG_ERROR_TYPE, 0, NULL, __LINE__);
  1143. wait = FALSE;
  1144. result = FALSE;
  1145. }
  1146. else {
  1147. DBGMSG(DBG_TRACE, ("UMRDPDR:DeviceIoControl indicated IO pending.\n"));
  1148. wait = TRUE;
  1149. result = TRUE;
  1150. }
  1151. //
  1152. // Wait for the IO to complete.
  1153. //
  1154. if (wait) {
  1155. DBGMSG(DBG_TRACE, ("UMRDPDR:UMRDPDR_SendMessageToClient IO is pending.\n"));
  1156. waitResult = WaitForSingleObject(SendClientMsgOverlapped.hEvent, INFINITE);
  1157. if (waitResult != WAIT_OBJECT_0) {
  1158. DBGMSG(DBG_ERROR, ("UMRDPPRN:RDPDR.SYS failed client message IOCTL. Error: %ld\n",
  1159. GetLastError()));
  1160. TsLogError(EVENT_NOTIFY_PRINTER_REDIRECTION_FAILED, EVENTLOG_ERROR_TYPE, 0, NULL, __LINE__);
  1161. result = FALSE;
  1162. }
  1163. else {
  1164. DBGMSG(DBG_TRACE, ("UMRDPDR:Client message sent successfully.\n"));
  1165. }
  1166. }
  1167. return result;
  1168. }
  1169. BOOL
  1170. UMRDPDR_ResizeBuffer(
  1171. IN OUT void **buffer,
  1172. IN DWORD bytesRequired,
  1173. IN OUT DWORD *bufferSize
  1174. )
  1175. /*++
  1176. Routine Description:
  1177. Make sure a buffer is large enough.
  1178. Arguments:
  1179. buffer - The buffer.
  1180. bytesRequired - Required size.
  1181. bufferSize - Current buffer size.
  1182. Return Value:
  1183. Returns FALSE if buffer cannot be resized.
  1184. --*/
  1185. {
  1186. BOOL result;
  1187. if (*bufferSize < bytesRequired) {
  1188. if (*buffer == NULL) {
  1189. *buffer = ALLOCMEM(bytesRequired);
  1190. }
  1191. else {
  1192. void *pTmp = REALLOCMEM(*buffer, bytesRequired);
  1193. if (pTmp != NULL) {
  1194. *buffer = pTmp;
  1195. } else {
  1196. FREEMEM(*buffer);
  1197. *buffer = NULL;
  1198. }
  1199. }
  1200. if (*buffer == NULL) {
  1201. *bufferSize = 0;
  1202. DBGMSG(DBG_ERROR, ("UMRDPPRN:Error resizing buffer. Error: %ld\n",
  1203. GetLastError()));
  1204. result = FALSE;
  1205. }
  1206. else {
  1207. result = TRUE;
  1208. *bufferSize = bytesRequired;
  1209. }
  1210. } else {
  1211. result = TRUE;
  1212. }
  1213. return result;
  1214. }
  1215. BOOL
  1216. SetToApplicationDesktop(
  1217. OUT HDESK *phDesk
  1218. )
  1219. /*++
  1220. Routine Description:
  1221. Set the current desktop for our thread to the application desktop.
  1222. Callers of this function should call CloseDesktop with the returned
  1223. desktop handle when they are done with the desktop.
  1224. Arguments:
  1225. phDesk - Pointer to the application desktop.
  1226. Return Value:
  1227. Returns TRUE on success. FALSE, otherwise.
  1228. --*/
  1229. {
  1230. ASSERT(phDesk != NULL);
  1231. *phDesk = OpenDesktopW(L"default", 0, FALSE,
  1232. DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW |
  1233. DESKTOP_CREATEMENU | DESKTOP_WRITEOBJECTS |
  1234. STANDARD_RIGHTS_REQUIRED);
  1235. if (*phDesk == NULL) {
  1236. DBGMSG(DBG_ERROR, ("UMRDPPRN:Failed to open desktop. Error: %ld\n",
  1237. GetLastError()));
  1238. return FALSE;
  1239. }
  1240. else if (!SetThreadDesktop(*phDesk)) {
  1241. DBGMSG(DBG_ERROR, ("UMRDPPRN:Failed to set current thread desktop. Error: %ld\n",
  1242. GetLastError()));
  1243. CloseDesktop(*phDesk);
  1244. *phDesk = NULL;
  1245. return FALSE;
  1246. }
  1247. else {
  1248. return TRUE;
  1249. }
  1250. }
  1251. VOID
  1252. UMRDPDR_GetUserSettings()
  1253. /*++
  1254. Routine Description:
  1255. Gets the flags to determine whether we do automatic installation
  1256. Arguments:
  1257. None.
  1258. Return Value:
  1259. None.
  1260. --*/
  1261. {
  1262. NTSTATUS Status;
  1263. WINSTATIONCONFIG WinStationConfig;
  1264. ULONG ReturnLength;
  1265. HANDLE hServer;
  1266. DBGMSG(DBG_TRACE, ("UMRDPDR:UMRDPDR_GetUserFlags called.\n"));
  1267. g_fAutoClientLpts = FALSE;
  1268. g_fForceClientLptDef = FALSE;
  1269. hServer = WinStationOpenServer(NULL);
  1270. if (hServer) {
  1271. Status = WinStationQueryInformation(hServer, g_SessionId,
  1272. WinStationConfiguration, &WinStationConfig,
  1273. sizeof(WinStationConfig), &ReturnLength);
  1274. if (NT_SUCCESS(Status)) {
  1275. g_fAutoClientLpts = WinStationConfig.User.fAutoClientLpts;
  1276. g_fForceClientLptDef = WinStationConfig.User.fForceClientLptDef;
  1277. } else {
  1278. DBGMSG(DBG_ERROR, ("UMRDPDR:Error querying user settings\n"));
  1279. }
  1280. WinStationCloseServer(hServer);
  1281. } else {
  1282. DBGMSG(DBG_ERROR, ("UMRDPDR:Opening winstation\n"));
  1283. }
  1284. DBGMSG(DBG_TRACE, ("UMRDPDR:Client printers will%sbe mapped\n",
  1285. g_fAutoClientLpts ? " " : " not "));
  1286. DBGMSG(DBG_TRACE, ("UMRDPDR:Client printers will%sbe made default\n",
  1287. g_fForceClientLptDef ? " " : " not "));
  1288. }
  1289. BOOL UMRDPDR_fAutoInstallPrinters()
  1290. {
  1291. return g_fAutoClientLpts;
  1292. }
  1293. BOOL UMRDPDR_fSetClientPrinterDefault()
  1294. {
  1295. return g_fForceClientLptDef;
  1296. }
  1297. #if DBG
  1298. VOID DbgMsg(CHAR *msgFormat, ...)
  1299. /*++
  1300. Routine Description:
  1301. Print debug output.
  1302. Arguments:
  1303. pathBuffer - Address of a buffer to receive the path name selected by
  1304. the user. The size of this buffer is assumed to be
  1305. MAX_PATH bytes. This buffer should contain the default
  1306. path.
  1307. Return Value:
  1308. Returns TRUE on success. FALSE, otherwise.
  1309. --*/
  1310. {
  1311. CHAR msgText[256];
  1312. va_list vargs;
  1313. va_start(vargs, msgFormat);
  1314. wvsprintfA(msgText, msgFormat, vargs);
  1315. va_end( vargs );
  1316. if (*msgText)
  1317. OutputDebugStringA("UMRDPDR: ");
  1318. OutputDebugStringA(msgText);
  1319. }
  1320. #endif
  1321. /*++
  1322. Unit-Test Entry Point
  1323. --*/
  1324. #ifdef UNITTEST
  1325. void __cdecl main(int argc, char **argv)
  1326. {
  1327. BOOL killLoop = FALSE;
  1328. int i;
  1329. BOOL result;
  1330. NTSTATUS ntStatus;
  1331. HKEY regKey;
  1332. LONG regValueSize;
  1333. LONG status;
  1334. HANDLE pHandle;
  1335. HANDLE tokenHandle;
  1336. TsInitLogging();
  1337. //
  1338. // Check the command-line args to see what test we are performing.
  1339. //
  1340. if ((argc > 1) && strcmp(argv[1], "\\?")) {
  1341. if (!strcmp(argv[1], "AddPrinter")) {
  1342. TellDrToAddTestPrinter();
  1343. exit(-1);
  1344. }
  1345. else if (!strcmp(argv[1], "StandAlone")) {
  1346. pHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE,
  1347. GetCurrentProcessId());
  1348. if (!OpenProcessToken(pHandle, TOKEN_ALL_ACCESS, &tokenHandle)) {
  1349. OutputDebugString(TEXT("Error opening process token. Exiting\n"));
  1350. exit(-1);
  1351. }
  1352. UMRDPDR_Initialize(tokenHandle);
  1353. while (!killLoop) {
  1354. Sleep(100);
  1355. }
  1356. UMRDPDR_Shutdown();
  1357. OutputDebugString(L"UMRDPDR:Exiting.\r\n");
  1358. exit(-1);
  1359. }
  1360. }
  1361. else {
  1362. printf("\\? for command line parameters.\n");
  1363. printf("AddPrinter to tell RDPDR.SYS to generate a test printer.\n");
  1364. printf("StandAlone to run normally, but stand-alone.\n");
  1365. printf("UnitTest to run a simple unit-test.\n");
  1366. exit(-1);
  1367. }
  1368. }
  1369. void TellDrToAddTestPrinter()
  1370. /*++
  1371. Routine Description:
  1372. This function uses a debug IOCTL to tell RDPDR to generate a test
  1373. printer event.
  1374. Arguments:
  1375. Return Value:
  1376. --*/
  1377. {
  1378. WCHAR drPath[MAX_PATH+1];
  1379. UNICODE_STRING uncDrPath;
  1380. HANDLE drHndl = INVALID_HANDLE_VALUE;
  1381. BOOL result;
  1382. OBJECT_ATTRIBUTES fileAttributes;
  1383. IO_STATUS_BLOCK IoStatusBlock;
  1384. NTSTATUS ntStatus;
  1385. BYTE inbuf[MAX_PATH];
  1386. BYTE outbuf[MAX_PATH];
  1387. DWORD bytesReturned;
  1388. //
  1389. // Create the path to the "dr."
  1390. //
  1391. wsprintf(drPath, L"\\\\.\\%s%s%ld",
  1392. RDPDRDVMGR_W32DEVICE_NAME_U,
  1393. RDPDYN_SESSIONIDSTRING,
  1394. 0x9999);
  1395. ASSERT(wcslen(drPath) <= MAX_PATH);
  1396. //
  1397. // Open a connection to the RDPDR.SYS device manager device.
  1398. //
  1399. drHndl = CreateFile(
  1400. drPath,
  1401. GENERIC_READ | GENERIC_WRITE,
  1402. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1403. NULL,
  1404. OPEN_EXISTING,
  1405. FILE_ATTRIBUTE_NORMAL,
  1406. NULL
  1407. );
  1408. if (drHndl == INVALID_HANDLE_VALUE) {
  1409. TsLogError(EVENT_NOTIFY_RDPDR_FAILED, EVENTLOG_ERROR_TYPE, 0, NULL, __LINE__);
  1410. DBGMSG(DBG_ERROR, ("UMRDPPRN:Error opening RDPDR device manager component. Error: %ld\n",
  1411. GetLastError()));
  1412. }
  1413. else {
  1414. // Tell the DR to add a new test printer.
  1415. if (!DeviceIoControl(drHndl, IOCTL_RDPDR_DBGADDNEWPRINTER, inbuf,
  1416. 0, outbuf, sizeof(outbuf), &bytesReturned, NULL)) {
  1417. TsLogError(EVENT_NOTIFY_RDPDR_FAILED, EVENTLOG_ERROR_TYPE, 0, NULL, __LINE__);
  1418. DBGMSG(DBG_ERROR, ("UMRDPPRN:Error sending IOCTL to device manager component. Error: %ld\n",
  1419. GetLastError()));
  1420. }
  1421. // Clean up.
  1422. CloseHandle(drHndl);
  1423. }
  1424. }
  1425. #endif