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.

5690 lines
167 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. umrdpprn.c
  5. Abstract:
  6. User-Mode Component for RDP Device Management that Handles Printing Device-
  7. Specific tasks.
  8. This is a supporting module. The main module is umrdpdr.c.
  9. Author:
  10. TadB
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include <winspool.h>
  16. #include <rdpdr.h>
  17. #include <aclapi.h>
  18. #include "setupapi.h"
  19. #include "printui.h"
  20. #include "drdevlst.h"
  21. #include "umrdpdr.h"
  22. #include "umrdpprn.h"
  23. #include "drdbg.h"
  24. #include "rdpprutl.h"
  25. #include "tsnutl.h"
  26. #include "rdpdr.h"
  27. #include "errorlog.h"
  28. #include <wlnotify.h>
  29. #include <time.h>
  30. ////////////////////////////////////////////////////////
  31. //
  32. // Defines
  33. //
  34. #ifndef BOOL
  35. #define BOOL int
  36. #endif
  37. #ifndef ARRAYSIZE
  38. #define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))
  39. #endif
  40. #define PRINTUILIBNAME TEXT("printui.dll")
  41. //
  42. // Printui Printer Configuration Save/Restore Flags.
  43. //
  44. // This one should be called as user for fetching the configuration data.
  45. #define CMDLINE_FOR_STORING_CONFIGINFO_IMPERSONATE L"/q /Ss /n \"%ws\" /a \"%ws\" 2 7 c d u g"
  46. // This one should be called first as system for restoring configuration data.
  47. #define CMDLINE_FOR_RESTORING_CONFIGINFO_NOIMPERSONATE L"/q /Sr /n \"%ws\" /a \"%ws\" 2 7 c d g r p h i"
  48. // This one should be called second as user for restoring configuration data.
  49. #define CMDLINE_FOR_RESTORING_CONFIGINFO_IMPERSONATE L"/q /Sr /n \"%ws\" /a \"%ws\" u r"
  50. #define TEMP_FILE_PREFIX L"prn"
  51. #define INF_PATH L"\\inf\\ntprint.inf"
  52. //
  53. // Reg key for configurable parms.
  54. //
  55. #define CONFIGREGKEY \
  56. L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\Wds\\rdpwd"
  57. //
  58. // Location of configurable threshold for delta between printer installation
  59. // time and forwarding of first user-initiated configuration change data
  60. // to the client. The units for this value is in seconds.
  61. //
  62. #define CONFIGTHRESHOLDREGVALUE \
  63. L"PrintRdrConfigThreshold"
  64. //
  65. // Default Value for Configurable Printer Configuration Threshold
  66. //
  67. #define CONFIGTHRESHOLDDEFAULT 20
  68. //
  69. // Registry key for storing default, per-user, printer names.
  70. //
  71. #define USERDEFAULTPRNREGKEY \
  72. L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\Wds\\rdpwd\\DefaultPrinterStore"
  73. #define TSSERIALDEVICEMAP \
  74. L"HARDWARE\\DEVICEMAP\\SERIALCOMM"
  75. //
  76. // Registry location of configurable client driver name mapping INF and INF
  77. // section.
  78. //
  79. #define CONFIGUSERDEFINEDMAPPINGINFNAMEVALUE\
  80. L"PrinterMappingINFName"
  81. #define CONFIGUSERDEFINEDMAPPINGINFSECTIONVALUE\
  82. L"PrinterMappingINFSection"
  83. //
  84. // Location of Windows Directory Path
  85. //
  86. #define WINDOWSDIRKEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
  87. #define WINDOWSDIRVALUENAME L"PathName"
  88. // Get a numeric representation of our session ID.
  89. #if defined(UNITTEST)
  90. #define GETTHESESSIONID() 0
  91. #else
  92. extern ULONG g_SessionId;
  93. #define GETTHESESSIONID() g_SessionId
  94. #endif
  95. #if defined(UNITTEST)
  96. HINSTANCE g_hInstance;
  97. #else
  98. extern HINSTANCE g_hInstance;
  99. #endif
  100. extern BOOL fRunningOnPTS;
  101. // Return true if the device type represents a serial or parallel port.
  102. #define ISPRINTPORT(type) (((type) == RDPDR_DTYP_SERIAL) || \
  103. ((type) == RDPDR_DTYP_PARALLEL) || \
  104. ((type) == RDPDR_DRYP_PRINTPORT))
  105. // Maximum number of characters in a session ID (Max chars in a dword is 17)
  106. #define MAXSESSIONIDCHARS 17
  107. // The field types we are waiting on (Printer Config change Notification)
  108. #define IS_CONFIG_INFO_FIELD(field) \
  109. (field == PRINTER_NOTIFY_FIELD_SHARE_NAME) || \
  110. (field == PRINTER_NOTIFY_FIELD_DEVMODE) || \
  111. (field == PRINTER_NOTIFY_FIELD_COMMENT) || \
  112. (field == PRINTER_NOTIFY_FIELD_LOCATION) || \
  113. (field == PRINTER_NOTIFY_FIELD_SEPFILE) || \
  114. (field == PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR) || \
  115. (field == PRINTER_NOTIFY_FIELD_PARAMETERS) || \
  116. (field == PRINTER_NOTIFY_FIELD_DATATYPE) || \
  117. (field == PRINTER_NOTIFY_FIELD_ATTRIBUTES) || \
  118. (field == PRINTER_NOTIFY_FIELD_PRIORITY) || \
  119. (field == PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY) || \
  120. (field == PRINTER_NOTIFY_FIELD_START_TIME) || \
  121. (field == PRINTER_NOTIFY_FIELD_UNTIL_TIME) || \
  122. (field == PRINTER_NOTIFY_FIELD_STATUS)
  123. #define CONFIG_WAIT_PERIOD (30 * 1000)
  124. #define INFINITE_WAIT_PERIOD (0xDFFFFFFF) //just a large number.Ok for 64-bit also.
  125. #define DEVICE_MAP_NAME L"\\??\\"
  126. #define DEVICE_MAP_NAME_COUNT 4 // 4 chars - \??\
  127. ////////////////////////////////////////////////////////////////////////
  128. //
  129. // Typedefs
  130. //
  131. typedef struct tagPRINTNOTIFYREC
  132. {
  133. HANDLE notificationObject; // Notification object registered
  134. // FindFirstPrinterChangeNotification.
  135. HANDLE printerHandle; // Open handle to the printer.
  136. DWORD serverDeviceID; // Server-side printer identifier.
  137. } PRINTNOTIFYREC, *PPRINTNOTIFYREC;
  138. ////////////////////////////////////////////////////////////////////////
  139. //
  140. // External Prototypes
  141. //
  142. #if DBG
  143. extern void DbgMsg(CHAR *msgFormat, ...);
  144. #endif
  145. ////////////////////////////////////////////////////////////////////////
  146. //
  147. // Local Prototypes
  148. //
  149. WCHAR *ANSIToUnicode(
  150. IN LPCSTR ansiString,
  151. IN UINT codePage
  152. );
  153. BOOL InstallPrinterWithPortName(
  154. IN DWORD deviceID,
  155. IN HANDLE hTokenForLoggedOnUser,
  156. IN BOOL bSetDefault,
  157. IN ULONG ulFlags,
  158. IN PCWSTR portName,
  159. IN PCWSTR driverName,
  160. IN PCWSTR printerName,
  161. IN PCWSTR clientComputerName,
  162. IN PBYTE cacheData,
  163. IN DWORD cacheDataLen
  164. );
  165. BOOL HandlePrinterNameChangeNotification(
  166. IN DWORD serverDeviceID,
  167. IN LPWSTR printerName
  168. );
  169. BOOL SendAddPrinterMsgToClient(
  170. IN PCWSTR printerName,
  171. IN PCWSTR driverName,
  172. IN PCSTR dosDevicePort
  173. );
  174. BOOL SendDeletePrinterMsgToClient(
  175. IN PCWSTR printerName
  176. );
  177. BOOL HandlePrinterDeleteNotification(
  178. IN DWORD serverDeviceID
  179. );
  180. void HandlePrinterRefreshNotification(
  181. IN PPRINTER_NOTIFY_INFO notifyInfo
  182. );
  183. DWORD AddSessionIDToPrinterQueue(
  184. IN HANDLE hPrinter,
  185. IN DWORD sessionID
  186. );
  187. BOOL SetDefaultPrinterToFirstFound(
  188. BOOL impersonate
  189. );
  190. DWORD GetPrinterConfigInfo(
  191. LPCWSTR printerName,
  192. LPBYTE * ppBuffer,
  193. LPDWORD pdwBufSize
  194. );
  195. DWORD SetPrinterConfigInfo(
  196. LPCWSTR printerName,
  197. LPVOID lpBuffer,
  198. DWORD dwBufSize
  199. );
  200. BOOL HandlePrinterConfigChangeNotification(
  201. IN DWORD serverDeviceID
  202. );
  203. BOOL SendPrinterConfigInfoToClient(
  204. IN PCWSTR printerName,
  205. IN LPBYTE pConfigInfo,
  206. IN DWORD ConfigInfoSize
  207. );
  208. DWORD CallPrintUiPersistFunc(
  209. LPCWSTR printerName,
  210. LPCWSTR fileName,
  211. LPCWSTR formatString
  212. );
  213. BOOL
  214. SendPrinterRenameToClient(
  215. IN PCWSTR oldprinterName,
  216. IN PCWSTR newprinterName
  217. );
  218. VOID LoadConfigurableValues();
  219. BOOL GetPrinterPortName(
  220. IN HANDLE hPrinter,
  221. OUT PWSTR *portName
  222. );
  223. BOOL MapClientPrintDriverName(
  224. IN PCWSTR clientDriver,
  225. IN OUT PWSTR *mappedName,
  226. IN OUT DWORD *mappedNameBufSize
  227. );
  228. DWORD PrinterDriverInstalled(
  229. IN PCWSTR clientDriver
  230. );
  231. HANDLE RegisterForPrinterPrefNotify();
  232. PACL GiveLoggedOnUserFullPrinterAccess(
  233. IN LPTSTR printerName,
  234. IN HANDLE hToken,
  235. PSECURITY_DESCRIPTOR *ppsd
  236. );
  237. DWORD SetPrinterDACL(
  238. IN LPTSTR printerName,
  239. IN PACL pDacl
  240. );
  241. VOID CloseWaitablePrintingObjects();
  242. VOID GlobalPrintNotifyObjectSignaled(
  243. IN HANDLE waitableObject,
  244. IN PVOID clientData
  245. );
  246. VOID PrintPreferenceChangeEventSignaled(
  247. HANDLE eventHandle,
  248. PVOID clientData
  249. );
  250. void WaitableTimerSignaled(
  251. HANDLE waitableObject,
  252. PVOID clientData
  253. );
  254. BOOL
  255. RegisterPrinterConfigChangeNotification(
  256. IN DWORD serverDeviceID
  257. );
  258. BOOL RestoreDefaultPrinterContext();
  259. BOOL SaveDefaultPrinterContext(PCWSTR currentlyInstallingPrinterName);
  260. BOOL SavePrinterNameAsGlobalDefault(
  261. IN PCWSTR printerName
  262. );
  263. // Struct used to split a full printer name.
  264. // Once filled, each psz points to a substring in the buffer
  265. // or to one of the original names. Nothing allocated.
  266. typedef struct _TS_PRINTER_NAMES {
  267. WCHAR szTemp[MAX_PATH+1];
  268. ULONG ulTempLen;
  269. PCWSTR pszFullName;
  270. PCWSTR pszCurrentClient;
  271. PCWSTR pszServer;
  272. PCWSTR pszClient;
  273. PCWSTR pszPrinter;
  274. } TS_PRINTER_NAMES, *PTS_PRINTER_NAMES;
  275. void FormatPrinterName(
  276. PWSTR pszNewNameBuf,
  277. ULONG ulBufLen,
  278. ULONG ulFlags,
  279. PTS_PRINTER_NAMES pPrinterNames);
  280. DWORD AddNamesToPrinterQueue(
  281. IN HANDLE hPrinter,
  282. IN PTS_PRINTER_NAMES pPrinterNames
  283. );
  284. VOID TriggerConfigChangeTimer();
  285. #ifdef UNITTEST
  286. void TellDrToAddTestPrinter();
  287. void SimpleUnitTest();
  288. #endif
  289. ////////////////////////////////////////////////////////
  290. //
  291. // Globals
  292. //
  293. //
  294. // Set to TRUE when the DLL is trying to shut down.
  295. //
  296. extern BOOL ShutdownFlag;
  297. ////////////////////////////////////////////////////////
  298. //
  299. // Globals to this Module
  300. //
  301. // True if this module has been successfully initialized.
  302. BOOL PrintingModuleInitialized = FALSE;
  303. // Comprehensive Device List
  304. PDRDEVLST DeviceList;
  305. // Handle to the print system dev mode for this user. This is the key
  306. // that is modified when a user changes a printer's printing preferences.
  307. HKEY DevModeHKey = INVALID_HANDLE_VALUE;
  308. // Configurable threshold for delta between printer installation
  309. // time and forwarding of first user-initiated configuration change data
  310. // to the client. The units for this value is in seconds.
  311. DWORD ConfigSendThreshold;
  312. //
  313. // Printer Change Notification Events
  314. //
  315. HANDLE PrintNotificationEvent = INVALID_HANDLE_VALUE;
  316. HANDLE PrintPreferenceChangeEvent = NULL;
  317. HANDLE PrintUILibHndl = NULL;
  318. FARPROC PrintUIEntryFunc = NULL;
  319. FARPROC PnpInterfaceFunc = NULL;
  320. HANDLE UMRPDPPRN_TokenForLoggedOnUser = INVALID_HANDLE_VALUE;
  321. HANDLE LocalPrinterServerHandle = NULL;
  322. WCHAR PrinterInfPath[MAX_PATH + (sizeof(INF_PATH)/sizeof(WCHAR)) + 2] = L""; // of the form "%windir%\\inf\\ntprint.inf"
  323. LPPRINTER_INFO_2 PrinterInfo2Buf = NULL;
  324. DWORD PrinterInfo2BufSize = 0;
  325. //WCHAR SessionString[MAX_PATH+1];
  326. WCHAR g_szFromFormat[MAX_PATH+1];
  327. WCHAR g_szOnFromFormat[MAX_PATH+1];
  328. BOOL g_fIsPTS = FALSE;
  329. BOOL g_fTimerSet = FALSE;
  330. HANDLE WaitableTimer = NULL;
  331. BOOL g_fDefPrinterEncountered = FALSE;
  332. // Global debug flag.
  333. extern DWORD GLOBAL_DEBUG_FLAGS;
  334. // Printer Notify Parameters
  335. WORD PrinterFieldType[] =
  336. {
  337. PRINTER_NOTIFY_FIELD_SHARE_NAME,
  338. PRINTER_NOTIFY_FIELD_PRINTER_NAME,
  339. PRINTER_NOTIFY_FIELD_COMMENT,
  340. PRINTER_NOTIFY_FIELD_LOCATION,
  341. PRINTER_NOTIFY_FIELD_DEVMODE,
  342. PRINTER_NOTIFY_FIELD_SEPFILE,
  343. PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR,
  344. PRINTER_NOTIFY_FIELD_PARAMETERS,
  345. PRINTER_NOTIFY_FIELD_DATATYPE,
  346. PRINTER_NOTIFY_FIELD_ATTRIBUTES,
  347. PRINTER_NOTIFY_FIELD_PRIORITY,
  348. PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY,
  349. PRINTER_NOTIFY_FIELD_START_TIME,
  350. PRINTER_NOTIFY_FIELD_UNTIL_TIME,
  351. PRINTER_NOTIFY_FIELD_STATUS
  352. };
  353. PRINTER_NOTIFY_OPTIONS_TYPE PrinterNotifyOptionsType[] =
  354. {
  355. {
  356. PRINTER_NOTIFY_TYPE,
  357. 0,
  358. 0,
  359. 0,
  360. sizeof(PrinterFieldType) / sizeof(WORD),
  361. PrinterFieldType
  362. }
  363. };
  364. PRINTER_NOTIFY_OPTIONS PrinterNotifyOptions =
  365. {
  366. 2,
  367. 0,
  368. sizeof(PrinterNotifyOptionsType) / sizeof(PRINTER_NOTIFY_OPTIONS_TYPE),
  369. PrinterNotifyOptionsType
  370. };
  371. //
  372. // User-Configurable Client Driver Mapping INF Name and INF Section.
  373. //
  374. LPWSTR UserDefinedMappingINFName = NULL;
  375. LPWSTR UserDefinedMappingINFSection = NULL;
  376. //
  377. // Buffer for converting from Win9x driver names to Win2K driver names.
  378. //
  379. PWSTR MappedDriverNameBuf = NULL;
  380. DWORD MappedDriverNameBufSize = 0;
  381. //
  382. // Waitable Object Manager
  383. //
  384. WTBLOBJMGR UMRDPPRN_WaitableObjMgr = NULL;
  385. //
  386. // Default Printer Name
  387. //
  388. WCHAR SavedDefaultPrinterName[MAX_PATH+1] = L"";
  389. //
  390. // Printer section names
  391. //
  392. static WCHAR* prgwszPrinterSectionNames[] = {
  393. L"Printer Driver Mapping_Windows NT x86_Version 2",
  394. L"Printer Driver Mapping_Windows NT x86_Version 3",
  395. NULL
  396. };
  397. BOOL IsItPTS()
  398. {
  399. OSVERSIONINFOEX gOsVersion;
  400. ZeroMemory(&gOsVersion, sizeof(OSVERSIONINFOEX));
  401. gOsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  402. GetVersionEx( (LPOSVERSIONINFO ) &gOsVersion);
  403. return (gOsVersion.wProductType == VER_NT_WORKSTATION) // product type must be workstation.
  404. && !(gOsVersion.wSuiteMask & VER_SUITE_PERSONAL) // and product suite must not be personal.
  405. && (gOsVersion.wSuiteMask & VER_SUITE_SINGLEUSERTS); // it must be single user ts.
  406. }
  407. BOOL UMRDPPRN_Initialize(
  408. IN PDRDEVLST deviceList,
  409. IN WTBLOBJMGR waitableObjMgr,
  410. IN HANDLE hTokenForLoggedOnUser
  411. )
  412. /*++
  413. Routine Description:
  414. Initialize this module. This must be called prior to any other functions
  415. in this module being called.
  416. Arguments:
  417. deviceList - Comprehensive list of redirected devices.
  418. waitableObjMgr - Waitable object manager.
  419. hTokenForLoggedOnUser - This is the token for the logged in user.
  420. Return Value:
  421. Returns TRUE on success. FALSE, otherwise.
  422. --*/
  423. {
  424. HKEY regKey;
  425. LONG sz;
  426. DWORD errorEventID = -1;
  427. DWORD errorEventLineNumber = 0;
  428. BOOL result, impersonated = FALSE;
  429. DBGMSG(DBG_TRACE, ("UMRDPPRN:UMRDPPRN_Initialize.\n"));
  430. //
  431. // Make sure we don't get called twice without getting cleaned up.
  432. //
  433. ASSERT((PrintNotificationEvent == INVALID_HANDLE_VALUE) &&
  434. (PrintPreferenceChangeEvent == NULL) &&
  435. (PrintUILibHndl == NULL) &&
  436. (PrintUIEntryFunc == NULL) &&
  437. (PnpInterfaceFunc == NULL) &&
  438. (UMRPDPPRN_TokenForLoggedOnUser == INVALID_HANDLE_VALUE) &&
  439. (PrinterInfo2Buf == NULL) &&
  440. (PrinterInfo2BufSize == 0) &&
  441. (UMRDPPRN_WaitableObjMgr == NULL) &&
  442. (WaitableTimer == NULL) &&
  443. (DeviceList == NULL) &&
  444. !PrintingModuleInitialized);
  445. //
  446. // Is it PTS?
  447. //
  448. g_fIsPTS = IsItPTS();
  449. //
  450. // Zero the default printer name record.
  451. //
  452. wcscpy(SavedDefaultPrinterName, L"");
  453. //
  454. // Record the device list.
  455. //
  456. DeviceList = deviceList;
  457. //
  458. // Record the waitable object mananager.
  459. //
  460. UMRDPPRN_WaitableObjMgr = waitableObjMgr;
  461. //
  462. // Record the token for the logged in user.
  463. //
  464. UMRPDPPRN_TokenForLoggedOnUser = hTokenForLoggedOnUser;
  465. ASSERT(UMRPDPPRN_TokenForLoggedOnUser != NULL);
  466. if (UMRPDPPRN_TokenForLoggedOnUser != NULL) {
  467. impersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser);
  468. //
  469. // not fatal. Just a perf hit
  470. //
  471. if (!impersonated) {
  472. DBGMSG(DBG_ERROR,
  473. ("UMRDPPRN:Impersonation failed. Error: %ld\n", GetLastError()));
  474. }
  475. }
  476. //
  477. // Open the local print server while impersonating.
  478. // We need to impersonate so that notifications for
  479. // the printers belonging to the current user's sessions
  480. // are not sent to any other sessions.
  481. //
  482. result = OpenPrinter(NULL, &LocalPrinterServerHandle, NULL);
  483. if (impersonated) {
  484. RevertToSelf();
  485. }
  486. //
  487. // Initialize the print utility module, RDPDRPRT
  488. //
  489. if (result) {
  490. result = RDPDRUTL_Initialize(hTokenForLoggedOnUser);
  491. if (!result) {
  492. errorEventID = EVENT_NOTIFY_INSUFFICIENTRESOURCES;
  493. errorEventLineNumber = __LINE__;
  494. }
  495. }
  496. else {
  497. errorEventID = EVENT_NOTIFY_SPOOLERERROR;
  498. errorEventLineNumber = __LINE__;
  499. DBGMSG(DBG_ERROR,
  500. ("UMRDPPRN:Error opening printer. Error: %ld\n",
  501. GetLastError()));
  502. }
  503. //
  504. // Load configurable values out of the registry.
  505. //
  506. LoadConfigurableValues();
  507. //
  508. // Create the timer even that we use for staggering printer
  509. // configuration changes to the client.
  510. //
  511. if (result) {
  512. WaitableTimer = CreateWaitableTimer(
  513. NULL, // Security Attribs
  514. TRUE, // Manual Reset
  515. NULL); // Timer Name
  516. if (WaitableTimer != NULL) {
  517. if (WTBLOBJ_AddWaitableObject(
  518. UMRDPPRN_WaitableObjMgr, NULL,
  519. WaitableTimer,
  520. WaitableTimerSignaled
  521. ) != ERROR_SUCCESS) {
  522. errorEventID = EVENT_NOTIFY_INSUFFICIENTRESOURCES;
  523. errorEventLineNumber = __LINE__;
  524. result = FALSE;
  525. }
  526. }
  527. else {
  528. errorEventID = EVENT_NOTIFY_INSUFFICIENTRESOURCES;
  529. errorEventLineNumber = __LINE__;
  530. DBGMSG(DBG_ERROR,
  531. ("UMRDPPRN:Error creating Waitable timer. Error: %ld\n",
  532. GetLastError()));
  533. result = FALSE;
  534. }
  535. }
  536. //
  537. // Register for changes to one of this session's printers' Printing
  538. // Preferences.
  539. //
  540. if (result) {
  541. PrintPreferenceChangeEvent = RegisterForPrinterPrefNotify();
  542. if (PrintPreferenceChangeEvent != NULL) {
  543. if (WTBLOBJ_AddWaitableObject(
  544. UMRDPPRN_WaitableObjMgr, NULL,
  545. PrintPreferenceChangeEvent,
  546. PrintPreferenceChangeEventSignaled
  547. ) != ERROR_SUCCESS) {
  548. errorEventID = EVENT_NOTIFY_INSUFFICIENTRESOURCES;
  549. errorEventLineNumber = __LINE__;
  550. result = FALSE;
  551. }
  552. }
  553. else {
  554. result = FALSE;
  555. }
  556. }
  557. //
  558. // Register for change notification on addition/deletion of a
  559. // printer.
  560. //
  561. if (result) {
  562. PrintNotificationEvent = FindFirstPrinterChangeNotification(
  563. LocalPrinterServerHandle,
  564. 0, 0, &PrinterNotifyOptions
  565. );
  566. if (PrintNotificationEvent != INVALID_HANDLE_VALUE) {
  567. DWORD dwLastError = WTBLOBJ_AddWaitableObject(
  568. UMRDPPRN_WaitableObjMgr, NULL,
  569. PrintNotificationEvent,
  570. GlobalPrintNotifyObjectSignaled
  571. );
  572. result = dwLastError == ERROR_SUCCESS;
  573. }
  574. else {
  575. DWORD dwLastError = GetLastError();
  576. errorEventID = EVENT_NOTIFY_SPOOLERERROR;
  577. errorEventLineNumber = __LINE__;
  578. ClosePrinter(LocalPrinterServerHandle);
  579. LocalPrinterServerHandle = NULL;
  580. DBGMSG(DBG_ERROR,
  581. ("UMRDPPRN:Error registering for printer change notification. Error: %ld\n",
  582. dwLastError));
  583. }
  584. }
  585. //
  586. // Construct the inf path for printer installation
  587. //
  588. if (result) {
  589. DWORD dwResult;
  590. dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINDOWSDIRKEY, 0,
  591. KEY_READ, &regKey);
  592. result = (dwResult == ERROR_SUCCESS);
  593. if (result) {
  594. sz = sizeof(PrinterInfPath);
  595. dwResult = RegQueryValueEx(regKey,
  596. WINDOWSDIRVALUENAME,
  597. NULL,
  598. NULL,
  599. (PBYTE)PrinterInfPath,
  600. &sz);
  601. result = (dwResult == ERROR_SUCCESS);
  602. if (result) {
  603. wcscat(PrinterInfPath, INF_PATH);
  604. }
  605. else {
  606. DBGMSG(DBG_ERROR,
  607. ("UMRDPPRN:Error reading registry value for windows directory. Error: %ld\n",
  608. dwResult));
  609. }
  610. RegCloseKey(regKey);
  611. }
  612. else {
  613. errorEventID = EVENT_NOTIFY_INTERNALERROR;
  614. errorEventLineNumber = __LINE__;
  615. DBGMSG(DBG_ERROR,
  616. ("UMRDPPRN:Error opening registry key for windows directory. Error: %ld\n",
  617. dwResult));
  618. }
  619. }
  620. //
  621. // Load the PrintUILib DLL.
  622. //
  623. if (result) {
  624. PrintUILibHndl = LoadLibrary(PRINTUILIBNAME);
  625. result = (PrintUILibHndl != NULL);
  626. if (!result) {
  627. errorEventID = EVENT_NOTIFY_INTERNALERROR;
  628. errorEventLineNumber = __LINE__;
  629. DBGMSG(DBG_ERROR,
  630. ("UMRDPPRN:Unable to load PRINTUI DLL. Error: %ld\n",
  631. GetLastError()));
  632. }
  633. }
  634. //
  635. // Get a pointer to the only entry point that we use.
  636. //
  637. if (result) {
  638. PrintUIEntryFunc = GetProcAddress(PrintUILibHndl, "PrintUIEntryW");
  639. PnpInterfaceFunc = GetProcAddress(PrintUILibHndl, "PnPInterface");
  640. result = (PrintUIEntryFunc != NULL && PnpInterfaceFunc != NULL);
  641. if (!result) {
  642. errorEventID = EVENT_NOTIFY_INTERNALERROR;
  643. errorEventLineNumber = __LINE__;
  644. DBGMSG(DBG_ERROR,
  645. ("UMRDPPRN:Unable to locate PRINTUI DLL function. Error: %ld\n",
  646. GetLastError()));
  647. }
  648. }
  649. //
  650. // Initialize the printer driver name mapping buffer to a reasonable size.
  651. // Failure of this function to allocate memory is not a critical error because
  652. // we can try again later, if necessary.
  653. //
  654. UMRDPDR_ResizeBuffer(&MappedDriverNameBuf, MAX_PATH * sizeof(WCHAR),
  655. &MappedDriverNameBufSize);
  656. //
  657. // Load our localizable "session" printer name component from the resource file.
  658. //
  659. if (result) {
  660. if (!LoadString(g_hInstance,
  661. g_fIsPTS?IDS_TSPTEMPLATE_FROM:IDS_TSPTEMPLATE_FROM_IN,
  662. g_szFromFormat,
  663. sizeof(g_szFromFormat) / sizeof(g_szFromFormat[0])
  664. )) {
  665. DBGMSG(DBG_ERROR, ("UMRDPPRN:LoadString failed with Error: %ld.\n", GetLastError()));
  666. g_szFromFormat[0] = L'\0';
  667. }
  668. if (!LoadString(g_hInstance,
  669. g_fIsPTS?IDS_TSPTEMPLATE_ON_FROM:IDS_TSPTEMPLATE_ON_FROM_IN,
  670. g_szOnFromFormat,
  671. sizeof(g_szOnFromFormat) / sizeof(g_szOnFromFormat[0])
  672. )) {
  673. DBGMSG(DBG_ERROR, ("UMRDPPRN:LoadString failed with Error: %ld.\n", GetLastError()));
  674. g_szOnFromFormat[0] = L'\0';
  675. }
  676. }
  677. if (result) {
  678. DBGMSG(DBG_INFO, ("UMRDPPRN:UMRDPPRN_Initialize succeeded.\n"));
  679. PrintingModuleInitialized = TRUE;
  680. }
  681. else {
  682. //
  683. // Log an error event if we were able to discern one.
  684. //
  685. if (errorEventID != -1) {
  686. TsLogError(errorEventID, EVENTLOG_ERROR_TYPE, 0, NULL, errorEventLineNumber);
  687. }
  688. if (PrintUILibHndl != NULL) {
  689. FreeLibrary(PrintUILibHndl);
  690. PrintUILibHndl = NULL;
  691. }
  692. PrintUIEntryFunc = NULL;
  693. PnpInterfaceFunc = NULL;
  694. //
  695. // Close down waitable objects.
  696. //
  697. CloseWaitablePrintingObjects();
  698. //
  699. // Zero the waitable object manager.
  700. //
  701. UMRDPPRN_WaitableObjMgr = NULL;
  702. if (LocalPrinterServerHandle != NULL) {
  703. ClosePrinter(LocalPrinterServerHandle);
  704. LocalPrinterServerHandle = NULL;
  705. }
  706. //
  707. // Release the user-configurable client driver name mapping INF
  708. // and section names.
  709. //
  710. if (UserDefinedMappingINFName != NULL) {
  711. FREEMEM(UserDefinedMappingINFName);
  712. UserDefinedMappingINFName = NULL;
  713. }
  714. if (UserDefinedMappingINFSection != NULL) {
  715. FREEMEM(UserDefinedMappingINFSection);
  716. UserDefinedMappingINFSection = NULL;
  717. }
  718. }
  719. return result;
  720. }
  721. BOOL
  722. UMRDPPRN_Shutdown()
  723. /*++
  724. Routine Description:
  725. Close down this module. Right now, we just need to shut down the
  726. background thread.
  727. Arguments:
  728. NA
  729. Return Value:
  730. Returns TRUE on success. FALSE, otherwise.
  731. --*/
  732. {
  733. DBGMSG(DBG_TRACE, ("UMRDPPRN:UMRDPPRN_Shutdown.\n"));
  734. //
  735. // Check if we are already shutdown
  736. //
  737. if (!PrintingModuleInitialized) {
  738. return TRUE;
  739. }
  740. //
  741. // Unload printui.dll.
  742. //
  743. if (PrintUILibHndl != NULL) {
  744. FreeLibrary(PrintUILibHndl);
  745. PrintUILibHndl = NULL;
  746. }
  747. //
  748. // Zero the printui entry point function.
  749. //
  750. PrintUIEntryFunc = NULL;
  751. PnpInterfaceFunc = NULL;
  752. //
  753. // Shut down the print utility module, RDPDRPRT
  754. //
  755. RDPDRUTL_Shutdown();
  756. //
  757. // Close down waitable objects.
  758. //
  759. CloseWaitablePrintingObjects();
  760. //
  761. // Zero the waitable object manager.
  762. //
  763. UMRDPPRN_WaitableObjMgr = NULL;
  764. //
  765. // Zero the device list.
  766. //
  767. DeviceList = NULL;
  768. //
  769. // Close the handle to the open printing system dev mode registry
  770. // key for this user.
  771. //
  772. if (DevModeHKey != INVALID_HANDLE_VALUE) {
  773. RegCloseKey(DevModeHKey);
  774. DevModeHKey = INVALID_HANDLE_VALUE;
  775. }
  776. //
  777. // Close the handle to the local print server.
  778. //
  779. if (LocalPrinterServerHandle != NULL) {
  780. ClosePrinter(LocalPrinterServerHandle);
  781. LocalPrinterServerHandle = NULL;
  782. }
  783. //
  784. // Release the printer information level 2 buffer.
  785. //
  786. if (PrinterInfo2Buf != NULL) {
  787. FREEMEM(PrinterInfo2Buf);
  788. PrinterInfo2Buf = NULL;
  789. PrinterInfo2BufSize = 0;
  790. }
  791. //
  792. // Release the printer driver name conversion buffer.
  793. //
  794. if (MappedDriverNameBuf != NULL) {
  795. FREEMEM(MappedDriverNameBuf);
  796. MappedDriverNameBuf = NULL;
  797. MappedDriverNameBufSize = 0;
  798. }
  799. //
  800. // Release the user-configurable client driver name mapping INF
  801. // and section names.
  802. //
  803. if (UserDefinedMappingINFName != NULL) {
  804. FREEMEM(UserDefinedMappingINFName);
  805. UserDefinedMappingINFName = NULL;
  806. }
  807. if (UserDefinedMappingINFSection != NULL) {
  808. FREEMEM(UserDefinedMappingINFSection);
  809. UserDefinedMappingINFSection = NULL;
  810. }
  811. //
  812. // Zero the logged on user token.
  813. //
  814. UMRPDPPRN_TokenForLoggedOnUser = INVALID_HANDLE_VALUE;
  815. //
  816. // We are no longer initialized.
  817. //
  818. PrintingModuleInitialized = FALSE;
  819. DBGMSG(DBG_TRACE, ("UMRDPPRN:UMRDPPRN_Shutdown succeeded.\n"));
  820. return TRUE;
  821. }
  822. VOID
  823. CloseWaitablePrintingObjects()
  824. /*++
  825. Routine Description:
  826. Close out all waitable objects for this module.
  827. Arguments:
  828. NA
  829. Return Value:
  830. NA
  831. --*/
  832. {
  833. DWORD ofs;
  834. DBGMSG(DBG_TRACE, ("UMRDPPRN:CloseWaitablePrintingObjects begin.\n"));
  835. //
  836. // Scan the device list, looking for printing devices with registered
  837. // change notifications.
  838. //
  839. if (DeviceList != NULL) {
  840. for (ofs=0; ofs<DeviceList->deviceCount; ofs++) {
  841. if ((DeviceList->devices[ofs].deviceType == RDPDR_DTYP_PRINT) &&
  842. (DeviceList->devices[ofs].deviceSpecificData != NULL)) {
  843. PPRINTNOTIFYREC notifyRec = (PPRINTNOTIFYREC)
  844. DeviceList->devices[ofs].deviceSpecificData;
  845. ASSERT(notifyRec->notificationObject != NULL);
  846. ASSERT(notifyRec->printerHandle != NULL);
  847. if (UMRDPPRN_WaitableObjMgr != NULL) {
  848. WTBLOBJ_RemoveWaitableObject(
  849. UMRDPPRN_WaitableObjMgr,
  850. notifyRec->notificationObject
  851. );
  852. }
  853. FindClosePrinterChangeNotification(
  854. notifyRec->notificationObject
  855. );
  856. FREEMEM(notifyRec);
  857. DeviceList->devices[ofs].deviceSpecificData = NULL;
  858. }
  859. }
  860. }
  861. //
  862. // Close the waitable timer.
  863. //
  864. if (WaitableTimer != NULL) {
  865. if (UMRDPPRN_WaitableObjMgr != NULL) {
  866. WTBLOBJ_RemoveWaitableObject(
  867. UMRDPPRN_WaitableObjMgr,
  868. WaitableTimer
  869. );
  870. }
  871. CloseHandle(WaitableTimer);
  872. WaitableTimer = NULL;
  873. }
  874. //
  875. // Close the handle to the printer notification event.
  876. //
  877. if (PrintNotificationEvent != INVALID_HANDLE_VALUE) {
  878. if (UMRDPPRN_WaitableObjMgr != NULL) {
  879. WTBLOBJ_RemoveWaitableObject(
  880. UMRDPPRN_WaitableObjMgr,
  881. PrintNotificationEvent
  882. );
  883. }
  884. FindClosePrinterChangeNotification(PrintNotificationEvent);
  885. PrintNotificationEvent = INVALID_HANDLE_VALUE;
  886. }
  887. //
  888. // Close the handle to the printer preference change notification event.
  889. //
  890. if (PrintPreferenceChangeEvent != NULL) {
  891. if (UMRDPPRN_WaitableObjMgr != NULL) {
  892. WTBLOBJ_RemoveWaitableObject(
  893. UMRDPPRN_WaitableObjMgr,
  894. PrintPreferenceChangeEvent
  895. );
  896. }
  897. CloseHandle(PrintPreferenceChangeEvent);
  898. PrintPreferenceChangeEvent = NULL;
  899. }
  900. DBGMSG(DBG_TRACE, ("UMRDPPRN:CloseWaitablePrintingObjects end.\n"));
  901. }
  902. BOOL
  903. UMRDPPRN_HandlePrinterAnnounceEvent(
  904. IN PRDPDR_PRINTERDEVICE_SUB pPrintAnnounce
  905. )
  906. /*++
  907. Routine Description:
  908. Handle a printing device announce event from the "dr" by installing a
  909. local print queue and adding a record for the device to the list of
  910. installed devices.
  911. Arguments:
  912. hTokenForLoggedOnUser - Logged on user token.
  913. pPrintAnnounce - Printer device announce event.
  914. Return Value:
  915. Return TRUE on success. FALSE, otherwise.
  916. --*/
  917. {
  918. PWSTR driverName;
  919. PWSTR printerName;
  920. PBYTE pDataFollowingEvent;
  921. UINT codePage;
  922. int numChars;
  923. PWSTR drvNameStringConvertBuf=NULL;
  924. PWSTR prnNameStringConvertBuf=NULL;
  925. BOOL result = FALSE;
  926. PBYTE pPrinterCacheData=NULL;
  927. DWORD PrinterCacheDataLen=0;
  928. BOOL bSetDefault = FALSE;
  929. #if DBG
  930. HANDLE hPrinter = NULL;
  931. PRINTER_DEFAULTS defaults = {NULL, NULL, PRINTER_ALL_ACCESS};
  932. #endif
  933. if (!PrintingModuleInitialized) {
  934. return FALSE;
  935. }
  936. DBGMSG(DBG_TRACE, ("UMRDPPRN:HandlePrinterAnnounceEvent.\n"));
  937. // Sanity check the incoming event.
  938. ASSERT(pPrintAnnounce->deviceFields.DeviceType == RDPDR_DTYP_PRINT);
  939. ASSERT(pPrintAnnounce->deviceFields.DeviceDataLength >=
  940. sizeof(PRDPDR_PRINTERDEVICE_ANNOUNCE));
  941. // Get a pointer to the data that follows the event.
  942. pDataFollowingEvent = ((PBYTE)pPrintAnnounce) +
  943. sizeof(RDPDR_PRINTERDEVICE_SUB);
  944. // The driver name is the second field.
  945. driverName = (PWSTR)(pDataFollowingEvent +
  946. pPrintAnnounce->clientPrinterFields.PnPNameLen
  947. );
  948. // The printer name is the third field.
  949. printerName = (PWSTR)(pDataFollowingEvent +
  950. pPrintAnnounce->clientPrinterFields.PnPNameLen +
  951. pPrintAnnounce->clientPrinterFields.DriverLen
  952. );
  953. // NULL-terminate the names.
  954. // Length (in bytes) from client includes the null.
  955. // So, we need to subtract 1 and then NULL-terminate.
  956. if (pPrintAnnounce->clientPrinterFields.DriverLen > 0) {
  957. driverName[pPrintAnnounce->clientPrinterFields.DriverLen/sizeof(WCHAR) - 1] = L'\0';
  958. }
  959. if (pPrintAnnounce->clientPrinterFields.PrinterNameLen > 0) {
  960. printerName[pPrintAnnounce->clientPrinterFields.PrinterNameLen/sizeof(WCHAR) - 1] = L'\0';
  961. }
  962. // Cache data is the last field
  963. if (pPrintAnnounce->clientPrinterFields.CachedFieldsLen > 0) {
  964. PrinterCacheDataLen = pPrintAnnounce->clientPrinterFields.CachedFieldsLen;
  965. pPrinterCacheData = (PBYTE)(pDataFollowingEvent +
  966. pPrintAnnounce->clientPrinterFields.PnPNameLen +
  967. pPrintAnnounce->clientPrinterFields.DriverLen +
  968. pPrintAnnounce->clientPrinterFields.PrinterNameLen
  969. );
  970. DBGMSG(DBG_TRACE, ("PrinterNameLen - %ld\n", pPrintAnnounce->clientPrinterFields.PrinterNameLen));
  971. }
  972. //
  973. // See if we need to convert the name from ANSI to UNICODE.
  974. //
  975. if (pPrintAnnounce->clientPrinterFields.Flags & RDPDR_PRINTER_ANNOUNCE_FLAG_ANSI) {
  976. DBGMSG(DBG_TRACE, ("UMRDPPRN:HandlePrinterAnnounceEvent ansi flag is set.\n"));
  977. DBGMSG(DBG_TRACE, ("UMRDPPRN:HandlePrinterAnnounceEvent converting to unicode.\n"));
  978. //
  979. // Convert the driver name.
  980. //
  981. drvNameStringConvertBuf = ANSIToUnicode(
  982. (LPCSTR)driverName,
  983. pPrintAnnounce->clientPrinterFields.CodePage
  984. );
  985. if (drvNameStringConvertBuf != NULL) {
  986. driverName = drvNameStringConvertBuf;
  987. }
  988. else {
  989. return FALSE;
  990. }
  991. //
  992. // Convert the printer name.
  993. //
  994. prnNameStringConvertBuf = ANSIToUnicode(
  995. (LPCSTR)printerName,
  996. pPrintAnnounce->clientPrinterFields.CodePage
  997. );
  998. if (prnNameStringConvertBuf != NULL) {
  999. printerName = prnNameStringConvertBuf;
  1000. }
  1001. else {
  1002. FREEMEM(drvNameStringConvertBuf);
  1003. return FALSE;
  1004. }
  1005. }
  1006. if (pPrintAnnounce->clientPrinterFields.Flags &
  1007. RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER) {
  1008. bSetDefault = TRUE;
  1009. g_fDefPrinterEncountered = TRUE;
  1010. }
  1011. else {
  1012. bSetDefault = (!g_fDefPrinterEncountered) ? TRUE : FALSE;
  1013. }
  1014. DBGMSG(DBG_TRACE, ("UMRDPPRN:HandlePrinterAnnounceEvent driver name is %ws.\n",
  1015. driverName));
  1016. DBGMSG(DBG_TRACE, ("UMRDPPRN:HandlePrinterAnnounceEvent printer name is %ws.\n",
  1017. printerName));
  1018. // We will install the printer using the driver name only for now.
  1019. // Later, we can take advantage of the rest of the fields.
  1020. if (UMRDPDR_fAutoInstallPrinters()) {
  1021. result = InstallPrinterWithPortName(
  1022. pPrintAnnounce->deviceFields.DeviceId,
  1023. UMRPDPPRN_TokenForLoggedOnUser,
  1024. bSetDefault,
  1025. pPrintAnnounce->clientPrinterFields.Flags,
  1026. pPrintAnnounce->portName,
  1027. driverName,
  1028. printerName,
  1029. pPrintAnnounce->clientName,
  1030. pPrinterCacheData,
  1031. PrinterCacheDataLen
  1032. );
  1033. }
  1034. else {
  1035. result = TRUE;
  1036. }
  1037. // Release any buffers allocated for string conversion.
  1038. if (drvNameStringConvertBuf != NULL) {
  1039. FREEMEM(drvNameStringConvertBuf);
  1040. }
  1041. if (prnNameStringConvertBuf != NULL) {
  1042. FREEMEM(prnNameStringConvertBuf);
  1043. }
  1044. return result;
  1045. }
  1046. void
  1047. PrintPreferenceChangeEventSignaled(
  1048. HANDLE eventHandle,
  1049. PVOID clientData
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. This function handles when the user changes one of this session's printers'
  1054. Printing Preferences settings.
  1055. Arguments:
  1056. eventHandle - Signaled event.
  1057. clientData - Client data associated with callback registration.
  1058. Return Value:
  1059. NA
  1060. --*/
  1061. {
  1062. time_t timeDelta;
  1063. ULONG ofs;
  1064. ULONG ret;
  1065. DBGMSG(DBG_TRACE, ("UMRDPPRN:PrintPreferenceChangeEventSignaled entered.\n"));
  1066. //
  1067. // Reregister the change notification.
  1068. //
  1069. ASSERT(DevModeHKey != INVALID_HANDLE_VALUE);
  1070. ret = RegNotifyChangeKeyValue(
  1071. DevModeHKey,
  1072. TRUE,
  1073. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
  1074. eventHandle,
  1075. TRUE
  1076. );
  1077. //
  1078. // On failure, remove the notification registration.
  1079. //
  1080. if (ret != ERROR_SUCCESS) {
  1081. //
  1082. // Catch this with an assert so we can know how often this happens.
  1083. //
  1084. ASSERT(FALSE);
  1085. if (PrintPreferenceChangeEvent != NULL) {
  1086. if (UMRDPPRN_WaitableObjMgr != NULL) {
  1087. WTBLOBJ_RemoveWaitableObject(
  1088. UMRDPPRN_WaitableObjMgr,
  1089. PrintPreferenceChangeEvent
  1090. );
  1091. }
  1092. CloseHandle(PrintPreferenceChangeEvent);
  1093. PrintPreferenceChangeEvent = NULL;
  1094. }
  1095. DBGMSG(DBG_ERROR,
  1096. ("UMRDPPRN: can't register for registry key change event: %ld.\n",
  1097. ret));
  1098. }
  1099. //
  1100. // Since we have no way of knowing which printer changed, we need to
  1101. // handle this change for all printing devices.
  1102. //
  1103. for (ofs=0; ofs<DeviceList->deviceCount; ofs++) {
  1104. if (DeviceList->devices[ofs].deviceType == RDPDR_DTYP_PRINT) {
  1105. //
  1106. // Get the delta between the current time and when this device was
  1107. // installed. It outside the configurable threshhold, then the
  1108. // updated configuration should be sent to the client.
  1109. //
  1110. timeDelta = time(NULL) - DeviceList->devices[ofs].installTime;
  1111. if ((DWORD)timeDelta > ConfigSendThreshold) {
  1112. DBGMSG(DBG_TRACE,
  1113. ("UMRDPPRN:Processing config change because outside time delta.\n")
  1114. );
  1115. //
  1116. // Need to record that the configuration has changed and set a
  1117. // timer on forwarding to the client in order to compress changes into
  1118. // a single message to the client.
  1119. //
  1120. DeviceList->devices[ofs].fConfigInfoChanged = TRUE;
  1121. TriggerConfigChangeTimer();
  1122. }
  1123. }
  1124. }
  1125. DBGMSG(DBG_TRACE, ("UMRDPPRN:PrintPreferenceChangeEventSignaled done.\n"));
  1126. }
  1127. void
  1128. GlobalPrintNotifyObjectSignaled(
  1129. HANDLE waitableObject,
  1130. PVOID clientData
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. This function is called when the notification object for the local
  1135. print server is signaled. This is how we catch "global" changes to
  1136. the server printer configuration.
  1137. Changes detected here allow us to detect manually added TS printers
  1138. as well as a subset of possible configuration changes to existing
  1139. printers for this session.
  1140. Arguments:
  1141. waitableObject - Associated waitable object.
  1142. clientData - Client data associated with callback registration.
  1143. Return Value:
  1144. NA
  1145. --*/
  1146. {
  1147. DWORD changeValue;
  1148. PPRINTER_NOTIFY_INFO notifyInfo=NULL;
  1149. UINT32 i;
  1150. BOOL result;
  1151. DBGMSG(DBG_TRACE, ("UMRDPPRN:GlobalPrintNotifyObjectSignaled entered.\n"));
  1152. //
  1153. // Return immediately if the DLL is trying to shut down. This
  1154. // is to help prevent us from getting stuck in a system call.
  1155. //
  1156. if (ShutdownFlag) {
  1157. return;
  1158. }
  1159. //
  1160. // These two objects should be on in the same.
  1161. //
  1162. ASSERT(PrintNotificationEvent == waitableObject);
  1163. //
  1164. // Find out what changed.
  1165. //
  1166. PrinterNotifyOptions.Flags &= ~PRINTER_NOTIFY_OPTIONS_REFRESH;
  1167. result = FindNextPrinterChangeNotification(
  1168. PrintNotificationEvent, &changeValue,
  1169. &PrinterNotifyOptions, &notifyInfo
  1170. );
  1171. if (result && (notifyInfo != NULL)) {
  1172. //
  1173. // If this is not a refresh, then just handle individual notification
  1174. // events.
  1175. //
  1176. if (!(notifyInfo->Flags & PRINTER_NOTIFY_INFO_DISCARDED)) {
  1177. for (i=0; i<notifyInfo->Count; i++) {
  1178. // Notification Type must be PRINTER_NOTIFY_TYPE.
  1179. ASSERT(notifyInfo->aData[i].Type == PRINTER_NOTIFY_TYPE);
  1180. //
  1181. // If we have a printer name change event. This is what we use to
  1182. // detect new printers and renamed printers.
  1183. //
  1184. if (notifyInfo->aData[i].Field == PRINTER_NOTIFY_FIELD_PRINTER_NAME) {
  1185. HandlePrinterNameChangeNotification(
  1186. notifyInfo->aData[i].Id,
  1187. (LPWSTR)notifyInfo->aData[i].NotifyData.Data.pBuf
  1188. );
  1189. }
  1190. //
  1191. // If the Configuration Information changed.
  1192. //
  1193. else if (IS_CONFIG_INFO_FIELD(notifyInfo->aData[i].Field)) {
  1194. HandlePrinterConfigChangeNotification(
  1195. notifyInfo->aData[i].Id
  1196. );
  1197. }
  1198. }
  1199. }
  1200. //
  1201. // Otherwise, we need to refresh. This is an unusual case.
  1202. //
  1203. else {
  1204. DBGMSG(DBG_TRACE,
  1205. ("UMRDPPRN:!!!!FindNextPrinterChangeNotification refresh required.!!!!\n"));
  1206. //
  1207. // This refreshes the complete list of printers.
  1208. //
  1209. FreePrinterNotifyInfo(notifyInfo);
  1210. notifyInfo = NULL;
  1211. PrinterNotifyOptions.Flags |= PRINTER_NOTIFY_OPTIONS_REFRESH;
  1212. result = FindNextPrinterChangeNotification(
  1213. PrintNotificationEvent, &changeValue,
  1214. &PrinterNotifyOptions, &notifyInfo
  1215. );
  1216. //
  1217. // Make sure our view of the list of available printers
  1218. // is accurate.
  1219. //
  1220. if (result) {
  1221. HandlePrinterRefreshNotification(
  1222. notifyInfo
  1223. );
  1224. }
  1225. else {
  1226. DBGMSG(DBG_ERROR, ("UMRDPPRN:FindNextPrinterChangeNotification failed: %ld.\n",
  1227. GetLastError()));
  1228. }
  1229. }
  1230. }
  1231. //
  1232. // On failure, we need to remove the printer change notification object so we don't
  1233. // get into an infinite loop caused by the notification object never entering a
  1234. // non-signaled state. This can happen on a stressed machine and is an unusual
  1235. // case.
  1236. //
  1237. if (!result) {
  1238. DBGMSG(DBG_ERROR, ("UMRDPPRN:FindNextPrinterChangeNotification failed: %ld.\n",
  1239. GetLastError()));
  1240. DBGMSG(DBG_ERROR, ("UMRDPPRN:Disabling print change notification.\n"));
  1241. if (PrintNotificationEvent != INVALID_HANDLE_VALUE) {
  1242. WTBLOBJ_RemoveWaitableObject(
  1243. UMRDPPRN_WaitableObjMgr,
  1244. PrintNotificationEvent
  1245. );
  1246. FindClosePrinterChangeNotification(PrintNotificationEvent);
  1247. PrintNotificationEvent = INVALID_HANDLE_VALUE;
  1248. }
  1249. }
  1250. //
  1251. // Release the notification buffer.
  1252. //
  1253. if (notifyInfo != NULL) {
  1254. FreePrinterNotifyInfo(notifyInfo);
  1255. }
  1256. }
  1257. VOID
  1258. SinglePrinterNotifyObjectSignaled(
  1259. HANDLE waitableObject,
  1260. PPRINTNOTIFYREC notifyRec
  1261. )
  1262. /*++
  1263. Routine Description:
  1264. This function is called when the notification object for a single
  1265. printer is signaled. This function indicates that we need to forward
  1266. configuration information for a specific printer to the client for
  1267. persistent storage.
  1268. Arguments:
  1269. waitableObject - Associated waitable object.
  1270. serverDeviceID - Device list identifier for printing device being
  1271. signaled.
  1272. Return Value:
  1273. NA
  1274. --*/
  1275. {
  1276. DWORD ofs;
  1277. BOOL result;
  1278. DWORD changeValue;
  1279. DBGMSG(DBG_TRACE, ("UMRDPPRN:SinglePrinterNotifyObjectSignaled entered.\n"));
  1280. //
  1281. // Return immediately if the DLL is trying to shut down. This
  1282. // is to help prevent us from getting stuck in a system call.
  1283. //
  1284. if (ShutdownFlag) {
  1285. return;
  1286. }
  1287. result = DRDEVLST_FindByServerDeviceID(
  1288. DeviceList,
  1289. notifyRec->serverDeviceID,
  1290. &ofs);
  1291. ASSERT(result);
  1292. //
  1293. // Re-register the change notification.
  1294. //
  1295. if (result) {
  1296. ASSERT(notifyRec ==
  1297. (PPRINTNOTIFYREC)DeviceList->devices[ofs].deviceSpecificData)
  1298. ASSERT(notifyRec->notificationObject != NULL);
  1299. ASSERT(notifyRec->printerHandle != NULL);
  1300. ASSERT(notifyRec->notificationObject == waitableObject);
  1301. result = FindNextPrinterChangeNotification(
  1302. notifyRec->notificationObject,
  1303. &changeValue,
  1304. NULL, NULL
  1305. );
  1306. }
  1307. //
  1308. // If this failed, we need to release the change notification
  1309. // object to prevent infinitely looping on a signaled object.
  1310. //
  1311. if (!result) {
  1312. //
  1313. // Catch this with an assert so we can know how often this happens.
  1314. //
  1315. ASSERT(FALSE);
  1316. WTBLOBJ_RemoveWaitableObject(
  1317. UMRDPPRN_WaitableObjMgr,
  1318. notifyRec->notificationObject
  1319. );
  1320. FindClosePrinterChangeNotification(
  1321. notifyRec->notificationObject
  1322. );
  1323. ClosePrinter(notifyRec->printerHandle);
  1324. FREEMEM(notifyRec);
  1325. DeviceList->devices[ofs].deviceSpecificData = NULL;
  1326. }
  1327. //
  1328. // Handle the change.
  1329. //
  1330. if (result) {
  1331. //
  1332. // If it's a printer deletion.
  1333. //
  1334. if (changeValue & PRINTER_CHANGE_DELETE_PRINTER) {
  1335. HandlePrinterDeleteNotification(notifyRec->serverDeviceID);
  1336. }
  1337. //
  1338. // If it's a configuration change.
  1339. //
  1340. else if (changeValue &
  1341. (PRINTER_CHANGE_ADD_PRINTER_DRIVER |
  1342. PRINTER_CHANGE_SET_PRINTER_DRIVER |
  1343. PRINTER_CHANGE_DELETE_PRINTER_DRIVER)) {
  1344. HandlePrinterConfigChangeNotification(notifyRec->serverDeviceID);
  1345. }
  1346. }
  1347. DBGMSG(DBG_TRACE,
  1348. ("UMRDPPRN:SinglePrinterNotifyObjectSignaled exit.\n")
  1349. );
  1350. }
  1351. void
  1352. HandlePrinterRefreshNotification(
  1353. IN PPRINTER_NOTIFY_INFO notifyInfo
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. Handle a print notification refresh from the spooler.
  1358. Arguments:
  1359. notifyInfo - Notify info pointer returned by
  1360. FindNextPrinterChangeNotification.
  1361. Return Value:
  1362. NA
  1363. --*/
  1364. {
  1365. DWORD deviceListOfs;
  1366. DWORD notifyOfs;
  1367. LPWSTR printerName;
  1368. DWORD i;
  1369. DBGMSG(DBG_TRACE, ("UMRDPPRN:HandlePrinterRefreshNotification entered.\n"));
  1370. //
  1371. // Return immediately if the DLL is trying to shut down. This
  1372. // is to help prevent us from getting stuck in a system call.
  1373. //
  1374. if (ShutdownFlag) {
  1375. return;
  1376. }
  1377. //
  1378. // Handle printer additions, renames, etc.
  1379. //
  1380. for (i=0; i<notifyInfo->Count; i++) {
  1381. // Notification Type must be PRINTER_NOTIFY_TYPE.
  1382. ASSERT(notifyInfo->aData[i].Type == PRINTER_NOTIFY_TYPE);
  1383. //
  1384. // If we have a printer name change event. This is what we use to
  1385. // detect new printers and renamed printers.
  1386. //
  1387. if (notifyInfo->aData[i].Field == PRINTER_NOTIFY_FIELD_PRINTER_NAME) {
  1388. printerName = (LPWSTR)notifyInfo->aData[i].NotifyData.Data.pBuf;
  1389. HandlePrinterNameChangeNotification(
  1390. notifyInfo->aData[i].Id,
  1391. printerName
  1392. );
  1393. }
  1394. }
  1395. }
  1396. BOOL
  1397. HandlePrinterDeleteNotification(
  1398. IN DWORD serverDeviceID
  1399. )
  1400. /*++
  1401. Routine Description:
  1402. Handle notification from the spooler that a printer has been deleted.hanged.
  1403. Arguments:
  1404. serverDeviceID - Server-assigned device ID for printer being deleted.
  1405. Return Value:
  1406. Return TRUE on success. FALSE, otherwise.
  1407. --*/
  1408. {
  1409. DWORD ofs;
  1410. BOOL result;
  1411. DBGMSG(DBG_TRACE, ("UMRDPPRN:HandlePrinterDeleteNotification with server ID %ld.\n",
  1412. serverDeviceID));
  1413. //
  1414. // Return immediately if the DLL is trying to shut down. This
  1415. // is to help prevent us from getting stuck in a system call.
  1416. //
  1417. if (ShutdownFlag) {
  1418. return FALSE;
  1419. }
  1420. //
  1421. // If this is for one of our printers.
  1422. //
  1423. if (DRDEVLST_FindByServerDeviceID(DeviceList,
  1424. serverDeviceID, &ofs)) {
  1425. DBGMSG(DBG_TRACE, ("UMRDPPRN:****Printer %ws has been removed.****\n",
  1426. DeviceList->devices[ofs].serverDeviceName));
  1427. //
  1428. // Send a message to the client to let it know that a printer has been
  1429. // deleted.
  1430. //
  1431. result = SendDeletePrinterMsgToClient(
  1432. DeviceList->devices[ofs].clientDeviceName);
  1433. //
  1434. // Clean up the notification object if one is registered.
  1435. //
  1436. if (DeviceList->devices[ofs].deviceSpecificData != NULL) {
  1437. PPRINTNOTIFYREC notifyRec =
  1438. (PPRINTNOTIFYREC)DeviceList->devices[ofs].deviceSpecificData;
  1439. ASSERT(notifyRec->notificationObject != NULL);
  1440. ASSERT(notifyRec->printerHandle != NULL);
  1441. WTBLOBJ_RemoveWaitableObject(
  1442. UMRDPPRN_WaitableObjMgr,
  1443. notifyRec->notificationObject
  1444. );
  1445. FindClosePrinterChangeNotification(
  1446. notifyRec->notificationObject
  1447. );
  1448. ClosePrinter(notifyRec->printerHandle);
  1449. FREEMEM(notifyRec);
  1450. DeviceList->devices[ofs].deviceSpecificData = NULL;
  1451. }
  1452. //
  1453. // Remove it from the list of managed devices.
  1454. //
  1455. DRDEVLST_Remove(DeviceList, ofs);
  1456. }
  1457. else {
  1458. result = TRUE;
  1459. }
  1460. return result;
  1461. }
  1462. BOOL
  1463. HandlePrinterNameChangeNotification(
  1464. IN DWORD serverDeviceID,
  1465. IN LPWSTR printerName
  1466. )
  1467. /*++
  1468. Routine Description:
  1469. Handle notification from the spooler that the name of a printer has changed.
  1470. This allows us to track these significant events:
  1471. -A printer automatically created by us has been assigned a device ID by the
  1472. spooler.
  1473. -A new printer has been manually added to the system and attached to one
  1474. of our redirected ports.
  1475. -A printer attached to one of our redirected ports has had its name changed.
  1476. Arguments:
  1477. serverDeviceID - Server-assigned device ID associated with the printer
  1478. name change.
  1479. printerName - New printer name.
  1480. Return Value:
  1481. Return TRUE on success. FALSE, otherwise.
  1482. --*/
  1483. {
  1484. HANDLE hPrinter = NULL;
  1485. BOOL result = TRUE;
  1486. PRINTER_DEFAULTS defaults = {NULL, NULL, PRINTER_ALL_ACCESS};
  1487. BOOL printerInList;
  1488. BOOL isNewPrinter;
  1489. DWORD ofs;
  1490. BOOL printerNameExists;
  1491. PWSTR portName;
  1492. DWORD printerNameOfs;
  1493. DWORD len;
  1494. DBGMSG(DBG_TRACE, ("UMRDPPRN:HandlePrinterNameChangeNotification printer %ws.\n",
  1495. printerName));
  1496. //
  1497. // Return immediately if the DLL is trying to shut down. This
  1498. // is to help prevent us from getting stuck in a system call.
  1499. //
  1500. if (ShutdownFlag) {
  1501. return FALSE;
  1502. }
  1503. //
  1504. // See if we already have a matching printer name.
  1505. //
  1506. printerNameExists =
  1507. (DRDEVLST_FindByServerDeviceName(DeviceList, printerName,
  1508. &printerNameOfs)
  1509. && (DeviceList->devices[printerNameOfs].deviceType ==
  1510. RDPDR_DTYP_PRINT));
  1511. //
  1512. // If a printer automatically created by us has been assigned a
  1513. // device ID by the spooler. In some cases, we may get a repeat
  1514. // printer name. That is okay because the ID should be the same.
  1515. //
  1516. if (printerNameExists) {
  1517. DBGMSG(DBG_TRACE,
  1518. ("UMRDPPRN:****Printer %ws has had its ID assigned to %ld.****\n",
  1519. DeviceList->devices[printerNameOfs].serverDeviceName,
  1520. serverDeviceID));
  1521. DeviceList->devices[printerNameOfs].serverDeviceID = serverDeviceID;
  1522. //
  1523. // Register a notification object with the printer, so we can
  1524. // be notified when its configuration changes. This change notification
  1525. // is registered for events that are not picked up by the global
  1526. // change notification object.
  1527. //
  1528. result = RegisterPrinterConfigChangeNotification(
  1529. serverDeviceID
  1530. );
  1531. }
  1532. //
  1533. // If a printer attached to one of our redirected ports has had
  1534. // its name changed.
  1535. //
  1536. else if (DRDEVLST_FindByServerDeviceID(
  1537. DeviceList,
  1538. serverDeviceID, &ofs
  1539. )) {
  1540. WCHAR *pBuf;
  1541. DBGMSG(DBG_TRACE,
  1542. ("UMRDPPRN:****Printer %ws has had its name changed to %ws.****\n",
  1543. DeviceList->devices[ofs].serverDeviceName,
  1544. printerName));
  1545. //
  1546. // Reallocate the server name field.
  1547. //
  1548. len = wcslen(printerName) + 1;
  1549. pBuf = REALLOCMEM(DeviceList->devices[ofs].serverDeviceName,
  1550. len * sizeof(WCHAR));
  1551. if (pBuf != NULL) {
  1552. DeviceList->devices[ofs].serverDeviceName = pBuf;
  1553. } else {
  1554. FREEMEM(DeviceList->devices[ofs].serverDeviceName);
  1555. DeviceList->devices[ofs].serverDeviceName = NULL;
  1556. }
  1557. if (DeviceList->devices[ofs].serverDeviceName != NULL) {
  1558. wcscpy(DeviceList->devices[ofs].serverDeviceName,
  1559. printerName);
  1560. //
  1561. // Send this information (printer name change) across to the client
  1562. //
  1563. DBGMSG(DBG_TRACE,("UMRDPPRN:clientDeviceID is %ld.\n",
  1564. DeviceList->devices[ofs].clientDeviceID ));
  1565. if (SendPrinterRenameToClient(
  1566. DeviceList->devices[ofs].clientDeviceName,
  1567. printerName
  1568. )) {
  1569. //
  1570. // Update the client name
  1571. //
  1572. pBuf = REALLOCMEM(DeviceList->devices[ofs].clientDeviceName,
  1573. len * sizeof(WCHAR));
  1574. if (pBuf != NULL) {
  1575. DeviceList->devices[ofs].clientDeviceName = pBuf;
  1576. } else {
  1577. FREEMEM(DeviceList->devices[ofs].clientDeviceName);
  1578. DeviceList->devices[ofs].clientDeviceName = NULL;
  1579. }
  1580. if (DeviceList->devices[ofs].clientDeviceName != NULL) {
  1581. wcscpy(DeviceList->devices[ofs].clientDeviceName,
  1582. printerName);
  1583. }
  1584. }
  1585. result = TRUE;
  1586. }
  1587. else {
  1588. DBGMSG(DBG_ERROR,("UMRDPPRN:Unable to allocate %ld bytes.\n",
  1589. len * sizeof(WCHAR)));
  1590. TsLogError(EVENT_NOTIFY_INSUFFICIENTRESOURCES, EVENTLOG_ERROR_TYPE,
  1591. 0, NULL, __LINE__);
  1592. result = FALSE;
  1593. }
  1594. }
  1595. else {
  1596. //
  1597. // Return immediately if the DLL is trying to shut down. This
  1598. // is to help prevent us from getting stuck in a system call.
  1599. //
  1600. if (ShutdownFlag) {
  1601. result = FALSE;
  1602. }
  1603. //
  1604. // Open the printer to get the associated port name.
  1605. //
  1606. if (result) {
  1607. result = OpenPrinter(printerName, &hPrinter, &defaults);
  1608. }
  1609. if (!result && !ShutdownFlag) {
  1610. //
  1611. // If the error is a result of a non-existent printer, the printer has
  1612. // probably been renamed and is pending delete, so this is ok.
  1613. //
  1614. if (GetLastError() == ERROR_INVALID_PRINTER_NAME) {
  1615. DBGMSG(DBG_WARN,
  1616. ("UMRDPDPRN:Error opening %ws in refresh. Error: %ld. Probably ok.\n",
  1617. printerName, GetLastError()));
  1618. result = TRUE;
  1619. }
  1620. else {
  1621. DBGMSG(DBG_ERROR,
  1622. ("UMRDPDPRN:Error opening %ws in refresh. Error: %ld.\n",
  1623. printerName, GetLastError()));
  1624. }
  1625. goto CleanupAndExit;
  1626. }
  1627. //
  1628. // Get the port name for the printer.
  1629. //
  1630. if (result) {
  1631. result = GetPrinterPortName(hPrinter, &portName);
  1632. if (!result) {
  1633. DBGMSG(DBG_ERROR,
  1634. ("UMRDPDPRN:GetPrinterPortName Failed. Error: %ld.\n",
  1635. GetLastError()));
  1636. }
  1637. }
  1638. //
  1639. // If a new printer has been manually added to the system and
  1640. // attached to one of our redirected ports.
  1641. //
  1642. if (result) {
  1643. if (DRDEVLST_FindByServerDeviceName(DeviceList, portName, &ofs) &&
  1644. ISPRINTPORT(DeviceList->devices[ofs].deviceType)) {
  1645. DBGMSG(DBG_TRACE,
  1646. ("UMRDPPRN:****New printer %ws manually attached to %ws.****\n",
  1647. printerName, portName));
  1648. //
  1649. // Send the add printer message to the client. We don't care about
  1650. // the return status, since we can't do anything to recover from
  1651. // a failure to send the message to the client.
  1652. //
  1653. SendAddPrinterMsgToClient(
  1654. printerName,
  1655. PrinterInfo2Buf->pDriverName,
  1656. DeviceList->devices[ofs].preferredDosName
  1657. );
  1658. //
  1659. // Add the session number to the printer queue data to identify the printer
  1660. // as a TS printer. Don't care about the return value here, because its
  1661. // failure for a manually installed printer is not a critical error.
  1662. //
  1663. AddSessionIDToPrinterQueue(hPrinter, GETTHESESSIONID());
  1664. //
  1665. // Add the new printer to our list of managed printers.
  1666. //
  1667. result = DRDEVLST_Add(
  1668. DeviceList, RDPDR_INVALIDDEVICEID,
  1669. serverDeviceID,
  1670. RDPDR_DTYP_PRINT, printerName, printerName, "UNKNOWN"
  1671. );
  1672. //
  1673. // Register a notification object with the printer, so we can
  1674. // be notified when its configuration changes. This change notification
  1675. // is registered for events that are not picked up by the global
  1676. // change notification object.
  1677. //
  1678. if (result) {
  1679. RegisterPrinterConfigChangeNotification(
  1680. serverDeviceID
  1681. );
  1682. }
  1683. }
  1684. }
  1685. }
  1686. CleanupAndExit:
  1687. //
  1688. // Close the printer.
  1689. //
  1690. if (hPrinter != NULL) {
  1691. ClosePrinter(hPrinter);
  1692. }
  1693. return result;
  1694. }
  1695. BOOL
  1696. RegisterPrinterConfigChangeNotification(
  1697. IN DWORD serverDeviceID
  1698. )
  1699. /*++
  1700. Routine Description:
  1701. Register a change notification event with the spooler so that we are
  1702. notified when the configuration for a specific printer has been changed.
  1703. Arguments:
  1704. serverDeviceID - Server-side ID for the device that is used to
  1705. track the device in the device list.
  1706. Return Value:
  1707. TRUE on success. Otherwise, FALSE is returned.
  1708. --*/
  1709. {
  1710. DWORD offset;
  1711. BOOL result;
  1712. PRINTER_DEFAULTS printerDefaults;
  1713. PPRINTNOTIFYREC notifyRec;
  1714. DBGMSG(DBG_TRACE,
  1715. ("UMRDPPRN:RegisterPrinterConfigChangeNotification id %ld.\n",
  1716. serverDeviceID)
  1717. );
  1718. //
  1719. // Find the printer in the device list.
  1720. //
  1721. result = DRDEVLST_FindByServerDeviceID(
  1722. DeviceList, serverDeviceID, &offset
  1723. );
  1724. //
  1725. // Register a notification object with the printer, so we can
  1726. // be notified when its configuration changes. This change notification
  1727. // is registered for events that are not picked up by the global
  1728. // change notification object.
  1729. //
  1730. if (result && (DeviceList->devices[offset].deviceSpecificData == NULL)) {
  1731. LPWSTR name = DeviceList->devices[offset].serverDeviceName;
  1732. printerDefaults.pDatatype = NULL;
  1733. printerDefaults.pDevMode = NULL;
  1734. printerDefaults.DesiredAccess = PRINTER_ALL_ACCESS;
  1735. //
  1736. // Allocate a new notification record.
  1737. //
  1738. notifyRec = ALLOCMEM(sizeof(PRINTNOTIFYREC));
  1739. result = (notifyRec != NULL);
  1740. if (result) {
  1741. notifyRec->printerHandle = NULL;
  1742. notifyRec->notificationObject = NULL;
  1743. notifyRec->serverDeviceID = serverDeviceID;
  1744. result = OpenPrinter(name, &notifyRec->printerHandle,
  1745. &printerDefaults);
  1746. }
  1747. //
  1748. // Register the notification.
  1749. //
  1750. if (result) {
  1751. notifyRec->notificationObject =
  1752. FindFirstPrinterChangeNotification(
  1753. notifyRec->printerHandle,
  1754. PRINTER_CHANGE_PRINTER_DRIVER |
  1755. PRINTER_CHANGE_DELETE_PRINTER, 0,
  1756. NULL
  1757. );
  1758. if (notifyRec->notificationObject != NULL) {
  1759. result =
  1760. WTBLOBJ_AddWaitableObject(
  1761. UMRDPPRN_WaitableObjMgr,
  1762. notifyRec,
  1763. notifyRec->notificationObject,
  1764. SinglePrinterNotifyObjectSignaled
  1765. ) == ERROR_SUCCESS;
  1766. }
  1767. else {
  1768. DBGMSG(
  1769. DBG_ERROR,
  1770. ("UMRDPPRN:FindFirstPrinterChangeNotification failed for %ws: %ld.\n",
  1771. name, GetLastError())
  1772. );
  1773. result = FALSE;
  1774. }
  1775. }
  1776. else {
  1777. DBGMSG(DBG_ERROR, ("UMRDPPRN: Can't open printer %ws: %ld.\n",
  1778. name, GetLastError()));
  1779. }
  1780. //
  1781. // Record the notification record or clean up.
  1782. //
  1783. if (result) {
  1784. DeviceList->devices[offset].deviceSpecificData = notifyRec;
  1785. }
  1786. else if (notifyRec != NULL) {
  1787. if (notifyRec->notificationObject != NULL) {
  1788. WTBLOBJ_RemoveWaitableObject(
  1789. UMRDPPRN_WaitableObjMgr,
  1790. notifyRec->notificationObject
  1791. );
  1792. FindClosePrinterChangeNotification(
  1793. notifyRec->notificationObject
  1794. );
  1795. }
  1796. if (notifyRec->printerHandle != NULL) {
  1797. ClosePrinter(notifyRec->printerHandle);
  1798. }
  1799. FREEMEM(notifyRec);
  1800. }
  1801. }
  1802. DBGMSG(DBG_TRACE, ("UMRDPPRN:RegisterPrinterConfigChangeNotification done.\n"));
  1803. return result;
  1804. }
  1805. BOOL
  1806. SendAddPrinterMsgToClient(
  1807. IN PCWSTR printerName,
  1808. IN PCWSTR driverName,
  1809. IN PCSTR dosDevicePort
  1810. )
  1811. /*++
  1812. Routine Description:
  1813. Send an add printer message to the client.
  1814. Arguments:
  1815. printerName - Name of new printer.
  1816. driverName - Name of printer driver.
  1817. portName - Client-side dos device port name.
  1818. Return Value:
  1819. Return TRUE on success. FALSE, otherwise.
  1820. --*/
  1821. {
  1822. PRDPDR_PRINTER_CACHEDATA_PACKET cachedDataPacket;
  1823. DWORD cachedDataPacketSize;
  1824. PRDPDR_PRINTER_ADD_CACHEDATA cachedData;
  1825. BOOL result;
  1826. DWORD driverSz, printerSz;
  1827. PWSTR str;
  1828. DBGMSG(DBG_TRACE, ("UMRDPPRN:SendAddPrinterMsgToClient.\n"));
  1829. DBGMSG(DBG_TRACE, ("UMRDPPRN:SendAddPrinterMsgToClient printer name is %ws.\n",
  1830. printerName));
  1831. DBGMSG(DBG_TRACE, ("UMRDPPRN:SendAddPrinterMsgToClient driver name is %ws.\n",
  1832. driverName));
  1833. DBGMSG(DBG_TRACE, ("UMRDPPRN:SendAddPrinterMsgToClient dos device port is %s.\n",
  1834. dosDevicePort));
  1835. //
  1836. // Calculate the message size.
  1837. //
  1838. driverSz = ((wcslen(driverName) + 1) * sizeof(WCHAR));
  1839. printerSz = ((wcslen(printerName) + 1) * sizeof(WCHAR));
  1840. cachedDataPacketSize = sizeof(RDPDR_PRINTER_CACHEDATA_PACKET) +
  1841. sizeof(RDPDR_PRINTER_ADD_CACHEDATA) +
  1842. driverSz + printerSz;
  1843. //
  1844. // Allocate the message.
  1845. //
  1846. cachedDataPacket = (PRDPDR_PRINTER_CACHEDATA_PACKET)ALLOCMEM(
  1847. cachedDataPacketSize
  1848. );
  1849. result = (cachedDataPacket != NULL);
  1850. if (result) {
  1851. //
  1852. // Set up the packet.
  1853. //
  1854. cachedDataPacket->Header.PacketId = DR_PRN_CACHE_DATA;
  1855. cachedDataPacket->Header.Component = RDPDR_CTYP_PRN;
  1856. cachedDataPacket->EventId = RDPDR_ADD_PRINTER_EVENT;
  1857. //
  1858. // Set up the cached data.
  1859. //
  1860. cachedData = (PRDPDR_PRINTER_ADD_CACHEDATA)(
  1861. (PBYTE)cachedDataPacket +
  1862. sizeof(RDPDR_PRINTER_CACHEDATA_PACKET)
  1863. );
  1864. strcpy(cachedData->PortDosName, dosDevicePort);
  1865. cachedData->PnPNameLen = 0;
  1866. cachedData->DriverLen = driverSz;
  1867. cachedData->PrinterNameLen = printerSz;
  1868. cachedData->CachedFieldsLen = 0;
  1869. //
  1870. // Add the driver name.
  1871. //
  1872. str = (PWSTR)((PBYTE)cachedData + sizeof(RDPDR_PRINTER_ADD_CACHEDATA));
  1873. wcscpy(str, driverName);
  1874. //
  1875. // Add the printer name.
  1876. //
  1877. str = str + driverSz/2;
  1878. wcscpy(str, printerName);
  1879. //
  1880. // Send the message to the client.
  1881. //
  1882. result = UMRDPDR_SendMessageToClient(
  1883. cachedDataPacket,
  1884. cachedDataPacketSize
  1885. );
  1886. // Release the buffer.
  1887. FREEMEM(cachedDataPacket);
  1888. }
  1889. return result;
  1890. }
  1891. BOOL
  1892. SendDeletePrinterMsgToClient(
  1893. IN PCWSTR printerName
  1894. )
  1895. /*++
  1896. Routine Description:
  1897. Send a delete printer message to the client.
  1898. Arguments:
  1899. printerName - Client-recognized name of printer to delete.
  1900. Return Value:
  1901. Return TRUE on success. FALSE, otherwise.
  1902. --*/
  1903. {
  1904. PRDPDR_PRINTER_CACHEDATA_PACKET cachedDataPacket;
  1905. DWORD cachedDataPacketSize;
  1906. PRDPDR_PRINTER_DELETE_CACHEDATA cachedData;
  1907. BOOL result;
  1908. DWORD printerSz;
  1909. PWSTR str;
  1910. DBGMSG(DBG_TRACE, ("UMRDPPRN:SendDeletePrinterMsgToClient printer name is %ws.\n",
  1911. printerName));
  1912. //
  1913. // Calculate the message size.
  1914. //
  1915. printerSz = ((wcslen(printerName) + 1) * sizeof(WCHAR));
  1916. cachedDataPacketSize = sizeof(RDPDR_PRINTER_CACHEDATA_PACKET) +
  1917. sizeof(RDPDR_PRINTER_DELETE_CACHEDATA) +
  1918. printerSz;
  1919. //
  1920. // Allocate the message.
  1921. //
  1922. cachedDataPacket = (PRDPDR_PRINTER_CACHEDATA_PACKET)ALLOCMEM(
  1923. cachedDataPacketSize
  1924. );
  1925. result = (cachedDataPacket != NULL);
  1926. if (result) {
  1927. //
  1928. // Set up the packet.
  1929. //
  1930. cachedDataPacket->Header.PacketId = DR_PRN_CACHE_DATA;
  1931. cachedDataPacket->Header.Component = RDPDR_CTYP_PRN;
  1932. cachedDataPacket->EventId = RDPDR_DELETE_PRINTER_EVENT;
  1933. //
  1934. // Set up the cached data.
  1935. //
  1936. cachedData = (PRDPDR_PRINTER_DELETE_CACHEDATA)(
  1937. (PBYTE)cachedDataPacket +
  1938. sizeof(RDPDR_PRINTER_CACHEDATA_PACKET)
  1939. );
  1940. cachedData->PrinterNameLen = printerSz;
  1941. //
  1942. // Add the printer name.
  1943. //
  1944. str = (PWSTR)((PBYTE)cachedData + sizeof(RDPDR_PRINTER_DELETE_CACHEDATA));
  1945. wcscpy(str, printerName);
  1946. //
  1947. // Send the message to the client.
  1948. //
  1949. result = UMRDPDR_SendMessageToClient(
  1950. cachedDataPacket,
  1951. cachedDataPacketSize
  1952. );
  1953. // Release the buffer.
  1954. FREEMEM(cachedDataPacket);
  1955. }
  1956. return result;
  1957. }
  1958. BOOL
  1959. RegisterSerialPort(
  1960. IN PCWSTR portName,
  1961. IN PCWSTR devicePath
  1962. )
  1963. /*++
  1964. Routine Description:
  1965. Register a serial port device by creating the symbolic link
  1966. Arguments:
  1967. portName - Port name for the serial device
  1968. devicePath - NT device path for the symbolic link
  1969. Return Value:
  1970. Return TRUE on success. FALSE, otherwise.
  1971. --*/
  1972. {
  1973. DWORD SymLinkNameLen;
  1974. size_t RemainingCharCount;
  1975. PWSTR pNtSymLinkName, buffer;
  1976. UNICODE_STRING SymLinkName, SymLinkValue;
  1977. HANDLE SymLinkHandle;
  1978. OBJECT_ATTRIBUTES ObjectAttributes;
  1979. NTSTATUS Status;
  1980. ULONG dwErrorCode, LUIDDeviceMapsEnabled;
  1981. BOOL fImpersonated = FALSE, fLUIDDeviceMapsEnabled;
  1982. BOOL result = TRUE;
  1983. DBGMSG(DBG_TRACE, ("UMRDPPRN:RegisterSerialPort with port %ws.\n", portName));
  1984. DBGMSG(DBG_TRACE,
  1985. ("UMRDPPRN:RegisterSerialPort with device path %ws.\n", devicePath));
  1986. buffer = NULL;
  1987. //
  1988. // Check if LUID DosDevices maps are enabled
  1989. //
  1990. Status = NtQueryInformationProcess( NtCurrentProcess(),
  1991. ProcessLUIDDeviceMapsEnabled,
  1992. &LUIDDeviceMapsEnabled,
  1993. sizeof(LUIDDeviceMapsEnabled),
  1994. NULL
  1995. );
  1996. if (NT_SUCCESS(Status)) {
  1997. fLUIDDeviceMapsEnabled = (LUIDDeviceMapsEnabled != 0);
  1998. }
  1999. else {
  2000. fLUIDDeviceMapsEnabled = FALSE;
  2001. }
  2002. //
  2003. // If LUID Device Maps are enabled,
  2004. // We need to impersonate the logged on user in order to create
  2005. // the symbolic links in the correct device map
  2006. // If LUID Device Maps are disabled,
  2007. // we should not impersonate the logged on user in order to delete
  2008. // any existing symbolic links
  2009. //
  2010. if (fLUIDDeviceMapsEnabled == TRUE) {
  2011. fImpersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser);
  2012. if (!fImpersonated) {
  2013. DBGMSG(DBG_ERROR,
  2014. ("UMRDPPRN:Error impersonate user in function RegisterSerialPort. Error: %ld\n",
  2015. GetLastError()));
  2016. return FALSE;
  2017. }
  2018. }
  2019. // length of ( portName ) + Length of("\\??\\") + UNICODE NULL
  2020. RemainingCharCount = wcslen(portName) + DEVICE_MAP_NAME_COUNT + 1;
  2021. SymLinkNameLen = RemainingCharCount * sizeof( WCHAR );
  2022. pNtSymLinkName = (PWSTR) ALLOCMEM( SymLinkNameLen );
  2023. if (pNtSymLinkName == NULL) {
  2024. DBGMSG(DBG_ERROR,
  2025. ("UMRDPPRN:Error allocating memory in function RegisterSerialPort. Error: %ld\n",
  2026. GetLastError()));
  2027. return( FALSE );
  2028. }
  2029. //
  2030. // Copy \??\ to the symbolic link name
  2031. //
  2032. wcsncpy( pNtSymLinkName, DEVICE_MAP_NAME, RemainingCharCount );
  2033. RemainingCharCount = RemainingCharCount - DEVICE_MAP_NAME_COUNT;
  2034. //
  2035. // Append the portname to the symbolic link name
  2036. //
  2037. wcsncat( pNtSymLinkName, portName, RemainingCharCount );
  2038. RtlInitUnicodeString(&SymLinkName, (PCWSTR)pNtSymLinkName);
  2039. RtlInitUnicodeString(&SymLinkValue, devicePath);
  2040. InitializeObjectAttributes( &ObjectAttributes,
  2041. &SymLinkName,
  2042. OBJ_CASE_INSENSITIVE,
  2043. NULL,
  2044. NULL );
  2045. Status = NtCreateSymbolicLinkObject( &SymLinkHandle,
  2046. SYMBOLIC_LINK_ALL_ACCESS,
  2047. &ObjectAttributes,
  2048. &SymLinkValue
  2049. );
  2050. //
  2051. // If LUID device maps are disabled, then CsrPopulateDosDevices() would
  2052. // have copied the global symbolic link into this TS device map, which
  2053. // would cause the create to fail, so we need to delete the copy before
  2054. // creating our symbolic link
  2055. //
  2056. if (Status == STATUS_OBJECT_NAME_COLLISION) {
  2057. Status = NtOpenSymbolicLinkObject( &SymLinkHandle,
  2058. SYMBOLIC_LINK_QUERY | DELETE,
  2059. &ObjectAttributes
  2060. );
  2061. if (NT_SUCCESS ( Status)) {
  2062. UNICODE_STRING SymLinkString;
  2063. unsigned SymLinkValueLen, ReturnedLength, bufLen;
  2064. SymLinkValueLen = wcslen(devicePath);
  2065. // Find how much buffer is required for the symlink value
  2066. SymLinkString.Buffer = NULL;
  2067. SymLinkString.Length = 0;
  2068. SymLinkString.MaximumLength = 0;
  2069. ReturnedLength = 0;
  2070. Status = NtQuerySymbolicLinkObject( SymLinkHandle,
  2071. &SymLinkString,
  2072. &ReturnedLength
  2073. );
  2074. if (Status != STATUS_BUFFER_TOO_SMALL) {
  2075. ReturnedLength = 0;
  2076. }
  2077. bufLen = SymLinkValueLen * sizeof(WCHAR) + sizeof(UNICODE_NULL) * 2 + ReturnedLength;
  2078. buffer = (PWSTR) ALLOCMEM( bufLen );
  2079. if (buffer == NULL) {
  2080. NtClose(SymLinkHandle);
  2081. DBGMSG(DBG_ERROR,
  2082. ("UMRDPPRN:Error allocating memory in function RegisterSerialPort. Error: %ld\n",
  2083. GetLastError()));
  2084. return( FALSE );
  2085. }
  2086. // Setup the devicepath as the first entry
  2087. wcscpy(buffer, devicePath);
  2088. buffer[SymLinkValueLen] = UNICODE_NULL;
  2089. if (ReturnedLength > 0) {
  2090. // Get the existing symlink
  2091. SymLinkString.Buffer = buffer + SymLinkValueLen + 1;
  2092. SymLinkString.Buffer[0] = UNICODE_NULL;
  2093. SymLinkString.MaximumLength = (USHORT)(bufLen - (SymLinkValueLen + 1) * sizeof(WCHAR));
  2094. SymLinkString.Length = 0;
  2095. ReturnedLength = 0;
  2096. Status = NtQuerySymbolicLinkObject( SymLinkHandle,
  2097. &SymLinkString,
  2098. &ReturnedLength
  2099. );
  2100. if (Status == STATUS_SUCCESS) {
  2101. if (ReturnedLength > 2 && (SymLinkString.Buffer[ReturnedLength/sizeof(WCHAR) - 2] != UNICODE_NULL) ) {
  2102. // Make sure we always end with an UNICODE_NULL
  2103. SymLinkString.Buffer[ReturnedLength/sizeof(WCHAR)] = UNICODE_NULL;
  2104. ReturnedLength += sizeof(UNICODE_NULL);
  2105. }
  2106. }
  2107. else {
  2108. ReturnedLength = 0;
  2109. }
  2110. }
  2111. // Setup the symlink string
  2112. SymLinkString.Buffer = buffer;
  2113. SymLinkString.Length = (USHORT)(SymLinkValueLen * sizeof(WCHAR));
  2114. SymLinkString.MaximumLength = (USHORT)((SymLinkValueLen + 1) * sizeof(WCHAR) + ReturnedLength);
  2115. Status = NtMakeTemporaryObject( SymLinkHandle );
  2116. NtClose( SymLinkHandle );
  2117. SymLinkHandle = NULL;
  2118. if (NT_SUCCESS ( Status)) {
  2119. Status = NtCreateSymbolicLinkObject( &SymLinkHandle,
  2120. SYMBOLIC_LINK_ALL_ACCESS,
  2121. &ObjectAttributes,
  2122. &SymLinkString
  2123. );
  2124. }
  2125. }
  2126. }
  2127. // Revert the thread token to self
  2128. if (fImpersonated) {
  2129. RevertToSelf();
  2130. }
  2131. //
  2132. // After the revert to Local System
  2133. //
  2134. if (NT_SUCCESS(Status)) {
  2135. Status = NtMakePermanentObject( SymLinkHandle ); // must be Local System
  2136. NtClose ( SymLinkHandle );
  2137. }
  2138. if (NT_SUCCESS(Status)) {
  2139. result = TRUE;
  2140. DBGMSG(DBG_TRACE, ("UMRDPPRN:RegisterSerialPort with port %ws succeeded.\n", portName));
  2141. }
  2142. else {
  2143. dwErrorCode = RtlNtStatusToDosError( Status );
  2144. SetLastError( dwErrorCode );
  2145. result = FALSE;
  2146. DBGMSG(DBG_ERROR, ("UMRDPPRN:RegisterSerialPort with port %ws failed: %x.\n",
  2147. portName, GetLastError()));
  2148. }
  2149. //
  2150. // Cleanup the memory that we allocated
  2151. //
  2152. if (pNtSymLinkName != NULL) {
  2153. FREEMEM(pNtSymLinkName);
  2154. }
  2155. if (buffer != NULL) {
  2156. FREEMEM(buffer);
  2157. }
  2158. return result;
  2159. }
  2160. BOOL
  2161. UMRDPPRN_HandlePrintPortAnnounceEvent(
  2162. IN PRDPDR_PORTDEVICE_SUB pPortAnnounce
  2163. )
  2164. /*++
  2165. Routine Description:
  2166. Handle a printer port device announce event from the "dr" by
  2167. adding a record for the device to the list of installed devices.
  2168. Arguments:
  2169. pPortAnnounce - Port device announce event.
  2170. Return Value:
  2171. Return TRUE on success. FALSE, otherwise.
  2172. --*/
  2173. {
  2174. DBGMSG(DBG_TRACE, ("UMRDPPRN:UMRDPPRN_HandlePrintPortAnnounceEvent with port %ws.\n",
  2175. pPortAnnounce->portName));
  2176. DBGMSG(DBG_TRACE, ("UMRDPPDRN:Preferred DOS name is %s.\n",
  2177. pPortAnnounce->deviceFields.PreferredDosName));
  2178. ASSERT( ISPRINTPORT(pPortAnnounce->deviceFields.DeviceType) );
  2179. if (pPortAnnounce->deviceFields.DeviceType == RDPDR_DTYP_SERIAL ||
  2180. pPortAnnounce->deviceFields.DeviceType == RDPDR_DTYP_PARALLEL) {
  2181. WCHAR serverDevicePath[MAX_PATH];
  2182. // Query the original symbolic link for the serial port and save it for restore
  2183. // later
  2184. serverDevicePath[0] = L'\0';
  2185. if (QueryDosDevice(pPortAnnounce->portName, serverDevicePath, MAX_PATH) != 0) {
  2186. DBGMSG(DBG_TRACE, ("UMRDPPRN:QueryDosDevice on port: %ws, returns path: %ws.\n",
  2187. pPortAnnounce->portName, serverDevicePath));
  2188. }
  2189. else {
  2190. DBGMSG(DBG_ERROR, ("UMRDPPRN:QueryDosDevice on port: %ws returns error: %x.\n",
  2191. pPortAnnounce->portName, GetLastError()));
  2192. }
  2193. // Register the new symbolic link name
  2194. RegisterSerialPort(pPortAnnounce->portName, pPortAnnounce->devicePath);
  2195. // Just record the port so we can remember it for later.
  2196. // We save the new serial symbolic link name in client device name and
  2197. // the original symbolic link in server device name
  2198. return DRDEVLST_Add(
  2199. DeviceList,
  2200. pPortAnnounce->deviceFields.DeviceId,
  2201. UMRDPDR_INVALIDSERVERDEVICEID,
  2202. pPortAnnounce->deviceFields.DeviceType,
  2203. serverDevicePath,
  2204. pPortAnnounce->devicePath,
  2205. pPortAnnounce->deviceFields.PreferredDosName
  2206. );
  2207. }
  2208. else {
  2209. if (!PrintingModuleInitialized) {
  2210. return FALSE;
  2211. }
  2212. // Just record the port so we can remember it for later.
  2213. return DRDEVLST_Add(
  2214. DeviceList,
  2215. pPortAnnounce->deviceFields.DeviceId,
  2216. UMRDPDR_INVALIDSERVERDEVICEID,
  2217. pPortAnnounce->deviceFields.DeviceType,
  2218. pPortAnnounce->portName,
  2219. pPortAnnounce->portName,
  2220. pPortAnnounce->deviceFields.PreferredDosName
  2221. );
  2222. }
  2223. }
  2224. BOOL
  2225. UMRDPPRN_DeleteSerialLink(
  2226. UCHAR *preferredDosName,
  2227. WCHAR *ServerDeviceName,
  2228. WCHAR *ClientDeviceName
  2229. )
  2230. /*++
  2231. Routine Description:
  2232. Delete the new symbolic link on disconnect/logoff and restore the old one
  2233. as necessary
  2234. Arguments:
  2235. preferredDosName - the port name in ANSI char
  2236. ServerDeviceName - the original serial link symbolic path
  2237. ClientDeviceName - the new serial link symbolic path
  2238. Return Value:
  2239. Return TRUE on success. FALSE, otherwise.
  2240. --*/
  2241. {
  2242. ULONG LUIDDeviceMapsEnabled;
  2243. BOOL fImpersonated = FALSE, fLUIDDeviceMapsEnabled;
  2244. WCHAR PortNameBuff[PREFERRED_DOS_NAME_SIZE];
  2245. NTSTATUS Status;
  2246. DBGMSG(DBG_TRACE, ("UMRDPPRN:UMRDPPRN_DeleteSerialLink\n"));
  2247. // Assemble the port name from preferred dos name
  2248. PortNameBuff[0] = L'\0';
  2249. MultiByteToWideChar(CP_ACP, 0, preferredDosName, -1, PortNameBuff, PREFERRED_DOS_NAME_SIZE);
  2250. //
  2251. // Check if LUID DosDevices maps are enabled
  2252. //
  2253. Status = NtQueryInformationProcess( NtCurrentProcess(),
  2254. ProcessLUIDDeviceMapsEnabled,
  2255. &LUIDDeviceMapsEnabled,
  2256. sizeof(LUIDDeviceMapsEnabled),
  2257. NULL
  2258. );
  2259. if (NT_SUCCESS(Status)) {
  2260. fLUIDDeviceMapsEnabled = (LUIDDeviceMapsEnabled != 0);
  2261. }
  2262. else {
  2263. fLUIDDeviceMapsEnabled = FALSE;
  2264. }
  2265. //
  2266. // If LUID Device Maps are enabled,
  2267. // We need to impersonate the logged on user in order to delete
  2268. // the symbolic links from the correct device map
  2269. // If LUID Device Maps are disabled,
  2270. // we should not impersonate the logged on user in order to delete
  2271. // any existing symbolic links
  2272. //
  2273. if (fLUIDDeviceMapsEnabled == TRUE) {
  2274. fImpersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser);
  2275. if (!fImpersonated) {
  2276. DBGMSG(DBG_ERROR,
  2277. ("UMRDPPRN:Error impersonate user in function UMRDPPRN_DeleteSerialLink. Error: %ld\n",
  2278. GetLastError()));
  2279. return FALSE;
  2280. }
  2281. }
  2282. if (PortNameBuff[0] != L'\0') {
  2283. // Just need to delete the new symbolic link for this session
  2284. if (DefineDosDevice(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
  2285. PortNameBuff,
  2286. ClientDeviceName) != 0) {
  2287. DBGMSG(DBG_TRACE, ("UMRDPPRN:Delete port %ws with link %ws succeeded.\n",
  2288. PortNameBuff, ClientDeviceName));
  2289. }
  2290. else {
  2291. DBGMSG(DBG_ERROR, ("UMRDPPRN:Delete port: %ws with link %ws failed: %x\n",
  2292. PortNameBuff, ClientDeviceName, GetLastError()));
  2293. }
  2294. }
  2295. else {
  2296. DBGMSG(DBG_ERROR, ("UMRDPPRN:UMRDPPRN_DeleteSerialLink failed to get the port name\n"));
  2297. }
  2298. // Delete the serial registry entry if on PTS box
  2299. if (fRunningOnPTS) {
  2300. DWORD rc;
  2301. HKEY regKey;
  2302. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TSSERIALDEVICEMAP, 0,
  2303. KEY_ALL_ACCESS, &regKey);
  2304. if (rc == ERROR_SUCCESS) {
  2305. RegDeleteValue(regKey, PortNameBuff);
  2306. RegCloseKey(regKey);
  2307. }
  2308. }
  2309. // Revert the thread token to self
  2310. if (fImpersonated) {
  2311. RevertToSelf();
  2312. }
  2313. return TRUE;
  2314. }
  2315. WCHAR *ANSIToUnicode(
  2316. IN LPCSTR ansiString,
  2317. IN UINT codePage
  2318. )
  2319. /*++
  2320. Routine Description:
  2321. Convert an ANSI string to Unicode.
  2322. Arguments:
  2323. Return Value:
  2324. Returns the converted string or NULL on error.. It is up to the caller to
  2325. release this string.
  2326. --*/
  2327. {
  2328. int numChars;
  2329. PWSTR buf=NULL;
  2330. //
  2331. // Convert the driver name.
  2332. //
  2333. // First, get the required buffer size.
  2334. numChars = MultiByteToWideChar(
  2335. codePage, 0, ansiString,
  2336. -1, NULL, 0
  2337. );
  2338. // Allocate the buffer.
  2339. buf = (PWSTR)ALLOCMEM((numChars + 1) * sizeof(WCHAR));
  2340. if (buf != NULL) {
  2341. buf[0] = L'\0';
  2342. numChars = MultiByteToWideChar(
  2343. codePage, 0, ansiString,
  2344. -1, buf, numChars
  2345. );
  2346. // Find out if the conversion succeeded.
  2347. if ((numChars != 0) || !ansiString[0]) {
  2348. return buf;
  2349. }
  2350. else {
  2351. DBGMSG(DBG_ERROR,
  2352. ("UMRDPPRN:Error converting to Unicode. Error: %ld\n",
  2353. GetLastError()));
  2354. FREEMEM(buf);
  2355. return NULL;
  2356. }
  2357. }
  2358. else {
  2359. DBGMSG(DBG_ERROR,
  2360. ("UMRDPPRN:Error allocating memory in function AnsiToUNICODE. Error: %ld\n",
  2361. GetLastError()));
  2362. return NULL;
  2363. }
  2364. }
  2365. DWORD
  2366. InstallPrinter(
  2367. IN PCWSTR portName,
  2368. IN PCWSTR driverName,
  2369. IN PWSTR printerNameBuf,
  2370. IN DWORD cchPrintNameBuf,
  2371. IN BOOL cachedDataExists,
  2372. OUT BOOL *triggerConfigChangeEvent
  2373. )
  2374. /*++
  2375. --*/
  2376. {
  2377. INT_PTR status = ERROR_SUCCESS; // PnpInterfaceFunc() returns INT_PTR
  2378. TAdvInfInstall tii;
  2379. TParameterBlock tpb;
  2380. PSECURITY_DESCRIPTOR psd;
  2381. PSID pSid = NULL;
  2382. BOOL daclPresent;
  2383. PACL dacl;
  2384. BOOL daclDefaulted;
  2385. DBGMSG(DBG_WARN,
  2386. ("UMRDPPRN:InstallPrinter portName %ws, driverName %ws, printerName %ws\n",
  2387. portName, driverName, printerNameBuf));
  2388. *triggerConfigChangeEvent = FALSE;
  2389. //
  2390. // Get the user sid.
  2391. //
  2392. if ((pSid = TSNUTL_GetUserSid(UMRPDPPRN_TokenForLoggedOnUser)) == NULL) {
  2393. status = GetLastError();
  2394. DBGMSG(DBG_ERROR, ("UMRDPPRN: Failed to get user SID: %ld\n",
  2395. status));
  2396. goto CLEANUPANDEXIT;
  2397. }
  2398. //
  2399. // Get the default printer security descriptor.
  2400. //
  2401. psd = RDPDRUTL_CreateDefaultPrinterSecuritySD(pSid);
  2402. if (psd == NULL) {
  2403. status = GetLastError();
  2404. goto CLEANUPANDEXIT;
  2405. }
  2406. tii.cbSize = sizeof(tii);
  2407. tii.pszModelName = driverName;
  2408. tii.pszServerName = NULL;
  2409. tii.pszInfName = PrinterInfPath;
  2410. tii.pszPortName = portName;
  2411. tii.pszPrinterNameBuffer = printerNameBuf;
  2412. tii.cchPrinterName = cchPrintNameBuf;
  2413. tii.pszSourcePath = NULL;
  2414. tii.dwFlags = kPnPInterface_Quiet |
  2415. kPnPInterface_NoShare |
  2416. kPnpInterface_UseExisting |
  2417. kPnpInterface_HydraSpecific;
  2418. tii.dwAttributes = PRINTER_ATTRIBUTE_TS;
  2419. tii.pSecurityDescriptor = psd;
  2420. //
  2421. // If cached data does not exist, then OR in the flag that
  2422. // enables printui to set a default ICM color profile, for
  2423. // color printers. Note that there is no additional overhead
  2424. // for non-color printers.
  2425. //
  2426. if (!cachedDataExists) {
  2427. tii.dwFlags |= kPnPInterface_InstallColorProfiles;
  2428. }
  2429. memset(&tpb, 0, sizeof(tpb));
  2430. tpb.pAdvInfInstall = &tii;
  2431. status = PnpInterfaceFunc(kAdvInfInstall, &tpb);
  2432. //
  2433. // The configuration info needs to be cached on the client if
  2434. // the printer is color and we didn't have any cached data to begin
  2435. // with. This is a performance optimization so we don't need to
  2436. // create a color profile for the remote printer each time we log in.
  2437. //
  2438. if (status == ERROR_SUCCESS) {
  2439. *triggerConfigChangeEvent = !cachedDataExists &&
  2440. (tii.dwOutFlags & kAdvInf_ColorPrinter);
  2441. }
  2442. //
  2443. // Release the Security Descriptor.
  2444. //
  2445. LocalFree(psd);
  2446. CLEANUPANDEXIT:
  2447. if (pSid != NULL) FREEMEM(pSid);
  2448. DBGMSG(DBG_WARN,("UMRDPPRN:InstallPrinter returns %ld\n", status));
  2449. return (DWORD)status;
  2450. }
  2451. VOID
  2452. TriggerConfigChangeTimer()
  2453. /*++
  2454. Routine Description:
  2455. Set the config change timer callback to fire 1 time.
  2456. Arguments:
  2457. Return Value:
  2458. --*/
  2459. {
  2460. LARGE_INTEGER li;
  2461. if (g_fTimerSet == FALSE) {
  2462. li.QuadPart = Int32x32To64(CONFIG_WAIT_PERIOD, -10000); // 30 seconds (in nano second units)
  2463. if (SetWaitableTimer(WaitableTimer,
  2464. &li,
  2465. 0,
  2466. NULL,
  2467. NULL,
  2468. FALSE)) {
  2469. g_fTimerSet = TRUE;
  2470. }
  2471. else {
  2472. DBGMSG(DBG_TRACE, ("UMRDPPRN:SetWaitableTimer Failed. Error: %ld.\n", GetLastError()));
  2473. }
  2474. }
  2475. }
  2476. BOOL
  2477. InstallPrinterWithPortName(
  2478. IN DWORD deviceID,
  2479. IN HANDLE hTokenForLoggedOnUser,
  2480. IN BOOL bSetDefault,
  2481. IN ULONG ulFlags,
  2482. IN PCWSTR portName,
  2483. IN PCWSTR driverName,
  2484. IN PCWSTR printerName,
  2485. IN PCWSTR clientComputerName,
  2486. IN PBYTE cacheData,
  2487. IN DWORD cacheDataLen
  2488. )
  2489. /*++
  2490. Routine Description:
  2491. Install the printing device.
  2492. Arguments:
  2493. deviceID - Device identifier assigned by kernel mode component and client.
  2494. hTokenForLoggedOnUser - Logged on user token.
  2495. portName - Name of printer port.
  2496. driverName - Printer driver name. (eg. AGFA-AccuSet v52.3)
  2497. printerName - Printer name. This function appends "/Session X/Computer Name"
  2498. clientComputerName - Name of client computer.
  2499. Return Value:
  2500. Return TRUE on success. FALSE, otherwise.
  2501. --*/
  2502. {
  2503. WCHAR printerNameBuf[MAX_PATH+1];
  2504. size_t printerNameLen;
  2505. DWORD status = ERROR_SUCCESS;
  2506. WCHAR errorBuf[256];
  2507. HANDLE hPrinter;
  2508. TS_PRINTER_NAMES printerNames;
  2509. PRINTER_DEFAULTS defaults = {NULL, NULL, PRINTER_ALL_ACCESS};
  2510. BOOL queueCreated = FALSE;
  2511. DWORD requiredSize;
  2512. BOOL clientDriverMapped;
  2513. WCHAR *parms[2];
  2514. BOOL triggerConfigChangeEvent;
  2515. DWORD ofs;
  2516. BOOL printerNameExists;
  2517. #if DBG
  2518. DWORD i;
  2519. #endif
  2520. DBGMSG(DBG_TRACE, ("UMRDPPRN:InstallPrinterWithPortName.\n"));
  2521. DBGMSG(DBG_TRACE, ("UMRDPPRN:Port name is %ws driver name is %ws\n", portName, driverName));
  2522. #ifndef UNICODE
  2523. ASSERT(0);
  2524. #endif
  2525. //
  2526. // format printer name
  2527. //
  2528. printerNames.ulTempLen = sizeof(printerNames.szTemp)/sizeof(printerNames.szTemp[0]);
  2529. printerNames.pszFullName = printerName;
  2530. printerNames.pszCurrentClient = clientComputerName;
  2531. printerNames.pszServer = NULL;
  2532. printerNames.pszClient = NULL;
  2533. printerNames.pszPrinter = NULL;
  2534. FormatPrinterName(printerNameBuf,
  2535. sizeof(printerNameBuf)/sizeof(printerNameBuf[0]),
  2536. ulFlags,
  2537. &printerNames);
  2538. printerNameLen = wcslen(printerNameBuf);
  2539. //
  2540. // Delete the printer if it already exists.
  2541. //
  2542. if (OpenPrinter(printerNameBuf, &hPrinter, &defaults)) {
  2543. DBGMSG(DBG_WARN,
  2544. ("UMRDPPRN:Deleting existing printer %ws in InstallPrinterWithPortName!\n",
  2545. printerNameBuf));
  2546. if (!SetPrinter(hPrinter, 0, NULL, PRINTER_CONTROL_PURGE) ||
  2547. !DeletePrinter(hPrinter)) {
  2548. DBGMSG(DBG_ERROR,
  2549. ("UMRDPPRN:Error deleting existing printer %ws: %08X!\n",
  2550. printerNameBuf,GetLastError()));
  2551. ClosePrinter(hPrinter);
  2552. return FALSE;
  2553. }
  2554. else {
  2555. ClosePrinter(hPrinter);
  2556. hPrinter = INVALID_HANDLE_VALUE;
  2557. }
  2558. }
  2559. else {
  2560. hPrinter = INVALID_HANDLE_VALUE;
  2561. }
  2562. //
  2563. // Return immediately if the DLL is trying to shut down. This
  2564. // is to help prevent us from getting stuck in a system call.
  2565. //
  2566. if (ShutdownFlag) {
  2567. status = ERROR_SHUTDOWN_IN_PROGRESS;
  2568. goto Cleanup;
  2569. }
  2570. //
  2571. // We want to check if driver already install first because
  2572. // if we simply dump installation of a nt4 or win9x driver
  2573. // to print UI, it will takes a long time for it to find out
  2574. // that driver does not exist, on other case, if a OEM driver
  2575. // already install, we also want to use it.
  2576. //
  2577. //
  2578. // MapClientPrintDriverName() will try out with upgrade infs file
  2579. // first, so if NT4/Win9x driver (not in ntprintf.inf), we will
  2580. // pick up mapping first.
  2581. //
  2582. status = PrinterDriverInstalled( driverName );
  2583. if( ERROR_SHUTDOWN_IN_PROGRESS == status ) {
  2584. goto Cleanup;
  2585. }
  2586. if( ERROR_SUCCESS == status ) {
  2587. //
  2588. // Driver already install. Try installing the printer. If this fails,
  2589. // driver must be blocked.
  2590. //
  2591. status = InstallPrinter(
  2592. portName,
  2593. driverName,
  2594. printerNameBuf,
  2595. sizeof(printerNameBuf) / sizeof(printerNameBuf[0]),
  2596. cacheDataLen > 0,
  2597. &triggerConfigChangeEvent
  2598. );
  2599. if( ERROR_SUCCESS == status ) {
  2600. queueCreated = TRUE;
  2601. }
  2602. if( ShutdownFlag ) {
  2603. // overwrite last error since we are shutting down
  2604. status = ERROR_SHUTDOWN_IN_PROGRESS;
  2605. goto Cleanup;
  2606. }
  2607. }
  2608. if( ERROR_SUCCESS != status ) {
  2609. //
  2610. // Driver not installed or failed to installed printer with
  2611. // driver already exist on system, go thru mapping process
  2612. //
  2613. clientDriverMapped = MapClientPrintDriverName(
  2614. driverName,
  2615. &MappedDriverNameBuf,
  2616. &MappedDriverNameBufSize
  2617. );
  2618. status = InstallPrinter(
  2619. portName,
  2620. (clientDriverMapped) ? MappedDriverNameBuf : driverName,
  2621. printerNameBuf,
  2622. sizeof(printerNameBuf) / sizeof(printerNameBuf[0]),
  2623. cacheDataLen > 0,
  2624. &triggerConfigChangeEvent
  2625. );
  2626. if( ERROR_SUCCESS == status ) {
  2627. queueCreated = TRUE;
  2628. }
  2629. }
  2630. if( ShutdownFlag ) {
  2631. // overwrite last error since we are shutting down
  2632. status = ERROR_SHUTDOWN_IN_PROGRESS;
  2633. goto Cleanup;
  2634. }
  2635. //
  2636. // Log an error message if the driver wasn't found
  2637. //
  2638. if (!queueCreated) {
  2639. ASSERT( status != ERROR_SUCCESS );
  2640. if ((status == ERROR_FILE_NOT_FOUND) || (status == ERROR_PATH_NOT_FOUND)) {
  2641. ASSERT((sizeof(parms)/sizeof(WCHAR *)) >= 2);
  2642. parms[0] = (WCHAR *)driverName;
  2643. parms[1] = (WCHAR *)printerName;
  2644. TsLogError(EVENT_NOTIFY_DRIVER_NOT_FOUND, EVENTLOG_ERROR_TYPE, 2,
  2645. parms, __LINE__);
  2646. }
  2647. else if (status == ERROR_UNKNOWN_PRINTER_DRIVER) {
  2648. ASSERT((sizeof(parms)/sizeof(WCHAR *)) >= 2);
  2649. parms[0] = (WCHAR *)driverName;
  2650. parms[1] = (WCHAR *)printerName;
  2651. TsLogError(EVENT_NOTIFY_UNKNOWN_PRINTER_DRIVER, EVENTLOG_ERROR_TYPE, 2,
  2652. parms, __LINE__);
  2653. }
  2654. DBGMSG(DBG_TRACE, ("UMRDPPRN:Printui func failed with status %08x.\n", status));
  2655. }
  2656. //
  2657. // Set the new printer as the default printer, after saving the
  2658. // current printer context, if so configured.
  2659. //
  2660. if (ERROR_SUCCESS == status && UMRDPDR_fSetClientPrinterDefault() && bSetDefault) {
  2661. DWORD statusSave = ERROR_SUCCESS;
  2662. BOOL fImpersonated = FALSE;
  2663. SaveDefaultPrinterContext(printerNameBuf);
  2664. //
  2665. //impersonate before setting the default printer as the api
  2666. //accesses hkcu. If the impersonation fails, the api will fail
  2667. //and we will log an error. But, before logging an error, we will
  2668. //need to revert to self.
  2669. //
  2670. if (!(fImpersonated = ImpersonateLoggedOnUser(hTokenForLoggedOnUser))) {
  2671. DBGMSG(DBG_TRACE, ("UMRDPDR:ImpersonateLoggedOnUser failed. Error:%ld.\n", GetLastError()));
  2672. }
  2673. if (!SetDefaultPrinter(printerNameBuf)) {
  2674. statusSave = GetLastError();
  2675. }
  2676. //
  2677. //if revert to self fails, consider it fatal
  2678. //
  2679. if (fImpersonated && !RevertToSelf()) {
  2680. status = GetLastError();
  2681. DBGMSG(DBG_TRACE, ("UMRDPDR:RevertToSelf failed. Error:%ld.\n", status));
  2682. goto Cleanup;
  2683. }
  2684. if (statusSave != ERROR_SUCCESS) {
  2685. WCHAR * param = printerNameBuf;
  2686. DBGMSG(DBG_ERROR, ("UMRDPPRN: SetDefaultPrinter failed. Error: %ld\n",
  2687. statusSave));
  2688. TsLogError(EVENT_NOTIFY_SETDEFAULTPRINTER_FAILED,
  2689. EVENTLOG_ERROR_TYPE,
  2690. 1,
  2691. &param,
  2692. __LINE__);
  2693. }
  2694. }
  2695. //
  2696. // Return immediately if the DLL is trying to shut down. This
  2697. // is to help prevent us from getting stuck in a system call.
  2698. //
  2699. if (ShutdownFlag) {
  2700. status = ERROR_SHUTDOWN_IN_PROGRESS;
  2701. goto Cleanup;
  2702. }
  2703. //
  2704. // Restore cached data for the new printer.
  2705. //
  2706. if (ERROR_SUCCESS == status && cacheDataLen) {
  2707. status = SetPrinterConfigInfo(
  2708. printerNameBuf,
  2709. cacheData,
  2710. cacheDataLen
  2711. );
  2712. if (status != ERROR_SUCCESS) {
  2713. WCHAR * param = printerNameBuf;
  2714. DBGMSG(DBG_TRACE, ("UMRDPPRN:SetPrinterConfigInfo failed: %ld.\n", status));
  2715. SetLastError(status);
  2716. TsLogError(EVENT_NOTIFY_RESTORE_PRINTER_CONFIG_FAILED,
  2717. EVENTLOG_WARNING_TYPE,
  2718. 1,
  2719. &param,
  2720. __LINE__);
  2721. //
  2722. // We will go ahead and leave the queue created, but assume the config
  2723. // settings are bad on the client and cause them to be overwritten with
  2724. // the default config settings.
  2725. //
  2726. status = ERROR_SUCCESS;
  2727. triggerConfigChangeEvent = TRUE;
  2728. }
  2729. }
  2730. //
  2731. // Return immediately if the DLL is trying to shut down. This
  2732. // is to help prevent us from getting stuck in a system call.
  2733. //
  2734. if (ShutdownFlag) {
  2735. status = ERROR_SHUTDOWN_IN_PROGRESS;
  2736. goto Cleanup;
  2737. }
  2738. //
  2739. // Open the printer to make some modifications
  2740. //
  2741. if (queueCreated && (status == ERROR_SUCCESS)) {
  2742. ASSERT(hPrinter == INVALID_HANDLE_VALUE);
  2743. DBGMSG(DBG_TRACE, ("UMRDPPRN:InstallPrinterWithPortName installing printer queue succeeded.\n"));
  2744. if( OpenPrinter(printerNameBuf, &hPrinter, &defaults) == FALSE ) {
  2745. hPrinter = INVALID_HANDLE_VALUE;
  2746. status = GetLastError();
  2747. DBGMSG(DBG_TRACE, ("UMRDPPRN:OpenPrinter() %ws failed with %ld.\n", printerNameBuf, status));
  2748. }
  2749. //
  2750. // Add the session number to the printer queue data.
  2751. //
  2752. if (ERROR_SUCCESS == status) {
  2753. status = AddSessionIDToPrinterQueue(hPrinter, GETTHESESSIONID());
  2754. if( ERROR_SUCCESS != status ) {
  2755. DBGMSG(DBG_ERROR,
  2756. ("UMRDPPRN:AddSessionIDToPrinterQueue failed for %ws.\n",
  2757. printerNameBuf)
  2758. );
  2759. }
  2760. }
  2761. //
  2762. // Add the different names to the printer queue data.
  2763. // They will be used if we need to redirect (again!) the printer.
  2764. //
  2765. if (ERROR_SUCCESS == status) {
  2766. status = AddNamesToPrinterQueue(hPrinter, &printerNames);
  2767. if (status != ERROR_SUCCESS) {
  2768. DBGMSG(DBG_ERROR,
  2769. ("UMRDPPRN:AddNamesToPrinterQueue failed for %ws with status %08x.\n",
  2770. printerNameBuf, status)
  2771. );
  2772. }
  2773. }
  2774. }
  2775. //
  2776. // Return immediately if the DLL is trying to shut down. This
  2777. // is to help prevent us from getting stuck in a system call.
  2778. //
  2779. if (ShutdownFlag) {
  2780. status = ERROR_SHUTDOWN_IN_PROGRESS;
  2781. goto Cleanup;
  2782. }
  2783. //
  2784. // Check to make sure the printer doesn't already exist in the device list
  2785. //
  2786. printerNameExists =
  2787. (DRDEVLST_FindByServerDeviceName(DeviceList, printerNameBuf,
  2788. &ofs)
  2789. && (DeviceList->devices[ofs].deviceType ==
  2790. RDPDR_DTYP_PRINT));
  2791. if (!printerNameExists) {
  2792. //
  2793. // Add the printer to the list of installed devices.
  2794. //
  2795. if (ERROR_SUCCESS == status) {
  2796. if( !DRDEVLST_Add(DeviceList, deviceID,
  2797. UMRDPDR_INVALIDSERVERDEVICEID,
  2798. RDPDR_DTYP_PRINT,
  2799. printerNameBuf,
  2800. printerName,
  2801. "UNKNOWN") ) {
  2802. // DRDEVLST_Add
  2803. status = ERROR_OUTOFMEMORY;
  2804. }
  2805. }
  2806. //
  2807. // Trigger a config change event if the install function
  2808. // indicated that we need to push config data out to the client.
  2809. //
  2810. if (triggerConfigChangeEvent && (status == ERROR_SUCCESS)) {
  2811. DRDEVLST_FindByClientDeviceID(DeviceList, deviceID, &ofs);
  2812. DeviceList->devices[ofs].fConfigInfoChanged = TRUE;
  2813. TriggerConfigChangeTimer();
  2814. }
  2815. }
  2816. Cleanup:
  2817. //
  2818. // Close the printer handle if it was left open.
  2819. //
  2820. if (hPrinter != INVALID_HANDLE_VALUE) {
  2821. ClosePrinter(hPrinter);
  2822. }
  2823. //
  2824. // Delete the queue on failure.
  2825. //
  2826. if (status != ERROR_SUCCESS && queueCreated) {
  2827. UMRDPPRN_DeleteNamedPrinterQueue(printerNameBuf);
  2828. }
  2829. SetLastError(status);
  2830. return (status == ERROR_SUCCESS);
  2831. }
  2832. DWORD
  2833. AddSessionIDToPrinterQueue(
  2834. IN HANDLE hPrinter,
  2835. IN DWORD sessionID
  2836. )
  2837. /*++
  2838. Routine Description:
  2839. Add the session ID to printer queue associated with the specified
  2840. handle.
  2841. Arguments:
  2842. hPrinter - Handle for printer returned by OpenPrinter.
  2843. sessionID - Session ID.
  2844. Return Value:
  2845. Returns ERROR_SUCCESS on success. Error code, otherwise.
  2846. --*/
  2847. {
  2848. DWORD result;
  2849. result = SetPrinterData(
  2850. hPrinter, DEVICERDR_SESSIONID, REG_DWORD,
  2851. (PBYTE)&sessionID, sizeof(sessionID)
  2852. );
  2853. if (result != ERROR_SUCCESS) {
  2854. DBGMSG(DBG_ERROR, ("UMRDPPRN:SetPrinterData failed with status %08x.\n", result));
  2855. }
  2856. return result;
  2857. }
  2858. DWORD
  2859. AddNamesToPrinterQueue(
  2860. IN HANDLE hPrinter,
  2861. IN PTS_PRINTER_NAMES pPrinterNames
  2862. )
  2863. /*++
  2864. Routine Description:
  2865. Add the Server\Client\Printer names to printer queue
  2866. associated with the specified handle.
  2867. Arguments:
  2868. hPrinter - Handle for printer returned by OpenPrinter.
  2869. pPrinterNames - struct conataining the names.
  2870. Return Value:
  2871. Returns ERROR_SUCCESS on success. Error code, otherwise.
  2872. --*/
  2873. {
  2874. DWORD result = ERROR_SUCCESS;
  2875. if(pPrinterNames->pszServer) {
  2876. result = SetPrinterData(
  2877. hPrinter, DEVICERDR_PRINT_SERVER_NAME, REG_SZ,
  2878. (PBYTE)pPrinterNames->pszServer, (wcslen(pPrinterNames->pszServer) + 1)*sizeof(WCHAR)
  2879. );
  2880. if (result != ERROR_SUCCESS) {
  2881. DBGMSG(DBG_ERROR, ("UMRDPPRN:SetPrinterData failed to set %ws with status %08x.\n",
  2882. pPrinterNames->pszServer, result));
  2883. }
  2884. }
  2885. if((result == ERROR_SUCCESS) && pPrinterNames->pszClient) {
  2886. result = SetPrinterData(
  2887. hPrinter, DEVICERDR_CLIENT_NAME, REG_SZ,
  2888. (PBYTE)pPrinterNames->pszClient, (wcslen(pPrinterNames->pszClient) + 1)*sizeof(WCHAR)
  2889. );
  2890. if (result != ERROR_SUCCESS) {
  2891. DBGMSG(DBG_ERROR, ("UMRDPPRN:SetPrinterData failed to set %ws with status %08x.\n",
  2892. pPrinterNames->pszClient, result));
  2893. }
  2894. }
  2895. if((result == ERROR_SUCCESS) && pPrinterNames->pszPrinter) {
  2896. result = SetPrinterData(
  2897. hPrinter, DEVICERDR_PRINTER_NAME, REG_SZ,
  2898. (PBYTE)pPrinterNames->pszPrinter, (wcslen(pPrinterNames->pszPrinter) + 1)*sizeof(WCHAR)
  2899. );
  2900. if (result != ERROR_SUCCESS) {
  2901. DBGMSG(DBG_ERROR, ("UMRDPPRN:SetPrinterData failed to set %ws with status %08x.\n",
  2902. pPrinterNames->pszPrinter, result));
  2903. }
  2904. }
  2905. return result;
  2906. }
  2907. BOOL
  2908. UMRDPPRN_DeleteNamedPrinterQueue(
  2909. IN PWSTR printerName
  2910. )
  2911. /*++
  2912. Routine Description:
  2913. Delete the named printer. This function does not remove the printer
  2914. from the comprehensive device management list.
  2915. Arguments:
  2916. printerName - Name of printer to delete.
  2917. Return Value:
  2918. Returns TRUE on success. FALSE, otherwise.
  2919. --*/
  2920. {
  2921. HANDLE hPrinter;
  2922. PRINTER_DEFAULTS defaults = {NULL, NULL, PRINTER_ALL_ACCESS};
  2923. DWORD ofs;
  2924. BOOL result;
  2925. WCHAR defaultPrinterNameBuffer[MAX_PATH+1];
  2926. DWORD bufSize = sizeof(defaultPrinterNameBuffer) / sizeof(defaultPrinterNameBuffer[0]);
  2927. BOOL fPrinterIsDefault;
  2928. BOOL fDefaultPrinterSet = FALSE;
  2929. BOOL fImpersonated = FALSE;
  2930. defaultPrinterNameBuffer[0] = L'\0';
  2931. if (!PrintingModuleInitialized) {
  2932. return FALSE;
  2933. }
  2934. //
  2935. // If the printer is one of the devices we are tracking, then
  2936. // we need to remove the notification object associated with the
  2937. // printer.
  2938. //
  2939. if (DRDEVLST_FindByServerDeviceName(DeviceList, printerName, &ofs) &&
  2940. (DeviceList->devices[ofs].deviceSpecificData != NULL)) {
  2941. PPRINTNOTIFYREC notifyRec = (PPRINTNOTIFYREC)
  2942. DeviceList->devices[ofs].deviceSpecificData;
  2943. ASSERT(notifyRec->notificationObject != NULL);
  2944. ASSERT(notifyRec->printerHandle != NULL);
  2945. WTBLOBJ_RemoveWaitableObject(
  2946. UMRDPPRN_WaitableObjMgr,
  2947. notifyRec->notificationObject
  2948. );
  2949. FindClosePrinterChangeNotification(
  2950. notifyRec->notificationObject
  2951. );
  2952. ClosePrinter(notifyRec->printerHandle);
  2953. FREEMEM(notifyRec);
  2954. DeviceList->devices[ofs].deviceSpecificData = NULL;
  2955. }
  2956. //
  2957. // Check to see if the printer we are deleting is a default printer
  2958. //
  2959. if (!(fImpersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser))) {
  2960. DBGMSG(DBG_TRACE, ("UMRDPDR:ImpersonateLoggedOnUser failed. Error:%ld.\n", GetLastError()));
  2961. }
  2962. fPrinterIsDefault = (GetDefaultPrinter(defaultPrinterNameBuffer, &bufSize) &&
  2963. (wcscmp(defaultPrinterNameBuffer, printerName) == 0));
  2964. DBGMSG(DBG_TRACE, ("UMRDPPRN:DeleteNamedPrinter deleting %ws.\n",
  2965. printerName));
  2966. if (fImpersonated&& !RevertToSelf()) {
  2967. DBGMSG(DBG_TRACE, ("UMRDPDR:RevertToSelf failed. Error:%ld.\n", GetLastError()));
  2968. }
  2969. //
  2970. // Open the printer.
  2971. //
  2972. result = OpenPrinter(printerName, &hPrinter, &defaults);
  2973. //
  2974. // Purge and delete the printer.
  2975. //
  2976. if (result) {
  2977. result = SetPrinter(hPrinter, 0, NULL, PRINTER_CONTROL_PURGE) &&
  2978. DeletePrinter(hPrinter);
  2979. }
  2980. else {
  2981. hPrinter = NULL;
  2982. }
  2983. //
  2984. // If the printer is the default, then restore the previously stored
  2985. // printer context.
  2986. //
  2987. if (fPrinterIsDefault) {
  2988. RestoreDefaultPrinterContext();
  2989. }
  2990. //
  2991. // Log an event on failure.
  2992. //
  2993. if (!result) {
  2994. WCHAR * param = printerName;
  2995. TsLogError(EVENT_NOTIFY_DELETE_PRINTER_FAILED,
  2996. EVENTLOG_ERROR_TYPE,
  2997. 1,
  2998. &param,
  2999. __LINE__);
  3000. DBGMSG(DBG_ERROR,
  3001. ("UMRDPPRN:Unable to delete redirected printer - %ws. Error: %ld\n",
  3002. printerName, GetLastError()));
  3003. }
  3004. else
  3005. {
  3006. DBGMSG(DBG_TRACE, ("UMRDPPRN:Printer successfully deleted.\n"));
  3007. }
  3008. //
  3009. // Close the printer if we successfully opened it.
  3010. //
  3011. if (hPrinter != NULL) {
  3012. ClosePrinter(hPrinter);
  3013. }
  3014. return result;
  3015. }
  3016. BOOL
  3017. SetDefaultPrinterToFirstFound(
  3018. BOOL impersonate
  3019. )
  3020. /*++
  3021. Routine Description:
  3022. Enumerate all printers visible to the user and try to set the
  3023. first one we "can" to default.
  3024. Arguments:
  3025. impersonate - TRUE if this function should impersonate the user
  3026. prior to setting the default printer.
  3027. Return Value:
  3028. Returns TRUE on success. FALSE, otherwise.
  3029. --*/
  3030. {
  3031. BOOL fSuccess = FALSE;
  3032. BOOL fImpersonated = FALSE;
  3033. PRINTER_INFO_4 * pPrinterInfo = NULL;
  3034. DWORD cbBuf = 0;
  3035. DWORD cReturnedStructs = 0;
  3036. DWORD i;
  3037. DBGMSG(DBG_TRACE, ("UMRDPDR:SetDefaultPrinterToFirstFound Entered.\n"));
  3038. if (impersonate) {
  3039. //
  3040. // Impersonate Client
  3041. //
  3042. if ((UMRPDPPRN_TokenForLoggedOnUser == INVALID_HANDLE_VALUE) ||
  3043. !(fImpersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser))) {
  3044. if (UMRPDPPRN_TokenForLoggedOnUser == INVALID_HANDLE_VALUE) {
  3045. DBGMSG(DBG_TRACE, ("UMRDPDR:UMRPDPPRN_TokenForLoggedOnUser is INVALID_HANDLE_VALUE.\n"));
  3046. }
  3047. else {
  3048. DBGMSG(DBG_TRACE, ("UMRDPDR:ImpersonateLoggedOnUser failed. Error:%ld.\n", GetLastError()));
  3049. }
  3050. goto Cleanup;
  3051. }
  3052. }
  3053. //
  3054. // Enumerate Printers
  3055. //
  3056. if (!EnumPrinters(
  3057. PRINTER_ENUM_LOCAL, // Flags
  3058. NULL, // Name
  3059. 4, // Print Info Type
  3060. (PBYTE)pPrinterInfo, // buffer
  3061. 0, // Size of buffer
  3062. &cbBuf, // Required
  3063. &cReturnedStructs)) {
  3064. if(GetLastError() != ERROR_INSUFFICIENT_BUFFER ) {
  3065. DBGMSG(DBG_ERROR, ("UMRDPPRN: EnumPrinters failed. Error: %ld.\n", GetLastError()));
  3066. goto Cleanup;
  3067. }
  3068. }
  3069. if (cbBuf == 0) {
  3070. goto Cleanup;
  3071. }
  3072. pPrinterInfo = (PRINTER_INFO_4 *)ALLOCMEM(cbBuf);
  3073. if (pPrinterInfo == NULL) {
  3074. DBGMSG(DBG_ERROR, ("UMRDPPRN: ALLOCMEM failed. Error: %ld.\n", GetLastError()));
  3075. goto Cleanup;
  3076. }
  3077. if (!EnumPrinters(
  3078. PRINTER_ENUM_LOCAL,
  3079. NULL,
  3080. 4,
  3081. (PBYTE)pPrinterInfo,
  3082. cbBuf,
  3083. &cbBuf,
  3084. &cReturnedStructs)) {
  3085. DBGMSG(DBG_ERROR, ("UMRDPPRN: EnumPrinters failed. Error: %ld.\n", GetLastError()));
  3086. goto Cleanup;
  3087. }
  3088. DBGMSG(DBG_TRACE, ("UMRDPPRN: Found %ld Local printers on Session %ld.\n",
  3089. cReturnedStructs, GETTHESESSIONID()));
  3090. if (fImpersonated) {
  3091. RevertToSelf();
  3092. fImpersonated = FALSE;
  3093. }
  3094. //
  3095. // Try to set one of the available printers as the default printer
  3096. //
  3097. for (i = 0; i < cReturnedStructs; i++) {
  3098. if (pPrinterInfo[i].pPrinterName) {
  3099. DWORD status = ERROR_SUCCESS;
  3100. DBGMSG(DBG_TRACE, ("UMRDPPRN: EnumPrinters - #%ld; Printer Name - %ws.\n",
  3101. i, pPrinterInfo[i].pPrinterName));
  3102. //
  3103. //impersonate before setting the default printer as the api
  3104. //accesses hkcu. If the impersonation fails, the api will fail
  3105. //and we will log an error. But, before logging an error, we will
  3106. //need to revert to self.
  3107. //
  3108. if (!(fImpersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser))) {
  3109. DBGMSG(DBG_TRACE, ("UMRDPDR:ImpersonateLoggedOnUser failed. Error:%ld.\n", GetLastError()));
  3110. }
  3111. if (!SetDefaultPrinter(pPrinterInfo[i].pPrinterName)) {
  3112. //
  3113. //save the last error
  3114. //
  3115. status = GetLastError();
  3116. }
  3117. //
  3118. //if revert to self fails, consider it fatal
  3119. //
  3120. if (fImpersonated && !RevertToSelf()) {
  3121. DBGMSG(DBG_TRACE, ("UMRDPDR:RevertToSelf failed. Error:%ld.\n", GetLastError()));
  3122. fSuccess = FALSE;
  3123. break;
  3124. }
  3125. fImpersonated = FALSE;
  3126. if (status == ERROR_SUCCESS) {
  3127. fSuccess = TRUE;
  3128. DBGMSG(DBG_TRACE, ("UMRDPPRN: The printer %ws was set as the Default Printer.\n",
  3129. pPrinterInfo[i].pPrinterName));
  3130. break;
  3131. }
  3132. else {
  3133. WCHAR * param = pPrinterInfo[i].pPrinterName;
  3134. DBGMSG(DBG_ERROR, ("UMRDPPRN: SetDefaultPrinter failed. Error: %ld\n",
  3135. status));
  3136. TsLogError(EVENT_NOTIFY_SETDEFAULTPRINTER_FAILED,
  3137. EVENTLOG_ERROR_TYPE,
  3138. 1,
  3139. &param,
  3140. __LINE__);
  3141. }
  3142. }
  3143. }
  3144. Cleanup:
  3145. if (fImpersonated) {
  3146. RevertToSelf();
  3147. }
  3148. if (pPrinterInfo != NULL) {
  3149. FREEMEM(pPrinterInfo);
  3150. }
  3151. DBGMSG(DBG_TRACE, ("UMRDPDR:SetDefaultPrinterToFirstFound Leaving. fSuccess is %d.\n", fSuccess));
  3152. return fSuccess;
  3153. }
  3154. BOOL
  3155. HandlePrinterConfigChangeNotification(
  3156. IN DWORD serverDeviceID
  3157. )
  3158. /*++
  3159. Routine Description:
  3160. Handle notification from the spooler that the config info of a printer has changed.
  3161. Arguments:
  3162. serverDeviceID - Server-assigned device ID associated with the printer
  3163. Return Value:
  3164. Returns TRUE.
  3165. --*/
  3166. {
  3167. DWORD ofs;
  3168. time_t timeDelta;
  3169. DBGMSG(DBG_TRACE, ("UMRDPPRN:HandlePrinterConfigChangeNotification entered.\n"));
  3170. //
  3171. // If this is for one of our printers.
  3172. //
  3173. if (DRDEVLST_FindByServerDeviceID(DeviceList,
  3174. serverDeviceID, &ofs)) {
  3175. DBGMSG(DBG_TRACE, ("UMRDPPRN:Config Info for Printer %ws has changed.\n",
  3176. DeviceList->devices[ofs].serverDeviceName));
  3177. //
  3178. // The install time for the device needs to be beyond a configurable threshold
  3179. // before we will do anything about the change. This eliminates forwarding
  3180. // unnecessary (non-user initiated) configuration changes to the client.
  3181. //
  3182. timeDelta = time(NULL) - DeviceList->devices[ofs].installTime;
  3183. if ((DWORD)timeDelta > ConfigSendThreshold) {
  3184. DBGMSG(DBG_TRACE,
  3185. ("UMRDPPRN:Processing config change because outside change time delta.\n")
  3186. );
  3187. //
  3188. // Need to record that the configuration has changed and set a
  3189. // timer on forwarding to the client in order to compress changes into
  3190. // a single message to the client.
  3191. //
  3192. DeviceList->devices[ofs].fConfigInfoChanged = TRUE;
  3193. TriggerConfigChangeTimer();
  3194. }
  3195. else {
  3196. DBGMSG(DBG_TRACE,
  3197. ("UMRDPPRN:Skipping config change because inside change time delta.\n")
  3198. );
  3199. }
  3200. }
  3201. return TRUE;
  3202. }
  3203. BOOL
  3204. SendPrinterConfigInfoToClient(
  3205. IN PCWSTR printerName,
  3206. IN LPBYTE pConfigInfo,
  3207. IN DWORD ConfigInfoSize
  3208. )
  3209. /*++
  3210. Routine Description:
  3211. Send a printer update cache data message to the client.
  3212. Arguments:
  3213. printerName - Name of printer.
  3214. pConfigInfo - Configuration Information.
  3215. ConfigInfoSize - size of config info.
  3216. Return Value:
  3217. Return TRUE on success. FALSE, otherwise.
  3218. --*/
  3219. {
  3220. PRDPDR_PRINTER_CACHEDATA_PACKET cachedDataPacket;
  3221. DWORD cachedDataPacketSize;
  3222. PRDPDR_PRINTER_UPDATE_CACHEDATA cachedData;
  3223. BOOL result;
  3224. DWORD printerSz;
  3225. PWSTR str;
  3226. DBGMSG(DBG_TRACE, ("UMRDPPRN: SendPrinterConfigInfoToClient entered.\n"));
  3227. DBGMSG(DBG_TRACE, ("UMRDPPRN:SendPrinterConfigInfoToClient printer name is %ws.\n",
  3228. printerName));
  3229. //
  3230. // Calculate the message size.
  3231. //
  3232. printerSz = ((wcslen(printerName) + 1) * sizeof(WCHAR));
  3233. cachedDataPacketSize = sizeof(RDPDR_PRINTER_CACHEDATA_PACKET) +
  3234. sizeof(RDPDR_PRINTER_UPDATE_CACHEDATA) +
  3235. printerSz +
  3236. ConfigInfoSize;
  3237. //
  3238. // Allocate the message.
  3239. //
  3240. cachedDataPacket = (PRDPDR_PRINTER_CACHEDATA_PACKET)ALLOCMEM(
  3241. cachedDataPacketSize
  3242. );
  3243. result = (cachedDataPacket != NULL);
  3244. if (result) {
  3245. PBYTE pData = NULL;
  3246. //
  3247. // Set up the packet.
  3248. //
  3249. cachedDataPacket->Header.PacketId = DR_PRN_CACHE_DATA;
  3250. cachedDataPacket->Header.Component = RDPDR_CTYP_PRN;
  3251. cachedDataPacket->EventId = RDPDR_UPDATE_PRINTER_EVENT;
  3252. //
  3253. // Set up the cached data.
  3254. //
  3255. cachedData = (PRDPDR_PRINTER_UPDATE_CACHEDATA)(
  3256. (PBYTE)cachedDataPacket +
  3257. sizeof(RDPDR_PRINTER_CACHEDATA_PACKET)
  3258. );
  3259. cachedData->PrinterNameLen = printerSz;
  3260. cachedData->ConfigDataLen = ConfigInfoSize;
  3261. //
  3262. // Add the printer name.
  3263. //
  3264. str = (PWSTR)((PBYTE)cachedData + sizeof(RDPDR_PRINTER_UPDATE_CACHEDATA));
  3265. wcscpy(str, printerName);
  3266. //
  3267. // Add the config info.
  3268. //
  3269. pData = (PBYTE)str + printerSz;
  3270. memcpy(pData, pConfigInfo, ConfigInfoSize);
  3271. //
  3272. // Send the message to the client.
  3273. //
  3274. result = UMRDPDR_SendMessageToClient(
  3275. cachedDataPacket,
  3276. cachedDataPacketSize
  3277. );
  3278. // Release the buffer.
  3279. FREEMEM(cachedDataPacket);
  3280. }
  3281. else {
  3282. DBGMSG(DBG_ERROR, ("UMRDPPRN: Can't allocate cached data packet.\n"));
  3283. }
  3284. return result;
  3285. }
  3286. DWORD
  3287. GetPrinterConfigInfo(
  3288. LPCWSTR printerName,
  3289. LPBYTE * ppBuffer,
  3290. LPDWORD pdwBufSize
  3291. )
  3292. /*++
  3293. Routine Description:
  3294. Gets the Printer configuration Information from PrintUI.
  3295. Arguments:
  3296. printerName - Name of the printer.
  3297. ppBuffer - A place holder for a buffer pointer.
  3298. This functions allocates memory and sends it out through this argument
  3299. The caller should free this memory.
  3300. pdwBufSize - size of allocated memory.
  3301. Return Value:
  3302. Returns ERROR_SUCCESS if successful.
  3303. --*/
  3304. {
  3305. WCHAR fileName[MAX_PATH];
  3306. WCHAR tempPath[MAX_PATH];
  3307. HANDLE hFile = INVALID_HANDLE_VALUE;
  3308. DWORD dwResult;
  3309. DWORD dwBytes;
  3310. DWORD dwBytesRead;
  3311. BOOL fImpersonated = FALSE;
  3312. ASSERT(ppBuffer && pdwBufSize);
  3313. *pdwBufSize = 0;
  3314. //
  3315. // Get Temp Folder
  3316. // Impersonate first, so the file has the proper acls on it
  3317. // Ignore the error, the worst case is caching will not be possible, as we create it with system acls
  3318. // No security hole here
  3319. //
  3320. DBGMSG(DBG_TRACE, ("UMRDPPRN:GetPrinterConfigInfo entered.\n"));
  3321. fImpersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser);
  3322. dwResult = GetTempPathW(MAX_PATH, tempPath);
  3323. if (dwResult > 0 && dwResult <= MAX_PATH) {
  3324. GetTempFileNameW(tempPath, TEMP_FILE_PREFIX, 0, fileName);
  3325. }
  3326. else {
  3327. GetTempFileNameW(L".", TEMP_FILE_PREFIX, 0, fileName);
  3328. }
  3329. DBGMSG(DBG_TRACE, ("UMRDPPRN:Temp File Name is %ws.\n", fileName));
  3330. //
  3331. // While impersonating the logged on user, fetch the settings.
  3332. //
  3333. if (fImpersonated) {
  3334. dwResult = CallPrintUiPersistFunc(printerName, fileName,
  3335. CMDLINE_FOR_STORING_CONFIGINFO_IMPERSONATE);
  3336. RevertToSelf();
  3337. if (dwResult != ERROR_SUCCESS) {
  3338. DBGMSG(DBG_TRACE, ("UMRDPPRN:CallPrintUiPersistFunc failed with code: %ld\n", dwResult));
  3339. goto Cleanup;
  3340. }
  3341. }
  3342. else {
  3343. dwResult = GetLastError();
  3344. DBGMSG(DBG_TRACE, ("UMRDPPRN:ImpersonateLoggedOnUser: %ld\n", dwResult));
  3345. goto Cleanup;
  3346. }
  3347. //
  3348. // Open the file and read the contents to the buffer
  3349. //
  3350. hFile = CreateFileW(
  3351. fileName,
  3352. GENERIC_READ,
  3353. FILE_SHARE_READ,
  3354. NULL,
  3355. OPEN_EXISTING,
  3356. FILE_ATTRIBUTE_NORMAL,
  3357. NULL
  3358. );
  3359. if (hFile == INVALID_HANDLE_VALUE) {
  3360. dwResult = GetLastError();
  3361. DBGMSG(DBG_TRACE, ("UMRDPPRN:CreateFileW failed with code: %ld\n", dwResult));
  3362. goto Cleanup;
  3363. }
  3364. dwBytes = GetFileSize(hFile, NULL);
  3365. *ppBuffer = (LPBYTE) ALLOCMEM(dwBytes);
  3366. if (*ppBuffer == NULL) {
  3367. dwResult = GetLastError();
  3368. DBGMSG(DBG_TRACE, ("UMRDPPRN:AllocMem failed with code: %ld\n", dwResult));
  3369. goto Cleanup;
  3370. }
  3371. if (!ReadFile(
  3372. hFile,
  3373. *ppBuffer,
  3374. dwBytes,
  3375. &dwBytesRead,
  3376. NULL
  3377. )) {
  3378. dwResult = GetLastError();
  3379. DBGMSG(DBG_TRACE, ("UMRDPPRN:ReadFile failed with code: %ld\n", dwResult));
  3380. goto Cleanup;
  3381. }
  3382. * pdwBufSize = dwBytesRead;
  3383. dwResult = ERROR_SUCCESS;
  3384. Cleanup:
  3385. //
  3386. // Close the file and delete it
  3387. //
  3388. if (hFile != INVALID_HANDLE_VALUE) {
  3389. CloseHandle(hFile);
  3390. DeleteFileW(fileName);
  3391. }
  3392. return dwResult;
  3393. }
  3394. DWORD
  3395. SetPrinterConfigInfo(
  3396. LPCWSTR printerName,
  3397. LPVOID lpBuffer,
  3398. DWORD dwBufSize
  3399. )
  3400. /*++
  3401. Routine Description:
  3402. Sets the Printer configuration Information from the cache data.
  3403. Arguments:
  3404. printerName - Name of the printer.
  3405. lpBuffer - Cache data.
  3406. pdwBufSize - Size of Cache data.
  3407. Return Value:
  3408. Returns ERROR_SUCCESS if successful.
  3409. --*/
  3410. {
  3411. WCHAR fileName[MAX_PATH] = L"";
  3412. WCHAR tempPath[MAX_PATH] = L"";
  3413. HANDLE hFile = INVALID_HANDLE_VALUE;
  3414. DWORD dwResult;
  3415. DWORD dwBytes;
  3416. BOOL fImpersonated = FALSE;
  3417. DBGMSG(DBG_TRACE, ("UMRDPPRN:SetPrinterConfigInfo entered.\n"));
  3418. DBGMSG(DBG_TRACE, ("UMRDPPRN:printerName is %ws.\n", printerName));
  3419. DBGMSG(DBG_TRACE, ("UMRDPPRN:bufsize is %ld.\n", dwBufSize));
  3420. //
  3421. // Get Temp Folder
  3422. // Impersonate first, so the file has the proper acls on it
  3423. // Ignore the error, the worst case is caching will not be possible, as we create it with system acls
  3424. // No security hole here
  3425. //
  3426. fImpersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser);
  3427. if (!fImpersonated) {
  3428. DBGMSG(DBG_TRACE, ("UMRDPPRN:SetPrinterConfigInfo Impersonation failed. Creating temp file in the context of system\n"));
  3429. }
  3430. dwResult = GetTempPathW(MAX_PATH, tempPath);
  3431. if (dwResult > 0 && dwResult <= MAX_PATH) {
  3432. dwResult = GetTempFileNameW(tempPath, TEMP_FILE_PREFIX, 0, fileName);
  3433. }
  3434. else {
  3435. dwResult = GetTempFileNameW(L".", TEMP_FILE_PREFIX, 0, fileName);
  3436. }
  3437. if( dwResult == 0 ) {
  3438. dwResult = GetLastError();
  3439. DBGMSG(DBG_TRACE, ("UMRDPPRN:GetTempFileNameW failed with code: %ld\n", dwResult));
  3440. goto Cleanup;
  3441. }
  3442. //
  3443. // Save the contents to the file
  3444. //
  3445. hFile = CreateFileW(
  3446. fileName,
  3447. GENERIC_WRITE,
  3448. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3449. NULL,
  3450. CREATE_ALWAYS,
  3451. FILE_ATTRIBUTE_NORMAL,
  3452. NULL
  3453. );
  3454. if (hFile == INVALID_HANDLE_VALUE) {
  3455. dwResult = GetLastError();
  3456. DBGMSG(DBG_TRACE, ("UMRDPPRN:CreateFileW failed with code: %ld\n", dwResult));
  3457. goto Cleanup;
  3458. }
  3459. if ((!WriteFile(
  3460. hFile,
  3461. lpBuffer,
  3462. dwBufSize,
  3463. &dwBytes,
  3464. NULL
  3465. )) ||
  3466. (dwBytes < dwBufSize)) {
  3467. dwResult = GetLastError();
  3468. CloseHandle(hFile);
  3469. DBGMSG(DBG_TRACE, ("UMRDPPRN:WriteFile failed with code: %ld\n", dwResult));
  3470. goto Cleanup;
  3471. }
  3472. if (hFile != INVALID_HANDLE_VALUE) {
  3473. CloseHandle(hFile);
  3474. }
  3475. DBGMSG(DBG_TRACE, ("UMRDPPRN:fileName is %ws.\n", fileName));
  3476. if (fImpersonated) {
  3477. fImpersonated = !(RevertToSelf());
  3478. DBGMSG(DBG_TRACE, ("UMRDPPRN:RevertToSelf %s\n", fImpersonated?"Failed":"Passed"));
  3479. }
  3480. //
  3481. // Call printui the first time as system. We do this twice because
  3482. // some settings require that we be running as system vs. user.
  3483. //
  3484. dwResult = CallPrintUiPersistFunc(printerName, fileName,
  3485. CMDLINE_FOR_RESTORING_CONFIGINFO_NOIMPERSONATE);
  3486. if (dwResult != ERROR_SUCCESS) {
  3487. goto Cleanup;
  3488. }
  3489. //
  3490. // Call printui the second time as the logged on user.
  3491. //
  3492. if (ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser)) {
  3493. dwResult = CallPrintUiPersistFunc(printerName, fileName,
  3494. CMDLINE_FOR_RESTORING_CONFIGINFO_IMPERSONATE);
  3495. RevertToSelf();
  3496. if (dwResult != ERROR_SUCCESS) {
  3497. goto Cleanup;
  3498. }
  3499. }
  3500. else {
  3501. dwResult = GetLastError();
  3502. DBGMSG(DBG_ERROR, ("UMRDPPRN: ImpersonateLoggedOnUser: %08X\n",
  3503. dwResult));
  3504. }
  3505. Cleanup:
  3506. if (fImpersonated) {
  3507. RevertToSelf();
  3508. }
  3509. if (hFile != INVALID_HANDLE_VALUE) {
  3510. DeleteFileW(fileName);
  3511. }
  3512. return dwResult;
  3513. }
  3514. DWORD
  3515. CallPrintUiPersistFunc(
  3516. LPCWSTR printerName,
  3517. LPCWSTR fileName,
  3518. LPCWSTR formatString
  3519. )
  3520. /*++
  3521. Routine Description:
  3522. Calls the PrintUI function for storing or restoring printer config info.
  3523. Arguments:
  3524. printerName - Name of the printer.
  3525. fileName - Name of the temp file.
  3526. formatString - PrintUI save/restore format string.
  3527. Return Value:
  3528. Returns ERROR_SUCCESS if successful.
  3529. --*/
  3530. {
  3531. WCHAR cmdLine[3 * MAX_PATH + (sizeof(CMDLINE_FOR_RESTORING_CONFIGINFO_NOIMPERSONATE)/sizeof(WCHAR)) + 2];
  3532. WCHAR formattedPrinterName[(MAX_PATH+1)*2];
  3533. WCHAR * pSource, * pDest;
  3534. DWORD dwResult = ERROR_SUCCESS;
  3535. DBGMSG(DBG_TRACE, ("UMRDPPRN:CallPrintUiPersistFunc Entered.\n"));
  3536. ASSERT(PrintUIEntryFunc != NULL);
  3537. ASSERT(printerName != NULL);
  3538. ASSERT(fileName != NULL);
  3539. //
  3540. // Format the printer name
  3541. //
  3542. pSource = (WCHAR *)printerName;
  3543. pDest = formattedPrinterName;
  3544. while (*pSource) {
  3545. if (*pSource == L'\"' || *pSource == L'@') {
  3546. *pDest++ = L'\\';
  3547. }
  3548. *pDest++ = *pSource++;
  3549. //
  3550. // pDest may have buffer overflow. Check for it.
  3551. //
  3552. if ((pDest - formattedPrinterName) >=
  3553. (sizeof(formattedPrinterName)/sizeof(formattedPrinterName[0]) - 1)) {
  3554. return STATUS_BUFFER_OVERFLOW;
  3555. }
  3556. }
  3557. *pDest = L'\0';
  3558. //
  3559. // Format the command line to be passed to PrintUI function
  3560. //
  3561. swprintf(cmdLine, formatString, formattedPrinterName, fileName);
  3562. DBGMSG(DBG_TRACE, ("UMRDPPRN:cmdLine is: %ws\n", cmdLine));
  3563. dwResult = (DWORD)PrintUIEntryFunc(
  3564. NULL, // Window handle
  3565. PrintUILibHndl, // Handle to DLL instance.
  3566. cmdLine, // Command Line
  3567. TRUE
  3568. );
  3569. DBGMSG(DBG_TRACE, ("UMRDPPRN:PrintUiEntryFunc returned: %ld\n", dwResult));
  3570. return dwResult;
  3571. }
  3572. void
  3573. WaitableTimerSignaled(
  3574. HANDLE waitableObject,
  3575. PVOID clientData
  3576. )
  3577. /*++
  3578. Routine Description:
  3579. Goes through the device list checking if the config info has changed
  3580. for any of the printers. If so, sends the config info to the client.
  3581. Arguments:
  3582. waitableObject - Associated waitable object.
  3583. clientData - Ignored.
  3584. Return Value:
  3585. NONE.
  3586. --*/
  3587. {
  3588. DWORD dwResult = ERROR_SUCCESS;
  3589. DWORD i;
  3590. BOOL fImpersonated;
  3591. LARGE_INTEGER li;
  3592. DBGMSG(DBG_TRACE, ("UMRDPPRN: WaitableTimerSignaled Entered.\n"));
  3593. //
  3594. // Compute as large number as possible, but do not overflow.
  3595. //
  3596. li.QuadPart = Int32x32To64(INFINITE_WAIT_PERIOD, INFINITE_WAIT_PERIOD);
  3597. li.QuadPart *= -1; //relative time
  3598. //
  3599. // Reset the waitable timer to a non-signaled state.
  3600. // We don't want it signaled until we do a TriggerConfigChangeTimer.
  3601. // So, set the time interval to a very large number.
  3602. //
  3603. ASSERT(g_fTimerSet);
  3604. ASSERT(waitableObject == WaitableTimer);
  3605. if (!SetWaitableTimer(waitableObject,
  3606. &li,
  3607. 0,
  3608. NULL,
  3609. NULL,
  3610. FALSE)) {
  3611. DBGMSG(DBG_TRACE, ("UMRDPPRN:SetWaitableTimer Failed."
  3612. "Error: %ld.\n", GetLastError()));
  3613. }
  3614. //
  3615. // Now, kill the timer
  3616. // TODO: Do we really need this?
  3617. //
  3618. if (!CancelWaitableTimer(waitableObject)) {
  3619. DBGMSG(DBG_ERROR, ("UMRDPPRN: CancelWaitableTimer failed."
  3620. "Error: %ld\n", GetLastError()));
  3621. }
  3622. g_fTimerSet = FALSE;
  3623. //
  3624. // Iterate the Devices List to see if config Info has changed for any
  3625. //
  3626. for (i = 0; i < DeviceList->deviceCount; i++) {
  3627. if (DeviceList->devices[i].fConfigInfoChanged) {
  3628. LPBYTE pConfigData = NULL;
  3629. DWORD size = 0;
  3630. //
  3631. // reset error code in order to process next item
  3632. //
  3633. dwResult = ERROR_SUCCESS;
  3634. // Reset the flag
  3635. DeviceList->devices[i].fConfigInfoChanged = FALSE;
  3636. DBGMSG(DBG_INFO, ("UMRDPPRN: Trying to Get ConfigInfo for the printer %ws\n",
  3637. DeviceList->devices[i].serverDeviceName));
  3638. //
  3639. // Get the printer config info.
  3640. //
  3641. if (dwResult == ERROR_SUCCESS) {
  3642. dwResult = GetPrinterConfigInfo(
  3643. DeviceList->devices[i].serverDeviceName,
  3644. &pConfigData, &size);
  3645. }
  3646. if (dwResult == ERROR_SUCCESS) {
  3647. // Send this info to the client
  3648. SendPrinterConfigInfoToClient(
  3649. DeviceList->devices[i].clientDeviceName,
  3650. pConfigData,
  3651. size
  3652. );
  3653. }
  3654. if (pConfigData) {
  3655. FREEMEM(pConfigData);
  3656. }
  3657. }
  3658. }
  3659. DBGMSG(DBG_TRACE, ("UMRDPPRN: Leaving WaitableTimerSignaled.\n"));
  3660. }
  3661. BOOL
  3662. SendPrinterRenameToClient(
  3663. IN PCWSTR oldprinterName,
  3664. IN PCWSTR newprinterName
  3665. )
  3666. /*++
  3667. Routine Description:
  3668. Send a printer update cache data message to the client.
  3669. Arguments:
  3670. oldprinterName - Old Name of printer.
  3671. newprinterName - New Name of printer.
  3672. Return Value:
  3673. Return TRUE on success. FALSE, otherwise.
  3674. --*/
  3675. {
  3676. PRDPDR_PRINTER_CACHEDATA_PACKET cachedDataPacket;
  3677. DWORD cachedDataPacketSize;
  3678. PRDPDR_PRINTER_RENAME_CACHEDATA cachedData;
  3679. BOOL result;
  3680. DWORD oldNameLen, newNameLen;
  3681. PWSTR str;
  3682. DBGMSG(DBG_TRACE, ("UMRDPPRN: SendPrinterRenameToClient entered.\n"));
  3683. DBGMSG(DBG_TRACE, ("UMRDPPRN:SendPrinterRenameToClient Old printer name is %ws.\n",
  3684. oldprinterName));
  3685. DBGMSG(DBG_TRACE, ("UMRDPPRN:SendPrinterRenameToClient New printer name is %ws.\n",
  3686. newprinterName));
  3687. //
  3688. // Calculate the message size.
  3689. //
  3690. oldNameLen = (oldprinterName) ? ((wcslen(oldprinterName) + 1) * sizeof(WCHAR)) : 0;
  3691. newNameLen = (newprinterName) ? ((wcslen(newprinterName) + 1) * sizeof(WCHAR)) : 0;
  3692. if (!(oldNameLen && newNameLen)) {
  3693. DBGMSG(DBG_TRACE, ("UMRDPPRN: Printer name is empty. Returning FALSE\n"));
  3694. return FALSE;
  3695. }
  3696. cachedDataPacketSize = sizeof(RDPDR_PRINTER_CACHEDATA_PACKET) +
  3697. sizeof(RDPDR_PRINTER_RENAME_CACHEDATA) +
  3698. oldNameLen + newNameLen;
  3699. //
  3700. // Allocate the message.
  3701. //
  3702. cachedDataPacket = (PRDPDR_PRINTER_CACHEDATA_PACKET)ALLOCMEM(
  3703. cachedDataPacketSize
  3704. );
  3705. result = (cachedDataPacket != NULL);
  3706. if (result) {
  3707. //
  3708. // Set up the packet.
  3709. //
  3710. cachedDataPacket->Header.PacketId = DR_PRN_CACHE_DATA;
  3711. cachedDataPacket->Header.Component = RDPDR_CTYP_PRN;
  3712. cachedDataPacket->EventId = RDPDR_RENAME_PRINTER_EVENT;
  3713. //
  3714. // Set up the cached data.
  3715. //
  3716. cachedData = (PRDPDR_PRINTER_RENAME_CACHEDATA)(
  3717. (PBYTE)cachedDataPacket +
  3718. sizeof(RDPDR_PRINTER_CACHEDATA_PACKET)
  3719. );
  3720. cachedData->OldPrinterNameLen = oldNameLen;
  3721. cachedData->NewPrinterNameLen = newNameLen;
  3722. //
  3723. // Add the printer names.
  3724. //
  3725. str = (PWSTR)((PBYTE)cachedData + sizeof(RDPDR_PRINTER_RENAME_CACHEDATA));
  3726. wcscpy(str, oldprinterName);
  3727. str = (PWSTR)((PBYTE)str + oldNameLen);
  3728. wcscpy(str, newprinterName);
  3729. //
  3730. // Send the message to the client.
  3731. //
  3732. result = UMRDPDR_SendMessageToClient(
  3733. cachedDataPacket,
  3734. cachedDataPacketSize
  3735. );
  3736. // Release the buffer.
  3737. FREEMEM(cachedDataPacket);
  3738. }
  3739. DBGMSG(DBG_TRACE, ("UMRDPPRN: SendPrinterRenameToClient Leaving.\n"));
  3740. return result;
  3741. }
  3742. VOID LoadConfigurableValues()
  3743. /*++
  3744. Routine Description:
  3745. Load configurable values out of the registry.
  3746. Arguments:
  3747. Return Value:
  3748. --*/
  3749. {
  3750. LONG status;
  3751. HKEY regKey;
  3752. LONG sz;
  3753. BOOL fetchResult;
  3754. LONG s;
  3755. DBGMSG(DBG_TRACE, ("UMRDPPRN: LoadConfigurableValues entered.\n"));
  3756. //
  3757. // Open the top level reg key for configurable resources.
  3758. //
  3759. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, CONFIGREGKEY, 0,
  3760. KEY_READ, &regKey);
  3761. //
  3762. // Read the configurable threshold for delta between printer installation
  3763. // time and forwarding of first user-initiated configuration change data
  3764. // to the client. The units for this value is in seconds.
  3765. //
  3766. if (status == ERROR_SUCCESS) {
  3767. sz = sizeof(ConfigSendThreshold);
  3768. s = RegQueryValueEx(regKey, CONFIGTHRESHOLDREGVALUE, NULL,
  3769. NULL, (PBYTE)&ConfigSendThreshold, &sz);
  3770. if (s != ERROR_SUCCESS) {
  3771. ConfigSendThreshold = CONFIGTHRESHOLDDEFAULT;
  3772. DBGMSG(DBG_WARN,
  3773. ("UMRDPPRN: LoadConfigurableValues can't read config threshold: %ld.\n", s));
  3774. }
  3775. }
  3776. else {
  3777. regKey = NULL;
  3778. }
  3779. DBGMSG(DBG_TRACE,
  3780. ("UMRDPPRN:Config. change threshold is %ld.\n",
  3781. ConfigSendThreshold)
  3782. );
  3783. //
  3784. // Read the location of the user-configurable Client Driver Name Mapping INF.
  3785. //
  3786. ASSERT(UserDefinedMappingINFName == NULL);
  3787. ASSERT(UserDefinedMappingINFSection == NULL);
  3788. fetchResult = FALSE;
  3789. if (status == ERROR_SUCCESS) {
  3790. fetchResult = TSNUTL_FetchRegistryValue(
  3791. regKey,
  3792. CONFIGUSERDEFINEDMAPPINGINFNAMEVALUE,
  3793. (PBYTE *)&UserDefinedMappingINFName
  3794. );
  3795. }
  3796. //
  3797. // Read the section name of the user-configurable Client Driver Name Mapping INF.
  3798. //
  3799. if ((status == ERROR_SUCCESS) && fetchResult) {
  3800. fetchResult = TSNUTL_FetchRegistryValue(
  3801. regKey,
  3802. CONFIGUSERDEFINEDMAPPINGINFSECTIONVALUE,
  3803. (PBYTE *)&UserDefinedMappingINFSection
  3804. );
  3805. if (!fetchResult) {
  3806. ASSERT(UserDefinedMappingINFSection == NULL);
  3807. FREEMEM(UserDefinedMappingINFName);
  3808. UserDefinedMappingINFName = NULL;
  3809. }
  3810. }
  3811. //
  3812. // Close the parent reg key.
  3813. //
  3814. if (regKey != NULL) {
  3815. RegCloseKey(regKey);
  3816. }
  3817. DBGMSG(DBG_TRACE, ("UMRDPPRN: LoadConfigurableValues exiting.\n"));
  3818. }
  3819. HANDLE
  3820. RegisterForPrinterPrefNotify()
  3821. /*++
  3822. Routine Description:
  3823. Register for changes to one of this session's printers' Printing
  3824. Preferences.
  3825. Arguments:
  3826. Return Value:
  3827. Handle to an event that will be signaled when the printing preferences
  3828. change for one of this session's printers. NULL is returned on error.
  3829. --*/
  3830. {
  3831. LONG ret;
  3832. HANDLE hEvent;
  3833. BOOL impersonated=FALSE;
  3834. NTSTATUS status;
  3835. HANDLE hKeyCurrentUser=INVALID_HANDLE_VALUE;
  3836. DBGMSG(DBG_TRACE, ("UMRDPPRN: RegisterForPrinterPrefNotify entered.\n"));
  3837. //
  3838. // Open the event.
  3839. //
  3840. hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  3841. if (hEvent == NULL) {
  3842. DBGMSG(DBG_ERROR,
  3843. ("UMRDPPRN: can't create event: %ld.\n",
  3844. GetLastError()));
  3845. }
  3846. //
  3847. // Need to impersonate the logged in user so we can get to the right
  3848. // dev mode.
  3849. //
  3850. if (hEvent != NULL) {
  3851. if ((UMRPDPPRN_TokenForLoggedOnUser == INVALID_HANDLE_VALUE) ||
  3852. !ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser)) {
  3853. DBGMSG(DBG_ERROR, ("UMRDPPRN: can't impersonate user %ld.\n",
  3854. GetLastError()));
  3855. CloseHandle(hEvent);
  3856. hEvent = NULL;
  3857. impersonated = FALSE;
  3858. }
  3859. else {
  3860. impersonated = TRUE;
  3861. }
  3862. }
  3863. //
  3864. // Attempt to open the the HKEY_CURRENT_USER predefined handle.
  3865. //
  3866. if (hEvent != NULL) {
  3867. status = RtlOpenCurrentUser(KEY_ALL_ACCESS, &hKeyCurrentUser);
  3868. if (!NT_SUCCESS(status)) {
  3869. DBGMSG(DBG_ERROR, ("UMRDPPRN: can't open HKCU: %08X.\n",status));
  3870. CloseHandle(hEvent);
  3871. hEvent = NULL;
  3872. }
  3873. }
  3874. //
  3875. // Open the printing system dev mode for this user. If it doesn't exist,
  3876. // it will be created. This key is changed when a user modifies their printing
  3877. // preferences.
  3878. //
  3879. if (hEvent != NULL) {
  3880. ASSERT(DevModeHKey == INVALID_HANDLE_VALUE);
  3881. ret = RegCreateKeyEx(
  3882. hKeyCurrentUser, // handle to an open key
  3883. TEXT("Printers\\DevModePerUser"), // address of subkey name
  3884. 0, // reserved
  3885. NULL, // address of class string
  3886. REG_OPTION_NON_VOLATILE, // special options flag
  3887. KEY_ALL_ACCESS, // desired security access
  3888. NULL, // key security structure
  3889. &DevModeHKey, // buffer for opened handle
  3890. NULL // disposition value buffer
  3891. );
  3892. if (ret != ERROR_SUCCESS) {
  3893. DBGMSG(DBG_ERROR,
  3894. ("UMRDPPRN: can't open printing dev mode: %ld.\n", ret)
  3895. );
  3896. CloseHandle(hEvent);
  3897. hEvent = NULL;
  3898. DevModeHKey = INVALID_HANDLE_VALUE;
  3899. }
  3900. }
  3901. //
  3902. // Revert back to the system user.
  3903. //
  3904. if (impersonated) {
  3905. RevertToSelf();
  3906. }
  3907. //
  3908. // Register for notification on this key.
  3909. //
  3910. if (hEvent != NULL) {
  3911. ret = RegNotifyChangeKeyValue(
  3912. DevModeHKey,
  3913. TRUE,
  3914. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
  3915. hEvent,
  3916. TRUE
  3917. );
  3918. if (ret != ERROR_SUCCESS) {
  3919. DBGMSG(DBG_ERROR,
  3920. ("UMRDPPRN: can't register for registry key change event: %ld.\n",
  3921. ret));
  3922. CloseHandle(hEvent);
  3923. hEvent = NULL;
  3924. }
  3925. }
  3926. //
  3927. // Close the handle to HKCU.
  3928. //
  3929. if (hKeyCurrentUser != INVALID_HANDLE_VALUE) {
  3930. RegCloseKey(hKeyCurrentUser);
  3931. }
  3932. //
  3933. // Log an event on error.
  3934. //
  3935. if (hEvent == NULL) {
  3936. TsLogError(
  3937. EVENT_NOTIFY_FAILEDTOREGFOR_SETTING_NOTIFY,
  3938. EVENTLOG_ERROR_TYPE,
  3939. 0,
  3940. NULL,
  3941. __LINE__
  3942. );
  3943. }
  3944. DBGMSG(DBG_TRACE, ("UMRDPPRN: RegisterForPrinterPrefNotify done.\n"));
  3945. return hEvent;
  3946. }
  3947. /*++
  3948. Routine Description:
  3949. Check if a specific printer driver already installed.
  3950. Arguments:
  3951. clientDriver - Client Driver Name.
  3952. Return Values:
  3953. ERROR_SUCCESS if driver already installed.
  3954. ERROR_FILE_NOT_FOUND if driver is not installed.
  3955. or other error code
  3956. --*/
  3957. DWORD PrinterDriverInstalled(
  3958. IN PCWSTR clientDriver
  3959. )
  3960. {
  3961. PDRIVER_INFO_1 pDrivers = NULL;
  3962. DWORD cbNeeded;
  3963. DWORD cbAllocated;
  3964. DWORD cbReturned;
  3965. DWORD dwStatus = ERROR_FILE_NOT_FOUND;
  3966. BOOL bSuccess;
  3967. DWORD i;
  3968. DBGMSG(DBG_TRACE, ("UMRDPPRN: PrinterDriverInstalled looking for %ws.\n", clientDriver));
  3969. //
  3970. // Return immediately if the DLL is trying to shut down. This
  3971. // is to help prevent us from getting stuck in a system call.
  3972. //
  3973. if( ShutdownFlag ) {
  3974. return ERROR_SHUTDOWN_IN_PROGRESS;
  3975. }
  3976. bSuccess = EnumPrinterDrivers(
  3977. NULL,
  3978. NULL,
  3979. 1, // we only need a list of driver name
  3980. (LPBYTE) pDrivers,
  3981. 0,
  3982. &cbNeeded,
  3983. &cbReturned
  3984. );
  3985. if( TRUE == bSuccess || ( dwStatus = GetLastError() ) == ERROR_INSUFFICIENT_BUFFER ) {
  3986. //
  3987. // Return immediately if the DLL is trying to shut down. This
  3988. // is to help prevent us from getting stuck in a system call.
  3989. //
  3990. if( ShutdownFlag ) {
  3991. dwStatus = ERROR_SHUTDOWN_IN_PROGRESS;
  3992. }
  3993. else {
  3994. pDrivers = (PDRIVER_INFO_1)ALLOCMEM( cbAllocated = cbNeeded );
  3995. if( NULL != pDrivers ) {
  3996. bSuccess = EnumPrinterDrivers(
  3997. NULL,
  3998. NULL,
  3999. 1, // we only need a list of driver name
  4000. (LPBYTE)pDrivers,
  4001. cbAllocated,
  4002. &cbNeeded,
  4003. &cbReturned
  4004. );
  4005. if( TRUE == bSuccess ) {
  4006. //
  4007. // loop thru entire list to find out if interested driver
  4008. // exists on local machine.
  4009. // Return immediately if the DLL is trying to shut down. This
  4010. // is to help prevent us from getting stuck in a system call.
  4011. //
  4012. dwStatus = ERROR_FILE_NOT_FOUND;
  4013. for( i=0; FALSE == ShutdownFlag && i < cbReturned; i++ ) {
  4014. if( 0 == _wcsicmp( pDrivers[i].pName, clientDriver ) ) {
  4015. dwStatus = ERROR_SUCCESS;
  4016. break;
  4017. }
  4018. }
  4019. if( ShutdownFlag ) {
  4020. dwStatus = ERROR_SHUTDOWN_IN_PROGRESS;
  4021. }
  4022. }
  4023. else {
  4024. dwStatus = GetLastError();
  4025. }
  4026. FREEMEM( pDrivers );
  4027. }
  4028. else {
  4029. dwStatus = GetLastError();
  4030. }
  4031. }
  4032. }
  4033. DBGMSG(DBG_TRACE, ("UMRDPPRN: PrinterDriverInstalled done with %ld.\n", dwStatus));
  4034. return dwStatus;
  4035. }
  4036. /*++
  4037. Routine Description:
  4038. Map a client printer driver name to a server printer driver name,
  4039. if a mapping is defined in ntprint.inf or the inf that is available
  4040. to the end-user.
  4041. Arguments:
  4042. clientDriver - Client driver name.
  4043. mappedName - Pointer to mapped driver name buffer. Should
  4044. be released if the mapping is successful.
  4045. mappedNameBufSize - Returned size of mapped driver name buffer.
  4046. Return Value:
  4047. TRUE if the client driver name was mapped.
  4048. --*/
  4049. BOOL MapClientPrintDriverName(
  4050. IN PCWSTR clientDriver,
  4051. IN OUT PWSTR *mappedName,
  4052. IN OUT DWORD *mappedNameBufSize
  4053. )
  4054. {
  4055. BOOL clientDriverMapped = FALSE;
  4056. ULONG requiredSize;
  4057. USHORT nNumPrintSections;
  4058. DBGMSG(DBG_TRACE, ("UMRDPPRN: MapClientPrintDriverName with %ws.\n", clientDriver));
  4059. //
  4060. // First, check the user-defined INF section if it is so configured.
  4061. //
  4062. if ((UserDefinedMappingINFName != NULL) &&
  4063. (UserDefinedMappingINFSection != NULL)) {
  4064. while (!(clientDriverMapped =
  4065. RDPDRUTL_MapPrintDriverName(
  4066. clientDriver, UserDefinedMappingINFName,
  4067. UserDefinedMappingINFSection, 0, 1,
  4068. *mappedName,
  4069. (*mappedNameBufSize) / sizeof(WCHAR),
  4070. &requiredSize
  4071. )) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  4072. if (!UMRDPDR_ResizeBuffer(&MappedDriverNameBuf, requiredSize * sizeof(WCHAR),
  4073. &MappedDriverNameBufSize)) {
  4074. break;
  4075. }
  4076. }
  4077. }
  4078. if( clientDriverMapped ) {
  4079. goto Done;
  4080. }
  4081. //
  4082. // Client does not send over platform info (NT4, Win9x...) so try both
  4083. // upgrade file
  4084. //
  4085. //
  4086. // printupg.inf contain block driver and its mapping to inbox driver which
  4087. // is not in ntprint.inf.
  4088. //
  4089. nNumPrintSections = 0;
  4090. while( (NULL != prgwszPrinterSectionNames[nNumPrintSections]) &&
  4091. !(clientDriverMapped =
  4092. RDPDRUTL_MapPrintDriverName(
  4093. clientDriver,
  4094. L"printupg.inf",
  4095. prgwszPrinterSectionNames[nNumPrintSections++],
  4096. 0,
  4097. 1,
  4098. *mappedName,
  4099. (*mappedNameBufSize) / sizeof(WCHAR),
  4100. &requiredSize
  4101. ))&&
  4102. (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  4103. if (!UMRDPDR_ResizeBuffer(&MappedDriverNameBuf, requiredSize * sizeof(WCHAR),
  4104. &MappedDriverNameBufSize)) {
  4105. break;
  4106. }
  4107. }
  4108. if( clientDriverMapped ) {
  4109. goto Done;
  4110. }
  4111. //
  4112. // if still can't find a mapping, try using prtupg9x.inf
  4113. //
  4114. while( !(clientDriverMapped =
  4115. RDPDRUTL_MapPrintDriverName(
  4116. clientDriver,
  4117. L"prtupg9x.inf",
  4118. L"Printer Driver Mapping", 0, 1,
  4119. *mappedName,
  4120. (*mappedNameBufSize) / sizeof(WCHAR),
  4121. &requiredSize
  4122. )) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER) ) {
  4123. if (!UMRDPDR_ResizeBuffer(&MappedDriverNameBuf, requiredSize * sizeof(WCHAR),
  4124. &MappedDriverNameBufSize)) {
  4125. break;
  4126. }
  4127. }
  4128. if( clientDriverMapped ) {
  4129. goto Done;
  4130. }
  4131. //
  4132. // If we didn't get a match, then check the "Previous Names" section
  4133. // of ntprint.inf. Source and destination fields are kind of backwards
  4134. // in ntprint.inf.
  4135. //
  4136. if (!clientDriverMapped) {
  4137. while (!(clientDriverMapped =
  4138. RDPDRUTL_MapPrintDriverName(
  4139. clientDriver, L"ntprint.inf",
  4140. L"Previous Names", 1, 0,
  4141. *mappedName,
  4142. (*mappedNameBufSize) / sizeof(WCHAR),
  4143. &requiredSize
  4144. )) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  4145. if (!UMRDPDR_ResizeBuffer(&MappedDriverNameBuf, requiredSize * sizeof(WCHAR),
  4146. &MappedDriverNameBufSize)) {
  4147. break;
  4148. }
  4149. }
  4150. }
  4151. Done:
  4152. if(clientDriverMapped) {
  4153. DBGMSG(DBG_TRACE, ("UMRDPPRN: MapClientPrintDriverName returns %ws.\n", *mappedName));
  4154. }
  4155. return clientDriverMapped;
  4156. }
  4157. BOOL
  4158. GetPrinterPortName(
  4159. IN HANDLE hPrinter,
  4160. OUT PWSTR *portName
  4161. )
  4162. /*++
  4163. Routine Description:
  4164. Get the port name for an open printer.
  4165. Arguments:
  4166. hPrinter - Open printer handle.
  4167. portName - Port name
  4168. Return Value:
  4169. Return TRUE on success. FALSE, otherwise.
  4170. --*/
  4171. {
  4172. BOOL result;
  4173. DWORD sz;
  4174. //
  4175. // Size our printer info level 2 buffer.
  4176. //
  4177. result = !GetPrinter(hPrinter, 2, NULL, 0, &sz) &&
  4178. (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
  4179. if (result) {
  4180. result = UMRDPDR_ResizeBuffer(
  4181. &PrinterInfo2Buf,
  4182. sz, &PrinterInfo2BufSize
  4183. );
  4184. }
  4185. //
  4186. // Get printer info level 2 for the new printer.
  4187. //
  4188. if (result) {
  4189. result = GetPrinter(hPrinter, 2, (char *)PrinterInfo2Buf,
  4190. PrinterInfo2BufSize, &sz);
  4191. }
  4192. if (result) {
  4193. *portName = &PrinterInfo2Buf->pPortName[0];
  4194. }
  4195. else {
  4196. DBGMSG(DBG_ERROR, ("UMRDPDR:Error fetching printer port name."));
  4197. }
  4198. return result;
  4199. }
  4200. BOOL
  4201. SaveDefaultPrinterContext(PCWSTR currentlyInstallingPrinterName)
  4202. /*++
  4203. Routine Description:
  4204. Save current contextual information for the active user's default
  4205. printer, so it can be restored on printer deletion.
  4206. Arguments:
  4207. Return Value:
  4208. TRUE is returned on success. Otherwise, FALSE is returned and
  4209. GetLastError() can be used for retrieving extended error information.
  4210. --*/
  4211. {
  4212. BOOL result;
  4213. DWORD bufSize;
  4214. DWORD status = ERROR_SUCCESS;
  4215. BOOL fImpersonated = FALSE;
  4216. DBGMSG(DBG_TRACE, ("UMRDPPRN: SaveDefaultPrinterContext entered.\n"));
  4217. //
  4218. // Save the name of the current default printer, in RAM.
  4219. //
  4220. bufSize = sizeof(SavedDefaultPrinterName) / sizeof(SavedDefaultPrinterName[0]);
  4221. //
  4222. //impersonate first
  4223. //
  4224. if (!(fImpersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser))) {
  4225. DBGMSG(DBG_TRACE, ("UMRDPDR:ImpersonateLoggedOnUser failed. Error:%ld.\n", GetLastError()));
  4226. }
  4227. if (!(result = GetDefaultPrinter(SavedDefaultPrinterName, &bufSize))) {
  4228. status = GetLastError();
  4229. }
  4230. if (fImpersonated && !RevertToSelf()) {
  4231. DBGMSG(DBG_TRACE, ("UMRDPDR:RevertToSelf failed. Error:%ld.\n", GetLastError()));
  4232. result = FALSE;
  4233. }
  4234. //
  4235. // 645988:Check if the just installed TS printer is the default printer.
  4236. // Since we haven't set it as a TS printer yet, the RDPDRUTL_PrinterIsTs()
  4237. // function will return false and we save this as global default.
  4238. // That will cause problems later when we try to
  4239. // restore the default printer context.
  4240. //
  4241. if (_wcsicmp(currentlyInstallingPrinterName, SavedDefaultPrinterName) == 0) {
  4242. //
  4243. // Clear the default printer name to
  4244. // indicate we haven't found any yet.
  4245. //
  4246. wcscpy(SavedDefaultPrinterName, L"");
  4247. result = FALSE;
  4248. goto Exit;
  4249. }
  4250. //
  4251. // If the current default printer is a non-TS printer, store its
  4252. // name in a global reg. key for this user. That way, it can be
  4253. // saved when this session or some other session for this user
  4254. // disconnects/logs out.
  4255. //
  4256. if (result) {
  4257. if (!RDPDRUTL_PrinterIsTS(SavedDefaultPrinterName)) {
  4258. result = SavePrinterNameAsGlobalDefault(SavedDefaultPrinterName);
  4259. }
  4260. }
  4261. else {
  4262. DBGMSG(DBG_ERROR, ("UMRDPPRN: Error fetching def printer: %ld.\n",
  4263. status));
  4264. }
  4265. DBGMSG(DBG_TRACE, ("UMRDPPRN: SaveDefaultPrinterContext exiting.\n"));
  4266. Exit:
  4267. return result;
  4268. }
  4269. BOOL
  4270. SavePrinterNameAsGlobalDefault(
  4271. IN PCWSTR printerName
  4272. )
  4273. /*++
  4274. Routine Description:
  4275. Save the specified printer in the registry so it is visible to all
  4276. other sessions for this user as the last known default printer.
  4277. Arguments:
  4278. printerName - Printer name.
  4279. Return Value:
  4280. TRUE is returned on success. Otherwise, FALSE is returned and
  4281. GetLastError() can be used for retrieving extended error information.
  4282. --*/
  4283. {
  4284. BOOL result;
  4285. WCHAR *sidAsText = NULL;
  4286. HKEY regKey = NULL;
  4287. DWORD sz;
  4288. PSID pSid;
  4289. DWORD status;
  4290. DBGMSG(DBG_TRACE, ("UMRDPPRN: SavePrinterNameAsGlobalDefault entered.\n"));
  4291. //
  4292. // Get the user's SID. This is how we uniquely identify the user.
  4293. //
  4294. pSid = TSNUTL_GetUserSid(UMRPDPPRN_TokenForLoggedOnUser);
  4295. result = pSid != NULL;
  4296. //
  4297. // Get a textual representation of the session user's SID.
  4298. //
  4299. if (result) {
  4300. sz = 0;
  4301. result = TSNUTL_GetTextualSid(pSid, NULL, &sz);
  4302. ASSERT(!result);
  4303. if (!result && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  4304. sidAsText = (WCHAR *)ALLOCMEM(sz);
  4305. if (sidAsText != NULL) {
  4306. result = TSNUTL_GetTextualSid(pSid, sidAsText, &sz);
  4307. }
  4308. }
  4309. }
  4310. //
  4311. // Open the reg key.
  4312. //
  4313. if (result) {
  4314. status = RegCreateKey(
  4315. HKEY_LOCAL_MACHINE, USERDEFAULTPRNREGKEY,
  4316. &regKey
  4317. );
  4318. result = status == ERROR_SUCCESS;
  4319. if (!result) {
  4320. DBGMSG(DBG_ERROR, ("UMRDPPRN: RegCreateKey failed for %s: %ld.\n",
  4321. USERDEFAULTPRNREGKEY, status));
  4322. }
  4323. }
  4324. //
  4325. // Write the value for the default printer.
  4326. //
  4327. if (result) {
  4328. sz = (wcslen(printerName) + 1) * sizeof(WCHAR);
  4329. status = RegSetValueEx(regKey, sidAsText, 0, REG_SZ, (PBYTE)printerName, sz);
  4330. result = status == ERROR_SUCCESS;
  4331. if (!result) {
  4332. DBGMSG(DBG_ERROR, ("UMRDPPRN: RegSetValueEx failed for %s: %ld.\n",
  4333. sidAsText, status));
  4334. }
  4335. }
  4336. //
  4337. // Clean up.
  4338. //
  4339. if (sidAsText != NULL) FREEMEM(sidAsText);
  4340. if (regKey != NULL) RegCloseKey(regKey);
  4341. if (pSid != NULL) FREEMEM(pSid);
  4342. DBGMSG(DBG_TRACE, ("UMRDPPRN: SavePrinterNameAsGlobalDefault exiting.\n"));
  4343. return result;
  4344. }
  4345. BOOL
  4346. RestoreDefaultPrinterContext()
  4347. /*++
  4348. Routine Description:
  4349. Restore the most recent default printer context, as saved via a call to
  4350. SaveDefaultPrinterContext.
  4351. Arguments:
  4352. Return Value:
  4353. TRUE is returned on success. Otherwise, FALSE is returned and
  4354. GetLastError() can be used for retrieving extended error information.
  4355. --*/
  4356. {
  4357. BOOL result;
  4358. HANDLE hPrinter;
  4359. PRINTER_DEFAULTS printerDefaults = {NULL, NULL, PRINTER_ACCESS_USE};
  4360. WCHAR *sidAsText = NULL;
  4361. HKEY regKey = NULL;
  4362. DWORD sz;
  4363. PSID pSid = NULL;
  4364. DWORD status;
  4365. WCHAR savedDefaultPrinter[MAX_PATH];
  4366. WCHAR *nameToRestore = NULL;
  4367. DBGMSG(DBG_TRACE, ("UMRDPPRN: RestoreDefaultPrinterContext entered.\n"));
  4368. //
  4369. // Assume that we will succeed.
  4370. //
  4371. result = TRUE;
  4372. //
  4373. // Restore the default printer name stored in RAM, if it exists.
  4374. //
  4375. if (wcscmp(SavedDefaultPrinterName, L"") &&
  4376. OpenPrinter(SavedDefaultPrinterName, &hPrinter, &printerDefaults)) {
  4377. ClosePrinter(hPrinter);
  4378. nameToRestore = &SavedDefaultPrinterName[0];
  4379. }
  4380. //
  4381. // If the default printer name saved in RAM does not exist, then we need
  4382. // to save the one that is saved in the registry, if it exists.
  4383. //
  4384. if (nameToRestore == NULL) {
  4385. BOOL intermediateResult;
  4386. //
  4387. // Get the user's SID. This is how we uniquely identify the user.
  4388. //
  4389. pSid = TSNUTL_GetUserSid(UMRPDPPRN_TokenForLoggedOnUser);
  4390. intermediateResult = pSid != NULL;
  4391. //
  4392. // Get a textual representation of the session user's SID.
  4393. //
  4394. if (intermediateResult) {
  4395. sz = 0;
  4396. intermediateResult = TSNUTL_GetTextualSid(pSid, NULL, &sz);
  4397. ASSERT(!intermediateResult);
  4398. if (!intermediateResult && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  4399. sidAsText = (WCHAR *)ALLOCMEM(sz);
  4400. if (sidAsText != NULL) {
  4401. intermediateResult = TSNUTL_GetTextualSid(pSid, sidAsText, &sz);
  4402. }
  4403. }
  4404. }
  4405. //
  4406. // Open the reg key.
  4407. //
  4408. if (intermediateResult) {
  4409. status = RegCreateKey(
  4410. HKEY_LOCAL_MACHINE, USERDEFAULTPRNREGKEY,
  4411. &regKey
  4412. );
  4413. intermediateResult = status == ERROR_SUCCESS;
  4414. if (!intermediateResult) {
  4415. DBGMSG(DBG_ERROR, ("UMRDPPRN: RegCreateKey failed for %s: %ld.\n",
  4416. USERDEFAULTPRNREGKEY, status));
  4417. }
  4418. }
  4419. //
  4420. // Read the value.
  4421. //
  4422. if (intermediateResult) {
  4423. DWORD type;
  4424. DWORD sz = sizeof(savedDefaultPrinter);
  4425. status = RegQueryValueEx(
  4426. regKey, sidAsText, 0,
  4427. &type, (PBYTE)savedDefaultPrinter, &sz
  4428. );
  4429. if (status == ERROR_SUCCESS) {
  4430. intermediateResult = TRUE;
  4431. ASSERT(type == REG_SZ);
  4432. nameToRestore = savedDefaultPrinter;
  4433. }
  4434. }
  4435. //
  4436. // If we got a value, then that means we will be restoring the
  4437. // one from the registry. That also means that we should whack the
  4438. // registry value to be a good citizen.
  4439. //
  4440. if (intermediateResult) {
  4441. status = RegDeleteValue(regKey, sidAsText);
  4442. if (status != ERROR_SUCCESS) {
  4443. DBGMSG(DBG_ERROR, ("UMRDPPRN: Can't delete reg value %s: %ld\n",
  4444. sidAsText, status));
  4445. }
  4446. }
  4447. }
  4448. //
  4449. // If we have a name to restore, then do so.
  4450. //
  4451. if (nameToRestore != NULL) {
  4452. BOOL fImpersonated = FALSE;
  4453. //
  4454. //impersonate before setting the default printer as the api
  4455. //accesses hkcu. If the impersonation fails, the api will fail
  4456. //and we will log an error. But, before logging an error, we will
  4457. //need to revert to self.
  4458. //
  4459. if (!(fImpersonated = ImpersonateLoggedOnUser(UMRPDPPRN_TokenForLoggedOnUser))) {
  4460. DBGMSG(DBG_TRACE, ("UMRDPDR:ImpersonateLoggedOnUser failed. Error:%ld.\n", GetLastError()));
  4461. }
  4462. result = SetDefaultPrinter(nameToRestore);
  4463. //
  4464. //if revert to self fails, consider it fatal
  4465. //
  4466. if (fImpersonated && !RevertToSelf()) {
  4467. DBGMSG(DBG_TRACE, ("UMRDPDR:RevertToSelf failed. Error:%ld.\n", GetLastError()));
  4468. result = FALSE;
  4469. }
  4470. if (!result) {
  4471. WCHAR * param = nameToRestore;
  4472. TsLogError(EVENT_NOTIFY_SETDEFAULTPRINTER_FAILED,
  4473. EVENTLOG_ERROR_TYPE,
  4474. 1,
  4475. &param,
  4476. __LINE__);
  4477. }
  4478. }
  4479. //
  4480. // If we don't have a name to restore of the restore failed, then
  4481. // just restore the first printer we find.
  4482. //
  4483. if (nameToRestore == NULL) {
  4484. //
  4485. // If we still don't have a printer name to restore, then we should
  4486. // just restore the first printer we find.
  4487. //
  4488. result = SetDefaultPrinterToFirstFound(TRUE);
  4489. }
  4490. //
  4491. // Clean up.
  4492. //
  4493. if (sidAsText != NULL) FREEMEM(sidAsText);
  4494. if (regKey != NULL) RegCloseKey(regKey);
  4495. if (pSid != NULL) FREEMEM(pSid);
  4496. DBGMSG(DBG_TRACE, ("UMRDPPRN: RestoreDefaultPrinterContext exiting.\n"));
  4497. return result;
  4498. }
  4499. BOOL SplitName(
  4500. IN OUT LPTSTR pszFullName,
  4501. OUT LPCTSTR *ppszServer,
  4502. OUT LPCTSTR *ppszPrinter,
  4503. IN BOOL bCheckDoubleSlash)
  4504. /*++
  4505. Splits a fully qualified printer connection name into server and
  4506. printer name parts. If the function fails then none of the OUT
  4507. parameters are modified.
  4508. Arguments:
  4509. pszFullName - Input name of a printer. If it is a printer
  4510. connection (\\server\printer), then we will split it.
  4511. ppszServer - Receives pointer to the server string.
  4512. ppszPrinter - Receives a pointer to the printer string.
  4513. bCheckDoubleSlash - if TRUE check that the name begins with "\\".
  4514. If FALSE, the first character is the first character of the server.
  4515. Return Value: TRUE if everything is found as expected. FALSE otherwise.
  4516. --*/
  4517. {
  4518. LPTSTR pszPrinter;
  4519. LPTSTR pszTmp;
  4520. if (bCheckDoubleSlash) {
  4521. if (pszFullName[0] == TEXT('!') && pszFullName[1] == TEXT('!')) {
  4522. pszTmp = pszFullName + 2;
  4523. } else {
  4524. return FALSE;
  4525. }
  4526. } else {
  4527. pszTmp = pszFullName;
  4528. }
  4529. pszPrinter = wcschr(pszTmp, TEXT('!'));
  4530. if (pszPrinter)
  4531. {
  4532. //
  4533. // We found the backslash; null terminate the previous
  4534. // name.
  4535. //
  4536. *pszPrinter++ = 0;
  4537. *ppszServer = pszTmp;
  4538. *ppszPrinter = pszPrinter;
  4539. return TRUE;
  4540. }
  4541. return FALSE;
  4542. }
  4543. void FormatPrinterName(
  4544. PWSTR pszNewNameBuf,
  4545. ULONG ulBufLen,
  4546. ULONG ulFlags,
  4547. PTS_PRINTER_NAMES pPrinterNames)
  4548. {
  4549. WCHAR szSessionId[MAXSESSIONIDCHARS];
  4550. PWSTR pszRet = NULL;
  4551. PWSTR pszFormat;
  4552. DWORD dwBytes = 0;
  4553. const WCHAR * pStrings[4];
  4554. lstrcpyn(pPrinterNames->szTemp, pPrinterNames->pszFullName, pPrinterNames->ulTempLen);
  4555. // TS and network printer: \\Server\Client\Printer
  4556. // non TS network printer: \\Server\Printer
  4557. // TS non network printer: \\Client\Printer
  4558. if (ulFlags & RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER) {
  4559. if (SplitName(pPrinterNames->szTemp,
  4560. &(pPrinterNames->pszServer),
  4561. &(pPrinterNames->pszPrinter),
  4562. TRUE)) {
  4563. // We found a Server name, in any case we'll have
  4564. // something like "Printer on Server (from...)".
  4565. pszFormat = g_szOnFromFormat;
  4566. if (ulFlags & RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER ) {
  4567. if(!SplitName((PWSTR)(pPrinterNames->pszPrinter),
  4568. &(pPrinterNames->pszClient),
  4569. &(pPrinterNames->pszPrinter),
  4570. FALSE)) {
  4571. // The original client name could not be found,
  4572. // use the curent one.
  4573. pPrinterNames->pszClient = pPrinterNames->pszCurrentClient;
  4574. }
  4575. } else {
  4576. pPrinterNames->pszClient = pPrinterNames->pszCurrentClient;
  4577. }
  4578. } else {
  4579. // The name of the server could not be found!
  4580. // Use the original name.
  4581. pszFormat = g_szFromFormat;
  4582. pPrinterNames->pszPrinter = pPrinterNames->pszFullName;
  4583. pPrinterNames->pszClient = pPrinterNames->pszCurrentClient;
  4584. }
  4585. } else {
  4586. // It's not a network printer, so we'll have
  4587. // something like "Printer (from Client)".
  4588. pszFormat = g_szFromFormat;
  4589. if (ulFlags & RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER ) {
  4590. if(!SplitName(pPrinterNames->szTemp,
  4591. &(pPrinterNames->pszClient),
  4592. &(pPrinterNames->pszPrinter),
  4593. TRUE)) {
  4594. pPrinterNames->pszPrinter = pPrinterNames->pszFullName;
  4595. pPrinterNames->pszClient = pPrinterNames->pszCurrentClient;
  4596. }
  4597. } else {
  4598. pPrinterNames->pszPrinter = pPrinterNames->pszFullName;
  4599. pPrinterNames->pszClient = pPrinterNames->pszCurrentClient;
  4600. }
  4601. }
  4602. pStrings[0] = pPrinterNames->pszPrinter;
  4603. pStrings[1] = pPrinterNames->pszServer;
  4604. pStrings[2] = pPrinterNames->pszClient;
  4605. if (g_fIsPTS) {
  4606. pStrings[3] = NULL;
  4607. } else {
  4608. wsprintf(szSessionId, L"%ld", GETTHESESSIONID());
  4609. pStrings[3] = szSessionId;
  4610. }
  4611. if (*pszFormat) {
  4612. DBGMSG(DBG_TRACE, ("UMRDPPRN:formating %ws, %ws and %ws\n", pStrings[0], pStrings[1],
  4613. pStrings[2]?pStrings[2]:L""));
  4614. dwBytes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  4615. FORMAT_MESSAGE_FROM_STRING |
  4616. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4617. pszFormat,
  4618. 0,
  4619. 0,
  4620. (LPTSTR)&pszRet,
  4621. 0,
  4622. (va_list*)pStrings);
  4623. DBGMSG(DBG_TRACE, ("UMRDPPRN:formated %ws\n", pszRet));
  4624. }
  4625. //
  4626. // Copy the new name.
  4627. //
  4628. if ( dwBytes && pszRet ) {
  4629. wcsncpy(pszNewNameBuf, pszRet, ulBufLen);
  4630. } else {
  4631. wcsncpy(pszNewNameBuf, pPrinterNames->pszFullName, ulBufLen);
  4632. }
  4633. pszNewNameBuf[ulBufLen] = L'\0';
  4634. //
  4635. // Release the formated string.
  4636. //
  4637. if( pszRet ) {
  4638. LocalFree(pszRet);
  4639. }
  4640. }