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.

7764 lines
250 KiB

  1. /*++
  2. Copyright (c) 1990 - 1996 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. init.c
  6. Abstract:
  7. This module has all the initialization functions for the Local Print Provider
  8. Author:
  9. Dave Snipp (DaveSn) 15-Mar-1991
  10. Revision History:
  11. Felix Maxa (amaxa) 18-Jun-2000
  12. Modified SplCreateSpooler to special case cluster pIniSpooler
  13. Modified LoadPrintProcessor to be able to copy the print processor
  14. from the cluster disk
  15. Added SplCreateSpoolerWorkerThread
  16. ClusterAddDriversFromClusterDisk
  17. ClusterAddVersionDrivers
  18. ClusterAddOrUpdateDriverFromClusterDisk, all part of the DCR
  19. regarding installing rpinter drivers on clusters
  20. Adina Trufinescu (adinatru) 07-December 1998
  21. Commented InitializePrintMonitor2 ;
  22. Changed back to the old interface - InitializePrintMonitor - which is defined in localmon.c
  23. Khaled Sedky (khaleds) 1-September 1998
  24. Modified InitializePrintProcessor amd added LoadPrintProcessor
  25. as a result of merging winprint and localspl
  26. Steve Wilson (swilson) 1-November 1996
  27. Added ShadowFile2 so spooler can delete crashing shadowfiles.
  28. Muhunthan Sivapragasam (MuhuntS) 1-June-1995
  29. Driver info 3 changes; Changes to use RegGetString, RegGetDword etc
  30. Matthew A Felton (MattFe) 27-June-1994
  31. pIniSpooler - allow other providers to call the spooler functions in LocalSpl
  32. --*/
  33. #include <precomp.h>
  34. #pragma hdrstop
  35. #include <lm.h>
  36. #include <winbasep.h>
  37. #include <faxreg.h>
  38. #include "clusspl.h"
  39. #include "jobid.h"
  40. #include "filepool.hxx"
  41. MODULE_DEBUG_INIT( DBG_ERROR , DBG_ERROR );
  42. UINT gcClusterIniSpooler = 0;
  43. #if DBG
  44. HANDLE ghbtClusterRef = 0;
  45. #endif
  46. MONITORREG gMonitorReg = {
  47. sizeof( MONITORREG ),
  48. &SplRegCreateKey,
  49. &SplRegOpenKey,
  50. &SplRegCloseKey,
  51. &SplRegDeleteKey,
  52. &SplRegEnumKey,
  53. &SplRegQueryInfoKey,
  54. &SplRegSetValue,
  55. &SplRegDeleteValue,
  56. &SplRegEnumValue,
  57. &SplRegQueryValue
  58. };
  59. VOID
  60. SplCreateSpoolerWorkerThread(
  61. PVOID pv
  62. );
  63. DWORD
  64. ClusterAddOrUpdateDriverFromClusterDisk(
  65. HKEY hVersionKey,
  66. LPCWSTR pszDriverName,
  67. LPCWSTR pszEnvName,
  68. LPCWSTR pszEnvDir,
  69. PINISPOOLER pIniSpooler
  70. );
  71. BOOL
  72. Old2NewShadow(
  73. PSHADOWFILE pShadowFile1,
  74. PSHADOWFILE_3 pShadowFile2,
  75. DWORD *pnBytes
  76. );
  77. VOID
  78. FreeIniVersion(
  79. PINIVERSION pIniVersion
  80. );
  81. BOOL
  82. NotIniSpooler(
  83. BYTE *pMem
  84. );
  85. PINIDRIVER
  86. GetDriverList(
  87. HKEY hVersionKey,
  88. PINISPOOLER pIniSpooler,
  89. PINIENVIRONMENT pIniEnvironment,
  90. PINIVERSION pIniVersion
  91. );
  92. PINIVERSION
  93. GetVersionDrivers(
  94. HKEY hDriversKey,
  95. LPWSTR VersionName,
  96. PINISPOOLER pIniSpooler,
  97. PINIENVIRONMENT pIniEnvironment
  98. );
  99. VOID
  100. GetPrintSystemVersion(
  101. PINISPOOLER pIniSpooler
  102. );
  103. VOID
  104. InitializeSpoolerSettings(
  105. PINISPOOLER pIniSpooler
  106. );
  107. VOID
  108. WaitForSpoolerInitialization(
  109. VOID
  110. );
  111. BOOL
  112. ValidateProductSuite(
  113. PWSTR SuiteName
  114. );
  115. LPWSTR
  116. FormatRegistryKeyForPrinter(
  117. LPWSTR pSource, /* The string from which backslashes are to be added. */
  118. LPWSTR pScratch /* Scratch buffer for the function to write in; */
  119. ); /* must be at least as long as pSource. */
  120. #define MAX_LENGTH_DRIVERS_SHARE_REMARK 256
  121. WCHAR *szSpoolDirectory = L"\\spool";
  122. WCHAR *szPrintShareName = L""; /* No share for printers in product1 */
  123. WCHAR *szPrintDirectory = L"\\printers";
  124. WCHAR *szDriversDirectory = L"\\drivers";
  125. WCHAR *gszNT4EMF = L"NT EMF 1.003";
  126. WCHAR *gszNT5EMF = L"NT EMF 1.008";
  127. SHARE_INFO_2 DriversShareInfo={NULL, /* Netname - initialized below */
  128. STYPE_DISKTREE, /* Type of share */
  129. NULL, /* Remark */
  130. 0, /* Default permissions */
  131. SHI_USES_UNLIMITED, /* No users limit */
  132. SHI_USES_UNLIMITED, /* Current uses (??) */
  133. NULL, /* Path - initialized below */
  134. NULL}; /* No password */
  135. // WARNING
  136. // Do not access these directly always go via pIniSpooler->pszRegistr...
  137. // This will then work for multiple pIniSpoolers
  138. PWCHAR ipszRoot = L"Print";
  139. PWCHAR ipszRegistryRoot = L"System\\CurrentControlSet\\Control\\Print";
  140. PWCHAR ipszRegistryPrinters = L"System\\CurrentControlSet\\Control\\Print\\Printers";
  141. PWCHAR ipszRegSwPrinters = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers";
  142. PWCHAR ipszRegistryMonitors = L"Monitors";
  143. PWCHAR ipszRegistryMonitorsHKLM = L"\\System\\CurrentControlSet\\Control\\Print\\Monitors";
  144. PWCHAR ipszRegistryEnvironments = L"System\\CurrentControlSet\\Control\\Print\\Environments";
  145. PWCHAR ipszClusterDatabaseEnvironments = L"Environments";
  146. PWCHAR ipszRegistryEventLog = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\Print";
  147. PWCHAR ipszRegistryProviders = L"Providers";
  148. PWCHAR ipszEventLogMsgFile = L"%SystemRoot%\\System32\\LocalSpl.dll";
  149. PWCHAR ipszDriversShareName = L"print$";
  150. PWCHAR ipszRegistryForms = L"System\\CurrentControlSet\\Control\\Print\\Forms";
  151. PWCHAR ipszRegistryProductOptions = L"System\\CurrentControlSet\\Control\\ProductOptions";
  152. PWCHAR ipszRegistryWin32Root = L"System\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Servers";
  153. PWCHAR ipszRegistryClusRepository = SPLREG_CLUSTER_LOCAL_ROOT_KEY;
  154. WCHAR *szPrinterData = L"PrinterDriverData";
  155. WCHAR *szConfigurationKey = L"Configuration File";
  156. WCHAR *szDataFileKey = L"Data File";
  157. WCHAR *szDriverVersion = L"Version";
  158. WCHAR *szTempDir = L"TempDir";
  159. WCHAR *szDriverAttributes = L"DriverAttributes";
  160. WCHAR *szDriversKey = L"Drivers";
  161. WCHAR *szPrintProcKey = L"Print Processors";
  162. WCHAR *szPrintersKey = L"Printers";
  163. WCHAR *szEnvironmentsKey = L"Environments";
  164. WCHAR *szDirectory = L"Directory";
  165. WCHAR *szDriverIni = L"Drivers.ini";
  166. WCHAR *szDriverFile = L"Driver";
  167. WCHAR *szDriverDir = L"DRIVERS";
  168. WCHAR *szPrintProcDir = L"PRTPROCS";
  169. WCHAR *szPrinterDir = L"PRINTERS";
  170. WCHAR *szClusterPrinterDir= L"Spool";
  171. WCHAR *szPrinterIni = L"\\printer.ini";
  172. WCHAR *szAllSpools = L"\\*.SPL";
  173. WCHAR *szNullPort = L"NULL";
  174. WCHAR *szComma = L",";
  175. WCHAR *szName = L"Name";
  176. WCHAR *szShare = L"Share Name";
  177. WCHAR *szPort = L"Port";
  178. WCHAR *szPrintProcessor = L"Print Processor";
  179. WCHAR *szDatatype = L"Datatype";
  180. WCHAR *szDriver = L"Printer Driver";
  181. WCHAR *szLocation = L"Location";
  182. WCHAR *szDescription = L"Description";
  183. WCHAR *szAttributes = L"Attributes";
  184. WCHAR *szStatus = L"Status";
  185. WCHAR *szPriority = L"Priority";
  186. WCHAR *szDefaultPriority = L"Default Priority";
  187. WCHAR *szUntilTime = L"UntilTime";
  188. WCHAR *szStartTime = L"StartTime";
  189. WCHAR *szParameters = L"Parameters";
  190. WCHAR *szSepFile = L"Separator File";
  191. WCHAR *szDevMode = L"Default DevMode";
  192. WCHAR *szSecurity = L"Security";
  193. WCHAR *szSpoolDir = L"SpoolDirectory";
  194. WCHAR *szNetMsgDll = L"NETMSG.DLL";
  195. WCHAR *szMajorVersion = L"MajorVersion";
  196. WCHAR *szMinorVersion = L"MinorVersion";
  197. WCHAR *szTimeLastChange = L"ChangeID";
  198. WCHAR *szHelpFile = L"Help File";
  199. WCHAR *szMonitor = L"Monitor";
  200. WCHAR *szDependentFiles = L"Dependent Files";
  201. WCHAR *szPreviousNames = L"Previous Names";
  202. WCHAR *szDNSTimeout = L"dnsTimeout";
  203. WCHAR *szTXTimeout = L"txTimeout";
  204. WCHAR *szNTFaxDriver = FAX_DRIVER_NAME;
  205. WCHAR *szObjectGUID = L"ObjectGUID";
  206. WCHAR *szDsKeyUpdate = L"DsKeyUpdate";
  207. WCHAR *szDsKeyUpdateForeground = L"DsKeyUpdateForeground";
  208. WCHAR *szAction = L"Action";
  209. WCHAR *szMfgName = L"Manufacturer";
  210. WCHAR *szOEMUrl = L"OEM URL";
  211. WCHAR *szHardwareID = L"HardwareID";
  212. WCHAR *szProvider = L"Provider";
  213. WCHAR *szDriverDate = L"DriverDate";
  214. WCHAR *szLongVersion = L"DriverVersion";
  215. WCHAR *szClusDrvTimeStamp = L"TimeStamp";
  216. const WCHAR szDiscardTSJobs[] = L"DiscardTSJobs";
  217. const WCHAR szDisableFilePooling[] = L"DisableServerFilePooling";
  218. WCHAR *szRegistryRoot = L"System\\CurrentControlSet\\Control\\Print";
  219. WCHAR *szEMFThrottle = L"EMFThrottle";
  220. WCHAR *szFlushShadowFileBuffers = L"FlushShadowFileBuffers";
  221. WCHAR *szPendingUpgrades = L"PendingUpgrades";
  222. WCHAR *szPrintPublishPolicy = L"Software\\Policies\\Microsoft\\Windows NT\\Printers";
  223. WCHAR *szClusterDriverRoot = L"PrinterDrivers";
  224. WCHAR *szClusterNonAwareMonitors = L"OtherMonitors";
  225. #if DBG
  226. WCHAR *szDebugFlags = L"DebugFlags";
  227. #endif
  228. WCHAR *szEnvironment = LOCAL_ENVIRONMENT;
  229. WCHAR *szWin95Environment = L"Windows 4.0";
  230. const WCHAR gszCacheMasqPrinters[] = L"CacheMasqPrinters";
  231. HANDLE hInst;
  232. // Time before a job is assumed abandond and deleted during FastPrint
  233. // operation
  234. DWORD dwFastPrintWaitTimeout = FASTPRINT_WAIT_TIMEOUT;
  235. DWORD dwSpoolerPriority = THREAD_PRIORITY_NORMAL;
  236. DWORD dwPortThreadPriority = DEFAULT_PORT_THREAD_PRIORITY;
  237. DWORD dwSchedulerThreadPriority = DEFAULT_SCHEDULER_THREAD_PRIORITY;
  238. DWORD dwFastPrintThrottleTimeout = FASTPRINT_THROTTLE_TIMEOUT;
  239. DWORD dwFastPrintSlowDownThreshold = FASTPRINT_SLOWDOWN_THRESHOLD;
  240. DWORD dwServerThreadPriority = DEFAULT_SERVER_THREAD_PRIORITY;
  241. DWORD dwEnableBroadcastSpoolerStatus = 0;
  242. // NT 3.1 No Version ( Version 0 ) User Mode
  243. // NT 3.5 and 3.51 Version 1 User Mode
  244. // NT 4.0 Version 2 Kernel Mode
  245. DWORD dwMajorVersion = SPOOLER_VERSION;
  246. DWORD dwMinorVersion = 0;
  247. // Unique Printer ID counter which increases monotonically. Wraps at 4G.
  248. DWORD dwUniquePrinterSessionID = 0;
  249. // Globals for EMF job scheduling
  250. DWORD dwNumberOfEMFJobsRendering = 0;
  251. BOOL bUseEMFScheduling = FALSE;
  252. SIZE_T TotalMemoryForRendering = 0;
  253. SIZE_T AvailMemoryForRendering = 0;
  254. DWORD dwLastScheduleTime = 0;
  255. PJOBDATA pWaitingList = NULL;
  256. PJOBDATA pScheduleList = NULL;
  257. DWORD dwFlushShadowFileBuffers = 0; // default for uninitialized
  258. // Time to sleep if the LocalWritePrinter WritePort doesn't write any bytes
  259. // but still returns success.
  260. DWORD dwWritePrinterSleepTime = WRITE_PRINTER_SLEEP_TIME;
  261. BOOL gbRemoteFax = TRUE;
  262. BOOL Initialized = FALSE;
  263. PINISPOOLER pLocalIniSpooler = NULL;
  264. PINIENVIRONMENT pThisEnvironment = NULL;
  265. #define POOL_TIMEOUT 120000 // 2 minutes
  266. #define MAX_POOL_FILES 50
  267. //
  268. // Allowing remote connection policy.
  269. //
  270. ERemoteRPCEndPointPolicy gRemoteRPCEndPointPolicy;
  271. //
  272. // Global for KM Printers Blocking Policy
  273. // by default it is
  274. // 1 "blocked" for Server and
  275. // 0 "not blocked" for Workstation
  276. //
  277. DWORD DefaultKMPrintersAreBlocked;
  278. //
  279. // Read from the registry if the HKLM\...\Print\ServerInstallTimeOut DWORD entry exists
  280. // Otherwise default 5 mins.
  281. //
  282. DWORD gdwServerInstallTimeOut;
  283. //
  284. // 0 - Not upgrading, 1 - performing upgrade
  285. //
  286. DWORD dwUpgradeFlag = 0;
  287. LPWSTR szRemoteDoc;
  288. LPWSTR szLocalDoc;
  289. LPWSTR szFastPrintTimeout;
  290. LPWSTR szRaw = L"RAW";
  291. PRINTPROVIDOR PrintProvidor = {LocalOpenPrinter,
  292. LocalSetJob,
  293. LocalGetJob,
  294. LocalEnumJobs,
  295. LocalAddPrinter,
  296. SplDeletePrinter,
  297. SplSetPrinter,
  298. SplGetPrinter,
  299. LocalEnumPrinters,
  300. LocalAddPrinterDriver,
  301. LocalEnumPrinterDrivers,
  302. SplGetPrinterDriver,
  303. LocalGetPrinterDriverDirectory,
  304. LocalDeletePrinterDriver,
  305. LocalAddPrintProcessor,
  306. LocalEnumPrintProcessors,
  307. LocalGetPrintProcessorDirectory,
  308. LocalDeletePrintProcessor,
  309. LocalEnumPrintProcessorDatatypes,
  310. LocalStartDocPrinter,
  311. LocalStartPagePrinter,
  312. LocalWritePrinter,
  313. LocalEndPagePrinter,
  314. LocalAbortPrinter,
  315. LocalReadPrinter,
  316. LocalEndDocPrinter,
  317. LocalAddJob,
  318. LocalScheduleJob,
  319. SplGetPrinterData,
  320. SplSetPrinterData,
  321. LocalWaitForPrinterChange,
  322. SplClosePrinter,
  323. SplAddForm,
  324. SplDeleteForm,
  325. SplGetForm,
  326. SplSetForm,
  327. SplEnumForms,
  328. LocalEnumMonitors,
  329. LocalEnumPorts,
  330. LocalAddPort,
  331. LocalConfigurePort,
  332. LocalDeletePort,
  333. LocalCreatePrinterIC,
  334. LocalPlayGdiScriptOnPrinterIC,
  335. LocalDeletePrinterIC,
  336. LocalAddPrinterConnection,
  337. LocalDeletePrinterConnection,
  338. LocalPrinterMessageBox,
  339. LocalAddMonitor,
  340. LocalDeleteMonitor,
  341. SplResetPrinter,
  342. SplGetPrinterDriverEx,
  343. LocalFindFirstPrinterChangeNotification,
  344. LocalFindClosePrinterChangeNotification,
  345. LocalAddPortEx,
  346. NULL,
  347. LocalRefreshPrinterChangeNotification,
  348. LocalOpenPrinterEx,
  349. LocalAddPrinterEx,
  350. LocalSetPort,
  351. SplEnumPrinterData,
  352. SplDeletePrinterData,
  353. SplClusterSplOpen,
  354. SplClusterSplClose,
  355. SplClusterSplIsAlive,
  356. SplSetPrinterDataEx,
  357. SplGetPrinterDataEx,
  358. SplEnumPrinterDataEx,
  359. SplEnumPrinterKey,
  360. SplDeletePrinterDataEx,
  361. SplDeletePrinterKey,
  362. LocalSeekPrinter,
  363. LocalDeletePrinterDriverEx,
  364. LocalAddPerMachineConnection,
  365. LocalDeletePerMachineConnection,
  366. LocalEnumPerMachineConnections,
  367. LocalXcvData,
  368. LocalAddPrinterDriverEx,
  369. SplReadPrinter,
  370. LocalDriverUnloadComplete,
  371. LocalGetSpoolFileHandle,
  372. LocalCommitSpoolData,
  373. LocalCloseSpoolFileHandle,
  374. LocalFlushPrinter,
  375. LocalSendRecvBidiData,
  376. LocalAddDriverCatalog,
  377. };
  378. DWORD
  379. FinalInitAfterRouterInitCompleteThread(
  380. DWORD dwUpgrade
  381. );
  382. #if DBG
  383. VOID
  384. InitializeDebug(
  385. PINISPOOLER pIniSpooler
  386. );
  387. PDBG_POINTERS
  388. DbgSplGetPointers(
  389. VOID
  390. );
  391. #endif
  392. BOOL
  393. DllMain(
  394. HANDLE hModule,
  395. DWORD dwReason,
  396. LPVOID lpRes
  397. )
  398. {
  399. BOOL bRet = TRUE;
  400. switch(dwReason) {
  401. case DLL_PROCESS_ATTACH:
  402. DisableThreadLibraryCalls(hModule);
  403. hInst = hModule;
  404. bRet = InitializeLocalspl();
  405. if (bRet)
  406. {
  407. bRet = LocalMonInit(hInst);
  408. }
  409. break;
  410. case DLL_PROCESS_DETACH :
  411. ShutdownPorts( pLocalIniSpooler );
  412. break;
  413. default:
  414. break;
  415. }
  416. return bRet;
  417. UNREFERENCED_PARAMETER( lpRes );
  418. }
  419. BOOL
  420. InitializeLocalspl(
  421. VOID
  422. )
  423. {
  424. BOOL bRet = TRUE;
  425. #if DBG
  426. gpDbgPointers = DbgGetPointers();
  427. if( gpDbgPointers ){
  428. hcsSpoolerSection = gpDbgPointers->pfnAllocCritSec();
  429. SPLASSERT( hcsSpoolerSection );
  430. ghbtClusterRef = gpDbgPointers->pfnAllocBackTrace();
  431. }
  432. if( !hcsSpoolerSection ){
  433. //
  434. // Must be using the free version of spoolss.dll.
  435. //
  436. bRet = InitializeCriticalSectionAndSpinCount(&SpoolerSection, 0x80000000);
  437. }
  438. #else
  439. bRet = InitializeCriticalSectionAndSpinCount(&SpoolerSection, 0x80000000);
  440. #endif
  441. return bRet;
  442. }
  443. VOID
  444. SplDeleteSpoolerThread(
  445. PVOID pv
  446. )
  447. {
  448. PINIPORT pIniPort;
  449. PINIPORT pIniPortNext;
  450. PINIMONITOR pIniMonitor;
  451. PINIMONITOR pIniMonitorNext;
  452. PSHARE_INFO_2 pShareInfo;
  453. PINISPOOLER pIniSpooler = (PINISPOOLER)pv;
  454. //
  455. // Remove the cache entry associated with this pIniSpooler. At this time the pIniSpooler
  456. // is in pending deletion, so nobody is using it anymore.
  457. //
  458. CacheDeleteNode(pIniSpooler->pMachineName + 2);
  459. EnterSplSem();
  460. //
  461. // Cleanup the port monitors.
  462. //
  463. ShutdownMonitors( pIniSpooler );
  464. //
  465. // Close Cluster Access Token
  466. //
  467. if (pIniSpooler->hClusterToken != INVALID_HANDLE_VALUE)
  468. NtClose(pIniSpooler->hClusterToken);
  469. //
  470. // Delete All the Strings
  471. //
  472. FreeStructurePointers((LPBYTE)pIniSpooler, NULL, IniSpoolerOffsets);
  473. DeleteShared( pIniSpooler );
  474. //
  475. // Run all of the environments down if this isn't the local ini-spoolers
  476. // environment. This frees up the memory for all of the drivers and also
  477. // handles the driver ref-counts.
  478. //
  479. if (pIniSpooler->pIniEnvironment != pLocalIniSpooler->pIniEnvironment && pIniSpooler->pIniEnvironment) {
  480. PINIENVIRONMENT pIniEnvironment = NULL;
  481. PINIENVIRONMENT pNextEnvironment = NULL;
  482. for(pIniEnvironment = pIniSpooler->pIniEnvironment; pIniEnvironment; pIniEnvironment = pNextEnvironment) {
  483. pNextEnvironment = pIniEnvironment->pNext;
  484. FreeIniEnvironment(pIniEnvironment);
  485. }
  486. }
  487. //
  488. // Delete ports and monitors.
  489. //
  490. // Note that there is no reference counting here. By the time
  491. // we get here all jobs and printers should be deleted (otherwise
  492. // the pIniSpooler reference count would be != 0). Therefore,
  493. // even though we don't refcount ports and monitors, we should
  494. // be ok.
  495. //
  496. //
  497. // Remove all ports.
  498. //
  499. for( pIniPort = pIniSpooler->pIniPort;
  500. pIniPort;
  501. pIniPort = pIniPortNext ){
  502. pIniPortNext = pIniPort->pNext;
  503. if( !DeletePortEntry( pIniPort )){
  504. DBGMSG( DBG_ERROR,
  505. ( "Unable to delete port %ws %x %x %d",
  506. pIniPort->pName,
  507. GetMonitorHandle(pIniPort),
  508. pIniPort->Status,
  509. pIniPort->cJobs ));
  510. }
  511. }
  512. //
  513. // Remove all the monitors.
  514. //
  515. for( pIniMonitor = pIniSpooler->pIniMonitor;
  516. pIniMonitor;
  517. pIniMonitor = pIniMonitorNext ){
  518. pIniMonitorNext = pIniMonitor->pNext;
  519. if( !pIniMonitor->cRef ){
  520. FreeIniMonitor( pIniMonitor );
  521. }
  522. }
  523. //
  524. // Close cluster resource key handle.
  525. //
  526. if( pIniSpooler->hckRoot ){
  527. SplRegCloseKey( pIniSpooler->hckRoot, pIniSpooler );
  528. }
  529. //
  530. // Close cluster resource key handle.
  531. //
  532. if( pIniSpooler->hckPrinters ){
  533. SplRegCloseKey( pIniSpooler->hckPrinters, pIniSpooler );
  534. }
  535. //
  536. // Keep a counter of cluster pIniSpoolers.
  537. //
  538. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  539. --gcClusterIniSpooler;
  540. }
  541. //
  542. // Free the shared bitmap and shared driver info.
  543. //
  544. vDeleteJobIdMap( pIniSpooler->hJobIdMap );
  545. pShareInfo = (PSHARE_INFO_2)pIniSpooler->pDriversShareInfo;
  546. FreeSplStr( pShareInfo->shi2_remark );
  547. FreeSplStr( pShareInfo->shi2_path );
  548. FreeSplMem( pIniSpooler->pDriversShareInfo );
  549. LeaveSplSem();
  550. //
  551. // Shut down the file pool for this ini-spooler. It should not delete any of
  552. // the files.
  553. //
  554. if (pIniSpooler->hFilePool != INVALID_HANDLE_VALUE) {
  555. (VOID)DestroyFilePool(pIniSpooler->hFilePool, FALSE);
  556. }
  557. // Free this IniSpooler
  558. FreeSplMem( pIniSpooler );
  559. DBGMSG( DBG_WARN, ( "SplDeleteSpooler: Refcount 0 %x\n", pIniSpooler ));
  560. }
  561. BOOL
  562. SplDeleteSpooler(
  563. HANDLE hSpooler
  564. )
  565. {
  566. PINISPOOLER pIniSpooler = (PINISPOOLER) hSpooler;
  567. BOOL bReturn = FALSE;
  568. PINISPOOLER pCurrentIniSpooler = pLocalIniSpooler;
  569. HANDLE hThread;
  570. DWORD ThreadId;
  571. SplInSem();
  572. //
  573. // Whoever calls this must have deleted all the object associated with
  574. // this spooler, ie all printers etc, just make certain
  575. //
  576. if( pIniSpooler != pLocalIniSpooler ){
  577. //
  578. // Mark us as pending deletion.
  579. //
  580. pIniSpooler->SpoolerFlags |= SPL_PENDING_DELETION;
  581. DBGMSG(DBG_CLUSTER, ("SplDeleteSpooler: Deleting %x\n cRef %u\n", pIniSpooler, pIniSpooler->cRef ));
  582. //
  583. // pIniPrinters now acquire a reference to pIniSpooler.
  584. //
  585. if( pIniSpooler->cRef == 0 ){
  586. SPLASSERT( pIniSpooler->pIniPrinter == NULL );
  587. //( pIniSpooler->pIniPort == NULL ) &&
  588. //( pIniSpooler->pIniForm == NULL ) &&
  589. //( pIniSpooler->pIniMonitor == NULL ) &&
  590. //( pIniSpooler->pIniNetPrint == NULL ) &&
  591. //( pIniSpooler->pSpool == NULL ))
  592. //
  593. // Take this Spooler Off the Linked List if it's on it.
  594. //
  595. while (( pCurrentIniSpooler->pIniNextSpooler != NULL ) &&
  596. ( pCurrentIniSpooler->pIniNextSpooler != pIniSpooler )) {
  597. pCurrentIniSpooler = pCurrentIniSpooler->pIniNextSpooler;
  598. }
  599. //
  600. // May not be on the linked list if it was removed earlier by
  601. // clustering.
  602. //
  603. if( pCurrentIniSpooler->pIniNextSpooler ){
  604. SPLASSERT( pCurrentIniSpooler->pIniNextSpooler == pIniSpooler );
  605. pCurrentIniSpooler->pIniNextSpooler = pIniSpooler->pIniNextSpooler;
  606. }
  607. //
  608. // Hack for port monitors.
  609. //
  610. // Some monitors will call ClosePrinter, which deletes the very
  611. // last printer and allows the pIniSpooler to be destroyed.
  612. // Unfortunately, we call back to the monitors to close themselves
  613. // in the same thread, which the monitor does not support.
  614. //
  615. // Create a new thread and shut everything down.
  616. //
  617. if (hThread = CreateThread( NULL, 0,
  618. (LPTHREAD_START_ROUTINE)SplDeleteSpoolerThread,
  619. (PVOID)pIniSpooler,
  620. 0,
  621. &ThreadId ))
  622. {
  623. CloseHandle(hThread);
  624. }
  625. else
  626. {
  627. //
  628. // Bug 54840
  629. //
  630. // What do we do if we can't create a thread to shut down?
  631. // Sleep and retry?
  632. //
  633. DBGMSG(DBG_ERROR, ("Unable to create SplDeleteSpoolerThread\n"));
  634. }
  635. bReturn = TRUE;
  636. }
  637. }
  638. return bReturn;
  639. }
  640. BOOL
  641. SplCloseSpooler(
  642. HANDLE hSpooler
  643. )
  644. {
  645. PINISPOOLER pIniSpooler = (PINISPOOLER) hSpooler;
  646. EnterSplSem();
  647. if ((pIniSpooler == NULL) ||
  648. (pIniSpooler == INVALID_HANDLE_VALUE) ||
  649. (pIniSpooler == pLocalIniSpooler) ||
  650. (pIniSpooler->signature != ISP_SIGNATURE) ||
  651. (pIniSpooler->cRef == 0)) {
  652. SetLastError( ERROR_INVALID_HANDLE );
  653. DBGMSG(DBG_WARNING, ("SplCloseSpooler InvalidHandle %x\n", pIniSpooler ));
  654. LeaveSplSem();
  655. return FALSE;
  656. }
  657. DBGMSG(DBG_TRACE, ("SplCloseSpooler %x %ws cRef %d\n",pIniSpooler,
  658. pIniSpooler->pMachineName,
  659. pIniSpooler->cRef-1));
  660. DECSPOOLERREF( pIniSpooler );
  661. LeaveSplSem();
  662. return TRUE;
  663. }
  664. BOOL SplRegCopyTree(
  665. HKEY hDest,
  666. HKEY hSrc
  667. )
  668. /*++
  669. Function Description: Recursives copies every key and value from under hSrc to hDest
  670. Parameters: hDest - destination key
  671. hSrc - source key
  672. Return Value: TRUE if successful; FALSE otherwise
  673. --*/
  674. {
  675. BOOL bStatus = FALSE;
  676. DWORD dwError, dwIndex, cbValueName, cbData, cbKeyName, dwType;
  677. DWORD cKeys, cMaxValueNameLen, cMaxValueLen, cMaxKeyNameLen, cValues;
  678. LPBYTE lpValueName = NULL, lpData = NULL, lpKeyName = NULL;
  679. HKEY hSrcSubKey = NULL, hDestSubKey = NULL;
  680. //
  681. // Get the max key name length and value name length and data size for
  682. // allocating the buffers
  683. //
  684. if (dwError = RegQueryInfoKey( hSrc, NULL, NULL, NULL,
  685. &cKeys, &cMaxKeyNameLen, NULL,
  686. &cValues, &cMaxValueNameLen,
  687. &cMaxValueLen, NULL, NULL ))
  688. {
  689. SetLastError(dwError);
  690. goto CleanUp;
  691. }
  692. //
  693. // Adjust for the NULL char
  694. //
  695. ++cMaxValueNameLen;
  696. ++cMaxKeyNameLen;
  697. //
  698. // Allocate the buffers
  699. //
  700. lpValueName = AllocSplMem( cMaxValueNameLen * sizeof(WCHAR) );
  701. lpData = AllocSplMem( cMaxValueLen );
  702. lpKeyName = AllocSplMem( cMaxKeyNameLen * sizeof(WCHAR) );
  703. if (!lpValueName || !lpData || !lpKeyName)
  704. {
  705. goto CleanUp;
  706. }
  707. //
  708. // Copy all the values in the current key
  709. //
  710. for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
  711. {
  712. cbData = cMaxValueLen;
  713. cbValueName = cMaxValueNameLen;
  714. //
  715. // Retrieve the value name and the data
  716. //
  717. dwError = RegEnumValue( hSrc, dwIndex, (LPWSTR) lpValueName, &cbValueName,
  718. NULL, &dwType, lpData, &cbData );
  719. if (dwError)
  720. {
  721. SetLastError( dwError );
  722. goto CleanUp;
  723. }
  724. //
  725. // Set the value in the destination
  726. //
  727. dwError = RegSetValueEx( hDest, (LPWSTR) lpValueName, 0, dwType,
  728. lpData, cbData );
  729. if (dwError)
  730. {
  731. SetLastError( dwError );
  732. goto CleanUp;
  733. }
  734. }
  735. //
  736. // Recursively copies all the subkeys
  737. //
  738. for (dwIndex = 0; dwIndex < cKeys; ++dwIndex)
  739. {
  740. cbKeyName = cMaxKeyNameLen;
  741. //
  742. // Retrieve the key name
  743. //
  744. dwError = RegEnumKeyEx( hSrc, dwIndex, (LPWSTR) lpKeyName, &cbKeyName,
  745. NULL, NULL, NULL, NULL );
  746. if (dwError)
  747. {
  748. SetLastError( dwError );
  749. goto CleanUp;
  750. }
  751. //
  752. // Open the source subkey
  753. //
  754. if (dwError = RegOpenKeyEx( hSrc, (LPWSTR) lpKeyName, 0,
  755. KEY_READ, &hSrcSubKey ))
  756. {
  757. SetLastError( dwError );
  758. goto CleanUp;
  759. }
  760. //
  761. // Create the destination subkey
  762. //
  763. if (dwError = RegCreateKeyEx( hDest, (LPWSTR) lpKeyName, 0, NULL,
  764. REG_OPTION_VOLATILE, KEY_READ | KEY_WRITE | DELETE,
  765. NULL, &hDestSubKey, NULL ))
  766. {
  767. SetLastError( dwError );
  768. goto CleanUp;
  769. }
  770. //
  771. // Copy the subkey tree
  772. //
  773. if (!SplRegCopyTree( hDestSubKey, hSrcSubKey ))
  774. {
  775. goto CleanUp;
  776. }
  777. //
  778. // Close the registry handle
  779. //
  780. RegCloseKey( hDestSubKey );
  781. RegCloseKey( hSrcSubKey );
  782. hDestSubKey = NULL;
  783. hSrcSubKey = NULL;
  784. }
  785. bStatus = TRUE;
  786. CleanUp:
  787. //
  788. // Free allocated resources
  789. //
  790. if (lpValueName)
  791. {
  792. FreeSplMem( lpValueName );
  793. }
  794. if (lpData)
  795. {
  796. FreeSplMem( lpData );
  797. }
  798. if (lpKeyName)
  799. {
  800. FreeSplMem( lpKeyName );
  801. }
  802. //
  803. // Close registry handles
  804. //
  805. if (hDestSubKey)
  806. {
  807. RegCloseKey( hDestSubKey );
  808. }
  809. if (hSrcSubKey)
  810. {
  811. RegCloseKey( hSrcSubKey );
  812. }
  813. return bStatus;
  814. }
  815. VOID
  816. MigratePrinterData()
  817. /*++
  818. Function Description: When the spooler starts up for the first time after upgrade,
  819. the printer data is moved from HKLM\Software to HKLM\System
  820. Parameters: None
  821. Return Values: None
  822. --*/
  823. {
  824. HKEY hSysPrinters = NULL, hSwPrinters = NULL;
  825. //
  826. // Migrate the data only immediately following upgrade
  827. //
  828. if (!dwUpgradeFlag)
  829. {
  830. return;
  831. }
  832. //
  833. // Open the source and destination keys for the migration
  834. //
  835. if (( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  836. ipszRegSwPrinters,
  837. 0,
  838. KEY_WRITE | KEY_READ | DELETE,
  839. &hSwPrinters ) == ERROR_SUCCESS) &&
  840. ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  841. ipszRegistryPrinters,
  842. 0,
  843. KEY_WRITE | KEY_READ | DELETE,
  844. &hSysPrinters ) == ERROR_SUCCESS) )
  845. {
  846. //
  847. // Recursively copy the keys and the values from Software to System
  848. //
  849. SplRegCopyTree( hSysPrinters, hSwPrinters );
  850. }
  851. //
  852. // Close the registry handles
  853. //
  854. if (hSwPrinters)
  855. {
  856. RegCloseKey( hSwPrinters );
  857. }
  858. if (hSysPrinters)
  859. {
  860. RegCloseKey( hSysPrinters );
  861. }
  862. //
  863. // Delete the printers key from the software since it is no longer
  864. // accessed by the spooler
  865. //
  866. RegDeleteKey( HKEY_LOCAL_MACHINE, ipszRegSwPrinters );
  867. return;
  868. }
  869. NTSTATUS
  870. IsCCSetLinkedtoSoftwareHive (
  871. PBOOL pbIsLinked
  872. )
  873. /*++
  874. Function Description:
  875. Checks to see if it is a link between SYSTEM hive and SOFTWARE hive
  876. Only Nt Apis manage to do this.
  877. Parameters:
  878. OUT pbIsLinked - TRUE if there is a symbolic link between SYSTEM hive and SOFTWARE hive
  879. Return Values:
  880. --*/
  881. {
  882. NTSTATUS Status;
  883. OBJECT_ATTRIBUTES ObjectAttributes;
  884. UNICODE_STRING KeyName;
  885. HANDLE KeyHandle;
  886. *pbIsLinked = FALSE;
  887. RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Print\\Printers");
  888. InitializeObjectAttributes(&ObjectAttributes,
  889. &KeyName,
  890. OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
  891. (HANDLE)NULL,
  892. NULL);
  893. //
  894. // Open CurrentControlSet\\Control\\Print\\Printers key
  895. //
  896. Status = NtOpenKey( (PHANDLE)(&KeyHandle),
  897. MAXIMUM_ALLOWED,
  898. &ObjectAttributes
  899. );
  900. if (NT_SUCCESS(Status))
  901. {
  902. ULONG len;
  903. UCHAR ValueBuffer[MAX_PATH];
  904. UNICODE_STRING ValueName;
  905. PKEY_VALUE_FULL_INFORMATION keyInfo;
  906. RtlInitUnicodeString(&ValueName, L"SymbolicLinkValue");
  907. //
  908. // Query CurrentControlSet\\Control\\Print\\Printers for SymbolicLinkValue
  909. //
  910. Status = NtQueryValueKey(KeyHandle,
  911. &ValueName,
  912. KeyValueFullInformation,
  913. ValueBuffer,
  914. sizeof (ValueBuffer),
  915. &len
  916. );
  917. if( NT_SUCCESS(Status) ) {
  918. //
  919. // It's not enough that the value exists, it should be a REG_LINK value
  920. //
  921. keyInfo = ( PKEY_VALUE_FULL_INFORMATION ) ValueBuffer;
  922. *pbIsLinked = ( keyInfo->Type == REG_LINK );
  923. }
  924. NtClose(KeyHandle);
  925. }
  926. return Status;
  927. }
  928. DWORD
  929. LinkControlSet (
  930. LPCTSTR pszRegistryPrinters
  931. )
  932. /*++
  933. Function Description:
  934. Create a symbolic volatile link from SYSTEM hive to SOFTWARE hive
  935. Parameters:
  936. Return Values: ERROR_SUCCESS if succeeded
  937. --*/
  938. {
  939. HKEY hCCSKey;
  940. DWORD dwRet;
  941. BOOL bIsLinked = FALSE;
  942. PWCHAR pszRegistryPrintersFullLink = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers";
  943. dwRet = IsCCSetLinkedtoSoftwareHive(&bIsLinked);
  944. //
  945. // IsCCSetLinkedtoSoftwareHive returns NTSTATUS
  946. // If the link is not there , IsCCSetLinkedtoSoftwareHive fails with STATUS_OBJECT_NAME_NOT_FOUND
  947. // That's not an error.
  948. //
  949. if( NT_SUCCESS(dwRet) || dwRet == STATUS_OBJECT_NAME_NOT_FOUND ) {
  950. if (bIsLinked) {
  951. dwRet = ERROR_SUCCESS;
  952. }else{
  953. dwRet = SplDeleteThisKey( HKEY_LOCAL_MACHINE,
  954. NULL,
  955. (LPWSTR)pszRegistryPrinters,
  956. FALSE,
  957. NULL
  958. );
  959. if( dwRet == ERROR_SUCCESS || dwRet == ERROR_FILE_NOT_FOUND) {
  960. dwRet = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  961. pszRegistryPrinters,
  962. 0,
  963. NULL,
  964. REG_OPTION_VOLATILE|REG_OPTION_CREATE_LINK,
  965. KEY_WRITE | KEY_CREATE_LINK,
  966. NULL,
  967. &hCCSKey,
  968. NULL);
  969. if( dwRet == ERROR_SUCCESS )
  970. {
  971. dwRet = RegSetValueEx( hCCSKey,
  972. _T("SymbolicLinkValue"),
  973. 0,
  974. REG_LINK,
  975. (CONST BYTE *)pszRegistryPrintersFullLink,
  976. (_tcsclen(pszRegistryPrintersFullLink) * sizeof(WCHAR)));
  977. RegCloseKey(hCCSKey);
  978. }
  979. }
  980. }
  981. }
  982. return dwRet;
  983. }
  984. DWORD
  985. BackupPrintersToSystemHive(
  986. LPWSTR pszSwRegistryPrinters
  987. )
  988. /*++
  989. Function Description:
  990. Because the print registry data location was moved to SOFTWARE hive, we need to create
  991. a symbolic registry link between the new location and the old one in SYSTEM hive.
  992. We are doing this for applications that read directly from registry print data and
  993. rely on the old location.
  994. Parameters:
  995. pszSwRegistryPrinters - the new printer data location under SOFTWARE hive
  996. Return Values:
  997. FALSE if the printer keys are not in SOFTWARE hive
  998. Since this fuction's failure might stop spooler working,
  999. Control set's cleanup and link failures are not considered fatal.
  1000. Only apps that access printer data directly will fail.
  1001. --*/
  1002. {
  1003. HKEY hKey;
  1004. DWORD dwRet;
  1005. HKEY hSwPrinters = NULL;
  1006. //
  1007. // Check the existence of pszSwRegistryPrinters
  1008. //
  1009. dwRet = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  1010. pszSwRegistryPrinters,
  1011. 0,
  1012. NULL,
  1013. 0,
  1014. KEY_WRITE | KEY_CREATE_LINK,
  1015. NULL,
  1016. &hSwPrinters,
  1017. NULL);
  1018. if ( dwRet != ERROR_SUCCESS ) {
  1019. goto End;
  1020. }
  1021. //
  1022. // Create a volatile link between current location in SOFTWARE hive and the old one in SYSTEM hive
  1023. // Because it is volatile, this link must be created after each reboot (every time when spooler starts)
  1024. // A failure at this level is not fatal since spooler doesn't rely on SYSTEM hive location anymore
  1025. //
  1026. dwRet = LinkControlSet(ipszRegistryPrinters);
  1027. End:
  1028. if ( hSwPrinters ){
  1029. RegCloseKey( hSwPrinters );
  1030. }
  1031. return dwRet;
  1032. }
  1033. BOOL
  1034. CleanupDeletedPrinters (
  1035. PINISPOOLER pIniSpooler
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. Deletes the printers in pending deletion for real if they have no more jobs and
  1040. if they are not referenced anymore
  1041. Arguments:
  1042. pIniSpooler - not null
  1043. Return Value:
  1044. BOOL - ignored
  1045. --*/
  1046. {
  1047. PINIPRINTER pIniPrinter;
  1048. BOOL bRet = FALSE;
  1049. if(pIniSpooler) {
  1050. pIniPrinter = pIniSpooler->pIniPrinter;
  1051. while (pIniPrinter) {
  1052. if (pIniPrinter->Status & PRINTER_PENDING_DELETION &&
  1053. !pIniPrinter->cJobs &&
  1054. !pIniPrinter->cRef ) {
  1055. DeletePrinterForReal(pIniPrinter, INIT_TIME);
  1056. // The link list will have changed underneath us
  1057. // DeletePrinterForReal leaves the Spooler CS
  1058. // Lets just loop through again from the beginning
  1059. pIniPrinter = pIniSpooler->pIniPrinter;
  1060. } else
  1061. pIniPrinter = pIniPrinter->pNext;
  1062. }
  1063. bRet = TRUE;
  1064. }
  1065. return bRet;
  1066. }
  1067. HANDLE
  1068. SplCreateSpooler(
  1069. LPWSTR pMachineName,
  1070. DWORD Level,
  1071. PBYTE pSpooler,
  1072. LPBYTE pReserved
  1073. )
  1074. {
  1075. HANDLE hReturn = INVALID_HANDLE_VALUE;
  1076. PINISPOOLER pIniSpooler = NULL;
  1077. PSPOOLER_INFO_2 pSpoolerInfo2 = (PSPOOLER_INFO_2)pSpooler;
  1078. DWORD i;
  1079. WCHAR Buffer[MAX_PATH];
  1080. PSHARE_INFO_2 pShareInfo = NULL;
  1081. LONG Status;
  1082. HANDLE hToken = NULL;
  1083. DWORD dwRet;
  1084. hToken = RevertToPrinterSelf();
  1085. if (!hToken)
  1086. {
  1087. goto SplCreateDone;
  1088. }
  1089. EnterSplSem();
  1090. // Validate Parameters
  1091. if ( pMachineName == NULL ) {
  1092. SetLastError( ERROR_INVALID_NAME );
  1093. goto SplCreateDone;
  1094. }
  1095. if( Level == 1 &&
  1096. ( pSpoolerInfo2->SpoolerFlags & SPL_CLUSTER_REG ||
  1097. !pSpoolerInfo2->pszRegistryRoot ||
  1098. !pSpoolerInfo2->pszRegistryPrinters )){
  1099. SetLastError( ERROR_INVALID_PARAMETER );
  1100. goto SplCreateDone;
  1101. }
  1102. DBGMSG( DBG_TRACE, ("SplCreateSpooler %ws %d %x %x\n", pMachineName,
  1103. Level, pSpooler, pReserved ));
  1104. if( (pSpoolerInfo2->SpoolerFlags & (SPL_TYPE_LOCAL | SPL_PRINT)) &&
  1105. !(pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER) ){
  1106. if ( dwRet = (BackupPrintersToSystemHive( pSpoolerInfo2->pszRegistryPrinters )) != ERROR_SUCCESS ){
  1107. WCHAR szError[256];
  1108. StringCchPrintf(szError, COUNTOF(szError), L"%x", dwRet);
  1109. SplLogEvent(pIniSpooler,
  1110. LOG_ERROR,
  1111. MSG_BACKUP_SPOOLER_REGISTRY,
  1112. TRUE,
  1113. szError,
  1114. NULL);
  1115. }
  1116. }
  1117. if (pLocalIniSpooler != NULL) {
  1118. pIniSpooler = FindSpooler( pMachineName, pSpoolerInfo2->SpoolerFlags );
  1119. if (pSpoolerInfo2->SpoolerFlags & SPL_OPEN_EXISTING_ONLY && !pIniSpooler) {
  1120. SetLastError( ERROR_FILE_NOT_FOUND );
  1121. goto SplCreateDone;
  1122. }
  1123. }
  1124. //
  1125. // Make sure we clear out a request to only open an existing inispooler.
  1126. // This is not a useful flag except for when we are searching for inispoolers.
  1127. //
  1128. pSpoolerInfo2->SpoolerFlags &= ~SPL_OPEN_EXISTING_ONLY;
  1129. if ( pIniSpooler == NULL ) {
  1130. pIniSpooler = AllocSplMem( sizeof(INISPOOLER) );
  1131. if (pIniSpooler == NULL ) {
  1132. DBGMSG( DBG_WARNING, ("Unable to allocate IniSpooler\n"));
  1133. goto SplCreateDone;
  1134. }
  1135. pIniSpooler->signature = ISP_SIGNATURE;
  1136. INCSPOOLERREF( pIniSpooler );
  1137. pIniSpooler->hClusSplReady = NULL;
  1138. //
  1139. // Setup the job id map.
  1140. //
  1141. pIniSpooler->hJobIdMap = hCreateJobIdMap( 256 );
  1142. pIniSpooler->pMachineName = AllocSplStr( pMachineName );
  1143. if ( pIniSpooler->pMachineName == NULL ||
  1144. pIniSpooler->hJobIdMap == NULL ) {
  1145. DBGMSG( DBG_WARNING, ("Unable to allocate\n"));
  1146. goto SplCreateDone;
  1147. }
  1148. //
  1149. // A cluster spooler owns its drivers, ports, pprocessors, etc. In order to manage those
  1150. // resources, the cluster spooler needs to have information about the driver letter of
  1151. // the cluster disk. Also the spooler needs to know its own cluster resource GUID
  1152. //
  1153. if( pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER )
  1154. {
  1155. pIniSpooler->pszClusResDriveLetter = AllocSplStr(pSpoolerInfo2->pszClusResDriveLetter);
  1156. pIniSpooler->pszClusResID = AllocSplStr(pSpoolerInfo2->pszClusResID);
  1157. if (!pIniSpooler->pszClusResDriveLetter || !pIniSpooler->pszClusResID)
  1158. {
  1159. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1160. goto SplCreateDone;
  1161. }
  1162. //
  1163. // When a node is upgraded, the resource dll writes a key in the registry. When the cluster spooler
  1164. // fails over for the first time on the node that was upgraded, then it will try to read that key
  1165. // in the registry. Then it will know if it has to do upgrade specific tasks, like upgrading its
  1166. // printer drivers.
  1167. //
  1168. Status = ClusterSplReadUpgradeKey(pIniSpooler->pszClusResID, &pIniSpooler->dwClusNodeUpgraded);
  1169. if (Status != ERROR_SUCCESS)
  1170. {
  1171. SetLastError( Status );
  1172. goto SplCreateDone;
  1173. }
  1174. DBGMSG(DBG_CLUSTER, ("SplCreateSpooler cluster ClusterUpgradeFlag %u\n", pIniSpooler->dwClusNodeUpgraded));
  1175. }
  1176. else
  1177. {
  1178. //
  1179. // For a non cluster type spooler, these properties are meaningless.
  1180. //
  1181. pIniSpooler->pszClusResDriveLetter = NULL;
  1182. pIniSpooler->pszClusResID = NULL;
  1183. }
  1184. if (pSpoolerInfo2->pDir)
  1185. {
  1186. pIniSpooler->pDir = AllocSplStr( pSpoolerInfo2->pDir );
  1187. if (!pIniSpooler->pDir)
  1188. {
  1189. DBGMSG( DBG_WARNING, ("Unable to allocate pSpoolerInfo2-pDir\n"));
  1190. goto SplCreateDone;
  1191. }
  1192. StringCchCopy(&Buffer[0], COUNTOF(Buffer), pIniSpooler->pDir);
  1193. }
  1194. else
  1195. {
  1196. i = GetSystemDirectory(Buffer, COUNTOF(Buffer));
  1197. StringCchCopy(&Buffer[i], COUNTOF(Buffer) - i, szSpoolDirectory);
  1198. if (pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER)
  1199. {
  1200. //
  1201. // For a cluster type spooler, the directory where it stores its driver files is of the form:
  1202. // pDir = C:\Windows\system32\spool\Drivers\spooler-resource-GUID
  1203. //
  1204. StrCatAlloc(&pIniSpooler->pDir,
  1205. Buffer,
  1206. szDriversDirectory,
  1207. L"\\",
  1208. pIniSpooler->pszClusResID,
  1209. NULL);
  1210. }
  1211. else
  1212. {
  1213. //
  1214. // For the local spooler, the directory where it stores its driver files is the following:
  1215. // pDir = C:\Windows\system32\spool\Drivers
  1216. //
  1217. StrCatAlloc(&pIniSpooler->pDir,
  1218. Buffer,
  1219. NULL);
  1220. }
  1221. if (!pIniSpooler->pDir)
  1222. {
  1223. DBGMSG( DBG_WARNING, ("Unable to Allocate pIniSpooler->pDir\n"));
  1224. goto SplCreateDone;
  1225. }
  1226. }
  1227. //
  1228. // DriverShareInfo
  1229. //
  1230. pIniSpooler->pDriversShareInfo = AllocSplMem( sizeof( SHARE_INFO_2));
  1231. if ( pIniSpooler->pDriversShareInfo == NULL ) {
  1232. DBGMSG(DBG_WARNING, ("Unable to Alloc pIniSpooler->pDriversShareInfo\n"));
  1233. goto SplCreateDone;
  1234. }
  1235. pShareInfo = (PSHARE_INFO_2)pIniSpooler->pDriversShareInfo;
  1236. if ( pIniSpooler->pDriversShareInfo == NULL )
  1237. goto SplCreateDone;
  1238. pShareInfo->shi2_netname = NULL;
  1239. pShareInfo->shi2_type = STYPE_DISKTREE;
  1240. pShareInfo->shi2_remark = NULL;
  1241. pShareInfo->shi2_permissions = 0;
  1242. pShareInfo->shi2_max_uses = SHI_USES_UNLIMITED;
  1243. pShareInfo->shi2_current_uses = SHI_USES_UNLIMITED;
  1244. pShareInfo->shi2_path = NULL;
  1245. pShareInfo->shi2_passwd = NULL;
  1246. //
  1247. // Find end of "<winnt>\system32\spool"
  1248. //
  1249. i = wcslen(Buffer);
  1250. //
  1251. // Make <winnt>\system32\spool\drivers
  1252. //
  1253. StringCchCopy(&Buffer[i], COUNTOF(Buffer) - i, szDriversDirectory);
  1254. pShareInfo->shi2_path = AllocSplStr(Buffer);
  1255. if ( pShareInfo->shi2_path == NULL ) {
  1256. DBGMSG( DBG_WARNING, ("Unable to alloc pShareInfo->shi2_path\n"));
  1257. goto SplCreateDone;
  1258. }
  1259. pShareInfo->shi2_netname = ipszDriversShareName;
  1260. *Buffer = L'\0';
  1261. LoadString(hInst, IDS_PRINTER_DRIVERS, Buffer, (sizeof Buffer / sizeof *Buffer));
  1262. pShareInfo->shi2_remark = AllocSplStr(Buffer);
  1263. if ( pShareInfo->shi2_remark == NULL ) {
  1264. DBGMSG(DBG_WARNING, ("SplCreateSpooler Unable to allocate\n"));
  1265. goto SplCreateDone;
  1266. }
  1267. pIniSpooler->pIniPrinter = NULL;
  1268. pIniSpooler->pIniEnvironment = NULL;
  1269. pIniSpooler->pIniNetPrint = NULL;
  1270. pIniSpooler->cNetPrinters = 0;
  1271. //
  1272. // No need to initialize shared resources.
  1273. //
  1274. pIniSpooler->pSpool = NULL;
  1275. pIniSpooler->pDefaultSpoolDir = NULL;
  1276. pIniSpooler->bEnableRetryPopups = FALSE;
  1277. pIniSpooler->dwRestartJobOnPoolTimeout = DEFAULT_JOB_RESTART_TIMEOUT_ON_POOL_ERROR;
  1278. pIniSpooler->bRestartJobOnPoolEnabled = TRUE;
  1279. if (( pSpoolerInfo2->pszRegistryMonitors == NULL ) &&
  1280. ( pSpoolerInfo2->pszRegistryEnvironments == NULL ) &&
  1281. ( pSpoolerInfo2->pszRegistryEventLog == NULL ) &&
  1282. ( pSpoolerInfo2->pszRegistryProviders == NULL ) &&
  1283. ( pSpoolerInfo2->pszEventLogMsgFile == NULL ) &&
  1284. ( pSpoolerInfo2->pszRegistryForms == NULL ) &&
  1285. ( pSpoolerInfo2->pszDriversShare == NULL )) {
  1286. DBGMSG( DBG_WARNING, ("SplCreateSpooler Invalid Parameters\n"));
  1287. goto SplCreateDone;
  1288. }
  1289. if( !( pSpoolerInfo2->SpoolerFlags & SPL_CLUSTER_REG ) &&
  1290. ( pSpoolerInfo2->pszRegistryPrinters == NULL )){
  1291. DBGMSG( DBG_WARNING, ("SplCreateSpooler Invalid RegistryPrinters\n"));
  1292. goto SplCreateDone;
  1293. }
  1294. if ( pSpoolerInfo2->pDefaultSpoolDir != NULL ) {
  1295. pIniSpooler->pDefaultSpoolDir = AllocSplStr( pSpoolerInfo2->pDefaultSpoolDir );
  1296. if ( pIniSpooler->pDefaultSpoolDir == NULL ) {
  1297. DBGMSG(DBG_WARNING, ("SplCreateSpooler Unable to allocate\n"));
  1298. goto SplCreateDone;
  1299. }
  1300. }
  1301. pIniSpooler->pszRegistryMonitors = AllocSplStr( pSpoolerInfo2->pszRegistryMonitors );
  1302. //
  1303. // The spooler stores data about environemnts, versions, drivers and print processors
  1304. // in the regsitry (or cluster data base). This data is accessed via pIniSpooler->
  1305. // pszRegistryEnvironemts
  1306. //
  1307. if (pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER)
  1308. {
  1309. //
  1310. // For a cluster spooler pIniSpooler->hckRoot maps to Parameters key of the spooler
  1311. // resource in the cluster database. pIniSpooler->pszRegistryEnvironments is a key
  1312. // called "Environemts" under hckRoot.
  1313. //
  1314. pIniSpooler->pszRegistryEnvironments = AllocSplStr(ipszClusterDatabaseEnvironments);
  1315. }
  1316. else
  1317. {
  1318. //
  1319. // For local spooler pIniSpooler->pszRegistryEnvironments is the following string:
  1320. // System\CurrentControlSet\Control\Print\Environments. It is used relative to HKLM
  1321. //
  1322. pIniSpooler->pszRegistryEnvironments = AllocSplStr(!pLocalIniSpooler ? pSpoolerInfo2->pszRegistryEnvironments :
  1323. pLocalIniSpooler->pszRegistryEnvironments);
  1324. }
  1325. pIniSpooler->pszRegistryEventLog = AllocSplStr( pSpoolerInfo2->pszRegistryEventLog );
  1326. pIniSpooler->pszRegistryProviders = AllocSplStr( pSpoolerInfo2->pszRegistryProviders );
  1327. pIniSpooler->pszEventLogMsgFile = AllocSplStr( pSpoolerInfo2->pszEventLogMsgFile );
  1328. if (pSpoolerInfo2->SpoolerFlags & SPL_TYPE_CLUSTER)
  1329. {
  1330. //
  1331. // The driver share for a cluster spooler is of the form \\server\print$\spooler-resource-GUID
  1332. //
  1333. StrCatAlloc(&pIniSpooler->pszDriversShare,
  1334. pSpoolerInfo2->pszDriversShare,
  1335. L"\\",
  1336. pIniSpooler->pszClusResID,
  1337. szDriversDirectory,
  1338. NULL);
  1339. }
  1340. else
  1341. {
  1342. //
  1343. // The driver share for the local spooler is \\server\print$
  1344. //
  1345. StrCatAlloc(&pIniSpooler->pszDriversShare, pSpoolerInfo2->pszDriversShare, NULL);
  1346. }
  1347. pIniSpooler->pszRegistryForms = AllocSplStr( pSpoolerInfo2->pszRegistryForms ) ;
  1348. pIniSpooler->hClusterToken = INVALID_HANDLE_VALUE;
  1349. pIniSpooler->hFilePool = INVALID_HANDLE_VALUE;
  1350. if ( pIniSpooler->pszRegistryMonitors == NULL ||
  1351. pIniSpooler->pszRegistryEnvironments == NULL ||
  1352. pIniSpooler->pszRegistryEventLog == NULL ||
  1353. pIniSpooler->pszRegistryProviders == NULL ||
  1354. pIniSpooler->pszEventLogMsgFile == NULL ||
  1355. pIniSpooler->pszDriversShare == NULL ||
  1356. pIniSpooler->pszRegistryForms == NULL ) {
  1357. DBGMSG(DBG_WARNING, ("SplCreateSpooler Unable to allocate\n"));
  1358. goto SplCreateDone;
  1359. }
  1360. pIniSpooler->SpoolerFlags = pSpoolerInfo2->SpoolerFlags;
  1361. //
  1362. // Initialize the shared resources (pShared).
  1363. //
  1364. if( !InitializeShared( pIniSpooler )){
  1365. DBGMSG( DBG_WARN,
  1366. ( "SplCreateSpooler: InitializeShared Failed %d\n",
  1367. GetLastError() ));
  1368. goto SplCreateDone;
  1369. }
  1370. //
  1371. // Create the print share if necessary. This is always needed
  1372. // since the cluster printers are shared, while the local ones
  1373. // on this node aren't.
  1374. //
  1375. if(pIniSpooler->SpoolerFlags & SPL_ALWAYS_CREATE_DRIVER_SHARE ){
  1376. if( !AddPrintShare( pIniSpooler )){
  1377. goto SplCreateDone;
  1378. }
  1379. }
  1380. //
  1381. // Open and store the printer and root key from
  1382. // the resource registry.
  1383. //
  1384. if( pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG ){
  1385. SPLASSERT( Level == 2 );
  1386. // Set up the DS Cluster info. If we fail here, we can't publish printers, but let's
  1387. // not abort the cluster.
  1388. Status = InitializeDSClusterInfo(pIniSpooler, &hToken);
  1389. if (Status != ERROR_SUCCESS) {
  1390. DBGMSG(DBG_WARNING, ("InitializeDSClusterInfo FAILED: %d\n", Status));
  1391. }
  1392. pIniSpooler->hckRoot = OpenClusterParameterKey(
  1393. pSpoolerInfo2->pszResource );
  1394. if( !pIniSpooler->hckRoot ) {
  1395. goto SplCreateDone;
  1396. }
  1397. Status = SplRegCreateKey( pIniSpooler->hckRoot,
  1398. szPrintersKey,
  1399. 0,
  1400. KEY_WRITE | KEY_READ | DELETE,
  1401. NULL,
  1402. &pIniSpooler->hckPrinters,
  1403. NULL,
  1404. pIniSpooler );
  1405. if( Status != ERROR_SUCCESS ){
  1406. SetLastError( Status );
  1407. goto SplCreateDone;
  1408. }
  1409. } else {
  1410. DWORD dwDisposition;
  1411. Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  1412. pSpoolerInfo2->pszRegistryRoot,
  1413. 0,
  1414. NULL,
  1415. 0,
  1416. KEY_WRITE | KEY_READ | DELETE,
  1417. NULL,
  1418. &pIniSpooler->hckRoot,
  1419. &dwDisposition );
  1420. if( Status != ERROR_SUCCESS ){
  1421. SetLastError( Status );
  1422. goto SplCreateDone;
  1423. }
  1424. Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  1425. pSpoolerInfo2->pszRegistryPrinters,
  1426. 0,
  1427. NULL,
  1428. 0,
  1429. KEY_WRITE | KEY_READ | DELETE,
  1430. NULL,
  1431. &pIniSpooler->hckPrinters,
  1432. &dwDisposition );
  1433. if( Status != ERROR_SUCCESS ){
  1434. SetLastError( Status );
  1435. goto SplCreateDone;
  1436. }
  1437. }
  1438. pIniSpooler->pfnReadRegistryExtra = pSpoolerInfo2->pfnReadRegistryExtra;
  1439. pIniSpooler->pfnWriteRegistryExtra = pSpoolerInfo2->pfnWriteRegistryExtra;
  1440. pIniSpooler->pfnFreePrinterExtra = pSpoolerInfo2->pfnFreePrinterExtra;
  1441. // Success add to Linked List
  1442. if ( pLocalIniSpooler != NULL ) {
  1443. pIniSpooler->pIniNextSpooler = pLocalIniSpooler->pIniNextSpooler;
  1444. pLocalIniSpooler->pIniNextSpooler = pIniSpooler;
  1445. } else {
  1446. // First One is Always LocalSpl
  1447. pLocalIniSpooler = pIniSpooler;
  1448. pIniSpooler->pIniNextSpooler = NULL;
  1449. }
  1450. //
  1451. // This function will update the global varaiable dwUpgradeFlag
  1452. //
  1453. QueryUpgradeFlag( pIniSpooler );
  1454. InitializeEventLogging( pIniSpooler );
  1455. //
  1456. // Only initialize forms if this is not a clustered spooler.
  1457. //
  1458. if( !( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER )){
  1459. InitializeForms( pIniSpooler );
  1460. }
  1461. //
  1462. // Originally ports were a per-machine (manual) resource. However,
  1463. // this has changed for clustering in 5.0, so that ports can be
  1464. // stored in the cluster registry. Note that monitors are still
  1465. // manual resources, since there isn't an easy way to install them
  1466. // on a remote machine.
  1467. //
  1468. BuildAllPorts( pIniSpooler );
  1469. InitializeSpoolerSettings( pIniSpooler );
  1470. if ( pIniSpooler == pLocalIniSpooler ) {
  1471. GetPrintSystemVersion( pIniSpooler );
  1472. BuildEnvironmentInfo( pIniSpooler );
  1473. if ( dwUpgradeFlag ) {
  1474. //
  1475. // The problem is that we have built-in forms, and
  1476. // custom forms (duplicates disallowed).On NT4, we
  1477. // may have a custom "A6" form. When we upgrade to NT5,
  1478. // and we have a new built-in from "A6." We need to
  1479. // rename the custom form to "A6 Custom," otherwise we'll
  1480. // have duplicates.
  1481. //
  1482. UpgradeForms(pIniSpooler);
  1483. }
  1484. } else if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) {
  1485. HANDLE hThread;
  1486. DWORD dwThreadId;
  1487. DWORD dwError;
  1488. //
  1489. // The setup creates the registry strucutre for the local spooler:
  1490. // Environments {Windows NT x86, Windows IA64, etc}
  1491. // For a cluster spooler we need to create it ourselves in the
  1492. // cluster database
  1493. //
  1494. if ((dwError = CreateClusterSpoolerEnvironmentsStructure(pIniSpooler)) == ERROR_SUCCESS)
  1495. {
  1496. //
  1497. // Create all the environments, versions, drivers, processors strurctres
  1498. // This function always returns FALSE. We cannot take its return value
  1499. // into account.
  1500. //
  1501. BuildEnvironmentInfo(pIniSpooler);
  1502. //
  1503. // Now we launch a thread to do time consuming tasks that can
  1504. // be performed with the spooler on line. These inlude ungrading
  1505. // printer drivers, copying ICM profiles from the cluster disk etc.
  1506. //
  1507. // We need to bump the ref count so that the worker thread has
  1508. // a valid pIniSpooler. The worker thread will decref the pinispooler
  1509. // when it is done
  1510. //
  1511. INCSPOOLERREF(pIniSpooler);
  1512. //
  1513. // The event has manual reset and is not signaled.
  1514. //
  1515. pIniSpooler->hClusSplReady = CreateEvent(NULL, TRUE, FALSE, NULL);
  1516. //
  1517. // If the thread is created, then SplCreateSpoolerWorkerThread will
  1518. // close the hClusSplReady event handle.
  1519. //
  1520. if (pIniSpooler->hClusSplReady &&
  1521. (hThread = CreateThread(NULL,
  1522. 0,
  1523. (LPTHREAD_START_ROUTINE)SplCreateSpoolerWorkerThread,
  1524. (PVOID)pIniSpooler,
  1525. 0,
  1526. &dwThreadId)))
  1527. {
  1528. CloseHandle(hThread);
  1529. }
  1530. else
  1531. {
  1532. //
  1533. // Either CreateEvent or CreatreThread failed.
  1534. //
  1535. dwError = GetLastError();
  1536. if (pIniSpooler->hClusSplReady)
  1537. {
  1538. CloseHandle(pIniSpooler->hClusSplReady);
  1539. pIniSpooler->hClusSplReady = NULL;
  1540. }
  1541. DECSPOOLERREF(pIniSpooler);
  1542. DBGMSG(DBG_ERROR, ("Unable to create SplCreateSpoolerWorkerThread\n"));
  1543. }
  1544. }
  1545. //
  1546. // An error occured
  1547. //
  1548. if (dwError != ERROR_SUCCESS)
  1549. {
  1550. SetLastError(dwError);
  1551. goto SplCreateDone;
  1552. }
  1553. }
  1554. else
  1555. {
  1556. //
  1557. // This is the case of a network spooler. You get one of those when
  1558. // you make a true printer connection
  1559. //
  1560. pIniSpooler->pIniEnvironment = pLocalIniSpooler->pIniEnvironment;
  1561. }
  1562. //
  1563. // Read Printer Info from Registry (cluster databse for cluster spooler)
  1564. // There's no cleanup in any of this code--it doesn't free any allocated memory!
  1565. //
  1566. if( !BuildPrinterInfo( pIniSpooler, (BOOL) dwUpgradeFlag )){
  1567. goto SplCreateDone;
  1568. }
  1569. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  1570. //
  1571. // Keep a counter of pIniSpoolers.
  1572. //
  1573. ++gcClusterIniSpooler;
  1574. }
  1575. //
  1576. // We need to perform some costly initialization, so we increase the refcount
  1577. // on the pIniSpooler and will do the lengthy operations outside the global
  1578. // critical section
  1579. //
  1580. INCSPOOLERREF(pIniSpooler);
  1581. LeaveSplSem();
  1582. //
  1583. // GetDNSMachineName may fail, but that's okay. Just don't be surprised
  1584. // if pszFullMachineName is NULL.
  1585. //
  1586. GetDNSMachineName(pIniSpooler->pMachineName + 2, &pIniSpooler->pszFullMachineName);
  1587. if (Level == 2 && pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER)
  1588. {
  1589. LPWSTR *ppszIPAddresses = NULL;
  1590. DWORD cIPAddreeses = 0;
  1591. //
  1592. // The cluster resource calls us with level 2. In this case we want to add a node
  1593. // tothe cache, but we want the node to support the name and IP addresses we want.
  1594. // The resource tells us all the IP addresses the cluster spooler is dependent on.
  1595. //
  1596. if (BuildIPArrayFromCommaList(pSpoolerInfo2->pszAddress,
  1597. &ppszIPAddresses,
  1598. &cIPAddreeses) != S_OK ||
  1599. CacheCreateAndAddNodeWithIPAddresses(pIniSpooler->pMachineName + 2,
  1600. TRUE,
  1601. ppszIPAddresses,
  1602. cIPAddreeses) != S_OK)
  1603. {
  1604. EnterSplSem();
  1605. goto SplCreateDone;
  1606. }
  1607. }
  1608. else if (pIniSpooler->SpoolerFlags & (SPL_TYPE_CLUSTER | SPL_TYPE_LOCAL))
  1609. {
  1610. //
  1611. // We skip the \\ prepended to the server name. Cache nodes for cluster pIniSpooler
  1612. // are alwasy searched first. That is why in CacheCreateAndAddNode we indicate
  1613. // the type of the spooler.
  1614. //
  1615. if (CacheCreateAndAddNode(pIniSpooler->pMachineName + 2,
  1616. pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) != S_OK)
  1617. {
  1618. EnterSplSem();
  1619. goto SplCreateDone;
  1620. }
  1621. }
  1622. EnterSplSem();
  1623. DECSPOOLERREF(pIniSpooler);
  1624. } else {
  1625. INCSPOOLERREF( pIniSpooler );
  1626. }
  1627. //
  1628. // Initialize the DS.
  1629. //
  1630. if (pIniSpooler->SpoolerFlags & SPL_PRINT) {
  1631. InitializeDS(pIniSpooler);
  1632. }
  1633. hReturn = (HANDLE)pIniSpooler;
  1634. SplCreateDone:
  1635. //
  1636. // Check if an error occurred while creating the spooler.
  1637. //
  1638. if (hReturn == INVALID_HANDLE_VALUE && pIniSpooler)
  1639. {
  1640. //
  1641. // This will prevent leaking allocated fields
  1642. //
  1643. DECSPOOLERREF(pIniSpooler);
  1644. }
  1645. LeaveSplSem();
  1646. if ( !pIniSpooler )
  1647. {
  1648. if (!(pSpoolerInfo2->SpoolerFlags & SPL_OPEN_EXISTING_ONLY))
  1649. {
  1650. SplLogEvent(
  1651. NULL,
  1652. LOG_ERROR,
  1653. MSG_INIT_FAILED,
  1654. FALSE,
  1655. L"Spooler",
  1656. L"SplCreateSpooler",
  1657. L"Unknown Error",
  1658. NULL
  1659. );
  1660. }
  1661. }
  1662. if (hToken)
  1663. {
  1664. ImpersonatePrinterClient(hToken);
  1665. }
  1666. //
  1667. // Set the event that the cluster spooler is initialized
  1668. //
  1669. if (pIniSpooler &&
  1670. pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  1671. pIniSpooler->hClusSplReady)
  1672. {
  1673. SetEvent(pIniSpooler->hClusSplReady);
  1674. }
  1675. return hReturn;
  1676. }
  1677. BOOL
  1678. InitializePrintProvidor(
  1679. LPPRINTPROVIDOR pPrintProvidor,
  1680. DWORD cbPrintProvidor,
  1681. LPWSTR pFullRegistryPath
  1682. )
  1683. {
  1684. HANDLE hSchedulerThread;
  1685. HANDLE hFinalInitAfterRouterInitCompleteThread;
  1686. DWORD ThreadId;
  1687. BOOL bSucceeded = TRUE;
  1688. WCHAR Buffer[MAX_PATH];
  1689. DWORD i;
  1690. PINISPOOLER pIniSpooler = NULL;
  1691. static LPWSTR pMachineName = NULL;
  1692. static LPWSTR pszDriverShareName = NULL;
  1693. SPOOLER_INFO_1 SpoolerInfo1;
  1694. BOOL bInSem = FALSE;
  1695. try {
  1696. if (!InitializeWinSpoolDrv())
  1697. leave;
  1698. //
  1699. // Make sure sizes of structres are good
  1700. //
  1701. SPLASSERT( sizeof( PRINTER_INFO_STRESSW ) == sizeof ( PRINTER_INFO_STRESSA ) );
  1702. // !! LATER !!
  1703. // We could change this to succeed even on failure
  1704. // if we point all the routines to a function which returns failure
  1705. //
  1706. if (!InitializeNet())
  1707. leave;
  1708. //
  1709. // JobIdMap initialized when spooler created.
  1710. //
  1711. //
  1712. // Allocate LocalSpl Global IniSpooler
  1713. //
  1714. Buffer[0] = Buffer[1] = L'\\';
  1715. i = MAX_PATH-2;
  1716. OsVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1717. OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1718. if ( !GetComputerName(Buffer+2, &i) ||
  1719. !GetVersionEx((POSVERSIONINFO)&OsVersionInfoEx) ||
  1720. !GetVersionEx(&OsVersionInfo)) {
  1721. DBGMSG(DBG_WARNING, ("GetComputerName/OSVersionInfo failed.\n"));
  1722. leave;
  1723. }
  1724. pMachineName = AllocSplStr(Buffer);
  1725. if ( pMachineName == NULL )
  1726. leave;
  1727. pszDriverShareName = AllocSplStr(ipszDriversShareName); /* print$ */
  1728. if ( pszDriverShareName == NULL )
  1729. {
  1730. leave;
  1731. }
  1732. SpoolerInfo1.pszDriversShare = pszDriverShareName;
  1733. //
  1734. // Read value for Allow remote connection policy.
  1735. //
  1736. if (FAILED(GetServerPolicy(szRegisterSpoolerRemoteRpcEndPoint,
  1737. (ULONG*)(&gRemoteRPCEndPointPolicy))))
  1738. {
  1739. DBGMSG(DBG_ERROR, ("Failing to read the remote connections policy.\n"));
  1740. leave;
  1741. }
  1742. if (!InitializeSecurityStructures())
  1743. leave;
  1744. // Use Defaults
  1745. SpoolerInfo1.pDir = NULL;
  1746. SpoolerInfo1.pDefaultSpoolDir = NULL;
  1747. SpoolerInfo1.pszRegistryRoot = ipszRegistryRoot;
  1748. SpoolerInfo1.pszRegistryPrinters = ipszRegSwPrinters;
  1749. SpoolerInfo1.pszRegistryMonitors = ipszRegistryMonitorsHKLM;
  1750. SpoolerInfo1.pszRegistryEnvironments = ipszRegistryEnvironments;
  1751. SpoolerInfo1.pszRegistryEventLog = ipszRegistryEventLog;
  1752. SpoolerInfo1.pszRegistryProviders = ipszRegistryProviders;
  1753. SpoolerInfo1.pszEventLogMsgFile = ipszEventLogMsgFile;
  1754. SpoolerInfo1.pszRegistryForms = ipszRegistryForms;
  1755. SpoolerInfo1.SpoolerFlags = SPL_UPDATE_WININI_DEVICES |
  1756. SPL_PRINTER_CHANGES |
  1757. SPL_LOG_EVENTS |
  1758. SPL_FORMS_CHANGE |
  1759. SPL_BROADCAST_CHANGE |
  1760. SPL_SECURITY_CHECK |
  1761. SPL_OPEN_CREATE_PORTS |
  1762. SPL_FAIL_OPEN_PRINTERS_PENDING_DELETION |
  1763. SPL_REMOTE_HANDLE_CHECK |
  1764. SPL_PRINTER_DRIVER_EVENT |
  1765. SPL_SERVER_THREAD |
  1766. SPL_PRINT |
  1767. SPL_TYPE_LOCAL;
  1768. SpoolerInfo1.pfnReadRegistryExtra = NULL;
  1769. SpoolerInfo1.pfnWriteRegistryExtra = NULL;
  1770. SpoolerInfo1.pfnFreePrinterExtra = NULL;
  1771. pLocalIniSpooler = SplCreateSpooler( pMachineName,
  1772. 1,
  1773. (PBYTE)&SpoolerInfo1,
  1774. NULL );
  1775. if ( pLocalIniSpooler == INVALID_HANDLE_VALUE ) {
  1776. DBGMSG( DBG_WARNING, ("InitializePrintProvidor Unable to allocate pLocalIniSpooler\n"));
  1777. leave;
  1778. }
  1779. pIniSpooler = pLocalIniSpooler;
  1780. #if DBG
  1781. InitializeDebug( pIniSpooler );
  1782. #endif
  1783. // !! LATER !!
  1784. // Why is this done inside critical section ?
  1785. EnterSplSem();
  1786. bInSem = TRUE;
  1787. if (!LoadString(hInst, IDS_REMOTE_DOC, Buffer, MAX_PATH))
  1788. leave;
  1789. szRemoteDoc = AllocSplStr( Buffer );
  1790. if ( szRemoteDoc == NULL )
  1791. leave;
  1792. if (!LoadString(hInst, IDS_LOCAL_DOC, Buffer, MAX_PATH))
  1793. leave;
  1794. szLocalDoc = AllocSplStr( Buffer );
  1795. if ( szLocalDoc == NULL )
  1796. leave;
  1797. if (!LoadString(hInst, IDS_FASTPRINT_TIMEOUT, Buffer, MAX_PATH))
  1798. leave;
  1799. szFastPrintTimeout = AllocSplStr( Buffer );
  1800. if ( szFastPrintTimeout == NULL )
  1801. leave;
  1802. SchedulerSignal = CreateEvent(NULL,
  1803. EVENT_RESET_AUTOMATIC,
  1804. EVENT_INITIAL_STATE_NOT_SIGNALED,
  1805. NULL);
  1806. PowerManagementSignal = CreateEvent(NULL,
  1807. EVENT_RESET_MANUAL,
  1808. EVENT_INITIAL_STATE_SIGNALED,
  1809. NULL);
  1810. hSchedulerThread = CreateThread( NULL,
  1811. INITIAL_STACK_COMMIT,
  1812. (LPTHREAD_START_ROUTINE)SchedulerThread,
  1813. pIniSpooler, 0, &ThreadId );
  1814. hFinalInitAfterRouterInitCompleteThread = CreateThread( NULL, INITIAL_STACK_COMMIT,
  1815. (LPTHREAD_START_ROUTINE)FinalInitAfterRouterInitCompleteThread,
  1816. (LPVOID)ULongToPtr(dwUpgradeFlag), 0, &ThreadId );
  1817. if (!SchedulerSignal || !PowerManagementSignal || !hSchedulerThread || !hFinalInitAfterRouterInitCompleteThread) {
  1818. DBGMSG( DBG_WARNING, ("Scheduler/FinalInitAfterRouterInitCompleteThread not initialised properly: Error %d\n", GetLastError()));
  1819. leave;
  1820. }
  1821. if ( !SetThreadPriority( hSchedulerThread, dwSchedulerThreadPriority ) ) {
  1822. DBGMSG( DBG_WARNING, ("Setting Scheduler thread priority failed %d\n", GetLastError()));
  1823. }
  1824. CloseHandle( hSchedulerThread );
  1825. CloseHandle( hFinalInitAfterRouterInitCompleteThread );
  1826. //
  1827. // Read online/offline status for local printers from current config
  1828. //
  1829. SplConfigChange();
  1830. CHECK_SCHEDULER();
  1831. CopyMemory( pPrintProvidor, &PrintProvidor, min(sizeof(PRINTPROVIDOR), cbPrintProvidor));
  1832. LeaveSplSem();
  1833. bInSem = FALSE;
  1834. CloseProfileUserMapping(); // !!! We should be able to get rid of this
  1835. //
  1836. // Get the default value for DefaultKMPrintersAreBlocked. It depends
  1837. // what type of OS is running. If we cannot identify the type of OS,
  1838. // the default is set to "blocked"
  1839. //
  1840. DefaultKMPrintersAreBlocked = GetDefaultForKMPrintersBlockedPolicy();
  1841. gdwServerInstallTimeOut = GetServerInstallTimeOut();
  1842. Initialized = TRUE;
  1843. } finally {
  1844. if ( bInSem ) {
  1845. LeaveSplSem();
  1846. }
  1847. }
  1848. SplOutSem();
  1849. return Initialized;
  1850. }
  1851. PINIPORT
  1852. CreatePortEntry(
  1853. LPWSTR pPortName,
  1854. PINIMONITOR pIniMonitor,
  1855. PINISPOOLER pIniSpooler
  1856. )
  1857. {
  1858. DWORD cb;
  1859. PINIPORT pIniPort = NULL;
  1860. HANDLE hPort = NULL;
  1861. BOOL bPlaceHolder = FALSE;
  1862. BOOL bInitCS = FALSE;
  1863. //
  1864. // This is a placeholder if there is no monitor and later if there is no
  1865. // partial print provider.
  1866. //
  1867. bPlaceHolder = pIniMonitor == NULL;
  1868. SplInSem();
  1869. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  1870. if (!pPortName || !*pPortName || wcslen(pPortName) >= MAX_PATH) {
  1871. SetLastError(ERROR_UNKNOWN_PORT);
  1872. return NULL;
  1873. }
  1874. if (!pIniMonitor) {
  1875. /* Don't bother validating the port if we aren't initialised.
  1876. * It must be valid, since we wrote it in the registry.
  1877. * This fixes the problem of attempting to open a network
  1878. * printer before the redirector has initialised,
  1879. * and the problem of access denied because we're currently
  1880. * in the system's context.
  1881. */
  1882. if (Initialized) {
  1883. //
  1884. // !! Warning !!
  1885. //
  1886. // Watch for deadlock:
  1887. //
  1888. // spoolss!OpenPrinterPortW -> RPC to self printer port
  1889. // localspl!CreatePortEntry
  1890. // localspl!ValidatePortTokenList
  1891. // localspl!SetPrinterPorts
  1892. // localspl!LocalSetPrinter
  1893. // spoolss!SetPrinterW
  1894. // spoolss!RpcSetPrinter
  1895. // spoolss!winspool_RpcSetPrinter
  1896. //
  1897. //
  1898. // If we can't open the port then fail the call since this
  1899. // spooler did not know this name before.
  1900. //
  1901. LeaveSplSem();
  1902. if ( !OpenPrinterPortW(pPortName, &hPort, NULL) ){
  1903. EnterSplSem();
  1904. goto Cleanup;
  1905. }
  1906. else {
  1907. bPlaceHolder = FALSE;
  1908. ClosePrinter(hPort);
  1909. }
  1910. EnterSplSem();
  1911. }
  1912. }
  1913. cb = sizeof(INIPORT) + wcslen(pPortName)*sizeof(WCHAR) + sizeof(WCHAR);
  1914. if (pIniPort=AllocSplMem(cb)) {
  1915. StringCbCopy((LPWSTR)(pIniPort+1), cb - sizeof(*pIniPort), pPortName);
  1916. pIniPort->pName = (LPWSTR)(pIniPort+1);
  1917. pIniPort->signature = IPO_SIGNATURE;
  1918. pIniPort->pIniMonitor = pIniMonitor;
  1919. pIniPort->IdleTime = GetTickCount() - 1;
  1920. pIniPort->bIdleTimeValid = FALSE;
  1921. pIniPort->ErrorTime = 0;
  1922. pIniPort->hErrorEvent = NULL;
  1923. pIniPort->InCriticalSection = 0;
  1924. pIniPort->hPortThreadRunning = CreateEvent(NULL, TRUE, FALSE, NULL);
  1925. if ( !pIniPort->hPortThreadRunning ) {
  1926. goto Cleanup;
  1927. }
  1928. if (pIniMonitor) {
  1929. pIniPort->Status |= PP_MONITOR;
  1930. }
  1931. if (bPlaceHolder) {
  1932. pIniPort->Status |= PP_PLACEHOLDER;
  1933. }
  1934. if (!(bInitCS = InitializeCriticalSectionAndSpinCount(&(pIniPort->MonitorCS),
  1935. 0x80000000)))
  1936. {
  1937. goto Cleanup;
  1938. }
  1939. LinkPortToSpooler( pIniPort, pIniSpooler );
  1940. }
  1941. Cleanup:
  1942. if ( pIniPort && (!pIniPort->hPortThreadRunning || !bInitCS) ) {
  1943. DeletePortEntry(pIniPort);
  1944. }
  1945. return pIniPort;
  1946. }
  1947. BOOL
  1948. DeletePortEntry(
  1949. PINIPORT pIniPort
  1950. )
  1951. /*++
  1952. Routine Description:
  1953. Free pIniPort resources then delete it. If the pIniPort is on
  1954. a pIniSpooler's linked list, remove it too.
  1955. Arguments:
  1956. pIniPort - Port to delete. May or may not be on a pIniSpooler.
  1957. Return Value:
  1958. TRUE - deleted
  1959. FALSE - not deleted (may be in use).
  1960. --*/
  1961. {
  1962. PINISPOOLER pIniSpooler;
  1963. SplInSem();
  1964. SPLASSERT ( ( pIniPort != NULL) || ( pIniPort->signature == IPO_SIGNATURE) );
  1965. //
  1966. // We had better already closed the port monitor.
  1967. //
  1968. SPLASSERT( !GetMonitorHandle(pIniPort) &&
  1969. !(pIniPort->Status & PP_THREADRUNNING) &&
  1970. !pIniPort->cJobs);
  1971. if (pIniPort->cRef) {
  1972. pIniPort->Status |= PP_DELETING;
  1973. return FALSE;
  1974. }
  1975. pIniSpooler = pIniPort->pIniSpooler;
  1976. //
  1977. // If currently linked to a pIniSpooler, delink it.
  1978. //
  1979. if( pIniSpooler ){
  1980. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  1981. DelinkPortFromSpooler( pIniPort, pIniSpooler );
  1982. }
  1983. if (pIniPort->ppIniPrinter)
  1984. FreeSplMem(pIniPort->ppIniPrinter);
  1985. CloseHandle(pIniPort->hPortThreadRunning);
  1986. DeleteCriticalSection(&pIniPort->MonitorCS);
  1987. FreeSplMem(pIniPort);
  1988. return TRUE;
  1989. }
  1990. VOID
  1991. FreeIniMonitor(
  1992. PINIMONITOR pIniMonitor
  1993. )
  1994. {
  1995. if( pIniMonitor ){
  1996. FreeSplStr( pIniMonitor->pMonitorDll );
  1997. if( pIniMonitor->hModule ){
  1998. FreeLibrary( pIniMonitor->hModule );
  1999. }
  2000. if( pIniMonitor->pMonitorInit ){
  2001. FreeSplStr( (LPWSTR)pIniMonitor->pMonitorInit->pszServerName );
  2002. if( pIniMonitor->pMonitorInit->hckRegistryRoot ){
  2003. SplRegCloseKey( pIniMonitor->pMonitorInit->hckRegistryRoot,
  2004. pIniMonitor->pIniSpooler );
  2005. }
  2006. FreeSplMem( pIniMonitor->pMonitorInit );
  2007. }
  2008. FreeSplMem( pIniMonitor );
  2009. }
  2010. }
  2011. #ifdef _SPL_CLUST
  2012. LPMONITOR2
  2013. InitializePrintMonitor2(
  2014. PMONITORINIT pMonitorInit,
  2015. PHANDLE phMonitor
  2016. )
  2017. {
  2018. return(LocalMonInitializePrintMonitor2(pMonitorInit,phMonitor));
  2019. }
  2020. #endif
  2021. PINIMONITOR
  2022. CreateMonitorEntry(
  2023. LPWSTR pMonitorDll,
  2024. LPWSTR pMonitorName,
  2025. PINISPOOLER pIniSpooler
  2026. )
  2027. /*++
  2028. Routine Description:
  2029. Arguments:
  2030. Return Value:
  2031. Valid pIniMonitor - This means everything worked out fine.
  2032. NULL - This means the monitor DLL was found, but the initialisation routine
  2033. returned FALSE. This is non-fatal, as the monitor may need the
  2034. system to reboot before it can run properly.
  2035. -1 - This means the monitor DLL or the initialization routine was not found.
  2036. --*/
  2037. {
  2038. WCHAR szRegistryRoot[MAX_PATH];
  2039. DWORD cb, cbNeeded, cReturned, dwRetVal;
  2040. PPORT_INFO_1 pPorts, pPort;
  2041. PINIMONITOR pIniMonitor;
  2042. UINT uOldErrMode;
  2043. PMONITOR2 (*pfnInitializePrintMonitor2)(PMONITORINIT, PHANDLE) = NULL;
  2044. PINIMONITOR pReturnValue = (PINIMONITOR)-1;
  2045. HANDLE hKeyOut;
  2046. LPWSTR pszPathOut;
  2047. SPLASSERT( (pIniSpooler != NULL) || (pIniSpooler->signature == ISP_SIGNATURE));
  2048. SplInSem();
  2049. cb = sizeof(INIMONITOR) + wcslen(pMonitorName)*sizeof(WCHAR) + sizeof(WCHAR);
  2050. pIniMonitor = AllocSplMem(cb);
  2051. if( !pIniMonitor ){
  2052. goto Fail;
  2053. }
  2054. StringCbCopy((LPWSTR)(pIniMonitor+1), cb - sizeof(*pIniMonitor), pMonitorName);
  2055. pIniMonitor->pName = (LPWSTR)(pIniMonitor+1);
  2056. pIniMonitor->signature = IMO_SIGNATURE;
  2057. pIniMonitor->pMonitorDll = AllocSplStr(pMonitorDll);
  2058. pIniMonitor->pIniSpooler = pIniSpooler;
  2059. if( !pIniMonitor->pMonitorDll ){
  2060. goto Fail;
  2061. }
  2062. //
  2063. // Load the library, but don't show any hard error popups if it's an
  2064. // invalid binary.
  2065. //
  2066. INCSPOOLERREF( pIniSpooler );
  2067. LeaveSplSem();
  2068. uOldErrMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  2069. pIniMonitor->hModule = LoadLibrary(pMonitorDll);
  2070. SetErrorMode( uOldErrMode );
  2071. EnterSplSem();
  2072. DECSPOOLERREF( pIniSpooler );
  2073. if (!pIniMonitor->hModule) {
  2074. DBGMSG(DBG_WARNING, ("CreateMonitorEntry( %ws, %ws ) LoadLibrary failed %d\n",
  2075. pMonitorDll ? pMonitorDll : L"(NULL)",
  2076. pMonitorName ? pMonitorName : L"(NULL)",
  2077. GetLastError()));
  2078. goto Fail;
  2079. }
  2080. GetRegistryLocation( pIniSpooler->hckRoot,
  2081. pIniSpooler->pszRegistryMonitors,
  2082. &hKeyOut,
  2083. &pszPathOut );
  2084. dwRetVal = StrNCatBuff( szRegistryRoot,
  2085. COUNTOF(szRegistryRoot),
  2086. pszPathOut,
  2087. L"\\",
  2088. pMonitorName,
  2089. NULL );
  2090. if (dwRetVal != ERROR_SUCCESS)
  2091. {
  2092. SetLastError(ERROR_INVALID_PRINT_MONITOR);
  2093. goto Fail;
  2094. }
  2095. //
  2096. // Try calling the entry points in the following order:
  2097. // InitializePrintMonitor2 (used for clustering),
  2098. // InitializePrintMonitor,
  2099. // InitializeMonitorEx,
  2100. // InitializeMonitor
  2101. //
  2102. (FARPROC)pfnInitializePrintMonitor2 = GetProcAddress(
  2103. pIniMonitor->hModule,
  2104. "InitializePrintMonitor2" );
  2105. if( !pfnInitializePrintMonitor2 ){
  2106. //
  2107. // If this is clustered spooler, then only InitializePrintMonitor2
  2108. // monitors are supported.
  2109. //
  2110. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  2111. goto Fail;
  2112. }
  2113. //
  2114. // Add the parth to the Monitor name here.
  2115. //
  2116. pReturnValue = InitializeDMonitor( pIniMonitor,
  2117. szRegistryRoot );
  2118. if( pReturnValue == NULL ||
  2119. pReturnValue == (PINIMONITOR)-1 ){
  2120. goto Fail;
  2121. }
  2122. } else {
  2123. PMONITORINIT pMonitorInit;
  2124. DWORD Status;
  2125. PMONITOR2 pMonitor2 = NULL;
  2126. INCSPOOLERREF( pIniSpooler );
  2127. LeaveSplSem();
  2128. //
  2129. // kKeyOut must either be not HKLM, or it must not be a cluster.
  2130. // If it is both a cluster and also uses HKLM, then we have an error.
  2131. // This should never happen because only win32spl uses an absolute
  2132. // path.
  2133. //
  2134. SPLASSERT( (hKeyOut != HKEY_LOCAL_MACHINE) ||
  2135. !(pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ));
  2136. pMonitorInit = (PMONITORINIT)AllocSplMem( sizeof( MONITORINIT ));
  2137. if( !pMonitorInit ){
  2138. goto FailOutsideSem;
  2139. }
  2140. pMonitorInit->pszServerName = AllocSplStr( pIniSpooler->pMachineName );
  2141. if( !pMonitorInit->pszServerName ){
  2142. goto FailOutsideSem;
  2143. }
  2144. pMonitorInit->cbSize = sizeof( MONITORINIT );
  2145. pMonitorInit->hSpooler = (HANDLE)pIniSpooler;
  2146. pMonitorInit->pMonitorReg = &gMonitorReg;
  2147. pMonitorInit->bLocal = ( pIniSpooler == pLocalIniSpooler );
  2148. pIniMonitor->pMonitorInit = pMonitorInit;
  2149. Status = SplRegCreateKey( hKeyOut,
  2150. szRegistryRoot,
  2151. 0,
  2152. KEY_READ | KEY_WRITE | DELETE,
  2153. NULL,
  2154. &pMonitorInit->hckRegistryRoot,
  2155. NULL,
  2156. pIniSpooler );
  2157. //
  2158. // If we can't create the hck root key, then fail
  2159. // the call. We should log an event here too.
  2160. //
  2161. if( Status == ERROR_SUCCESS ){
  2162. pMonitor2 = (*pfnInitializePrintMonitor2)(
  2163. pMonitorInit,
  2164. &pIniMonitor->hMonitor );
  2165. if( pMonitor2 ){
  2166. DBGMSG( DBG_TRACE,
  2167. ( "CreateMonitorEntry: opened %x %x on %x\n",
  2168. pIniMonitor, pIniMonitor->hMonitor, pIniSpooler ));
  2169. //
  2170. // Succeeded, copy over the pMonitor2 structure into
  2171. // pIniMonitor->Monitor2.
  2172. //
  2173. CopyMemory((LPBYTE)&pIniMonitor->Monitor2, (LPBYTE)pMonitor2, min(pMonitor2->cbSize, sizeof(MONITOR2)));
  2174. //
  2175. // Check if the monitor2 supports Shutdown.
  2176. //
  2177. // Raid#: 193150 - Accept any size Monitor2 as long as it supports Shutdown
  2178. //
  2179. if( !pIniMonitor->Monitor2.pfnShutdown ){
  2180. DBGMSG( DBG_ERROR,
  2181. ( "Invalid print monitor %ws (no shutdown)\n",
  2182. pMonitorName ));
  2183. SetLastError(ERROR_INVALID_PRINT_MONITOR);
  2184. DECSPOOLERREF( pIniSpooler );
  2185. goto FailOutsideSem;
  2186. }
  2187. //
  2188. // Initialize an uplevel monitor for downlevel support.
  2189. //
  2190. InitializeUMonitor( pIniMonitor );
  2191. } else {
  2192. DBGMSG( DBG_WARN,
  2193. ( "CreateMonitorEntry: InitializePrintMonitor2 failed %d\n",
  2194. GetLastError() ));
  2195. }
  2196. } else {
  2197. DBGMSG( DBG_WARN,
  2198. ( "CreateMonitorEntry: Unable to create hckRoot "TSTR"\n",
  2199. pMonitorName ));
  2200. }
  2201. EnterSplSem();
  2202. DECSPOOLERREF( pIniSpooler );
  2203. if( !pMonitor2 ){
  2204. goto Fail;
  2205. }
  2206. pIniMonitor->bUplevel = TRUE;
  2207. }
  2208. //
  2209. // Check if the monitor supports essential functions
  2210. //
  2211. if ( (!pIniMonitor->Monitor2.pfnOpenPort &&
  2212. !pIniMonitor->Monitor2.pfnOpenPortEx) ||
  2213. !pIniMonitor->Monitor2.pfnClosePort ||
  2214. !pIniMonitor->Monitor2.pfnStartDocPort ||
  2215. !pIniMonitor->Monitor2.pfnWritePort ||
  2216. !pIniMonitor->Monitor2.pfnReadPort ||
  2217. !pIniMonitor->Monitor2.pfnEndDocPort ) {
  2218. DBGMSG(DBG_ERROR, ("Invalid print monitor %ws\n", pMonitorName));
  2219. SetLastError(ERROR_INVALID_PRINT_MONITOR);
  2220. goto Fail;
  2221. }
  2222. if (FindMonitor(pMonitorName, pIniSpooler)) {
  2223. SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
  2224. goto Fail;
  2225. }
  2226. if ((pIniMonitor->Monitor2.pfnEnumPorts) &&
  2227. !(*pIniMonitor->Monitor2.pfnEnumPorts)(
  2228. pIniMonitor->hMonitor,
  2229. NULL,
  2230. 1,
  2231. NULL,
  2232. 0,
  2233. &cbNeeded,
  2234. &cReturned)) {
  2235. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  2236. if (pPorts = AllocSplMem(cbNeeded)) {
  2237. pPort = pPorts;
  2238. if ((*pIniMonitor->Monitor2.pfnEnumPorts)(
  2239. pIniMonitor->hMonitor,
  2240. NULL,
  2241. 1,
  2242. (LPBYTE)pPorts,
  2243. cbNeeded,
  2244. &cbNeeded,
  2245. &cReturned)) {
  2246. while (cReturned--) {
  2247. CreatePortEntry(pPort->pName,
  2248. pIniMonitor,
  2249. pIniSpooler);
  2250. pPort++;
  2251. }
  2252. }
  2253. FreeSplMem(pPorts);
  2254. }
  2255. }
  2256. }
  2257. DBGMSG(DBG_TRACE, ("CreateMonitorEntry( %ws, %ws, %ws ) returning %x\n",
  2258. pMonitorDll ? pMonitorDll : L"(NULL)",
  2259. pMonitorName ? pMonitorName : L"(NULL)",
  2260. szRegistryRoot, pIniMonitor));
  2261. SplInSem();
  2262. //
  2263. // Success, link it up.
  2264. //
  2265. pIniMonitor->pNext = pIniSpooler->pIniMonitor;
  2266. pIniSpooler->pIniMonitor = pIniMonitor;
  2267. return pIniMonitor;
  2268. FailOutsideSem:
  2269. EnterSplSem();
  2270. Fail:
  2271. FreeIniMonitor( pIniMonitor );
  2272. return pReturnValue;
  2273. }
  2274. BOOL
  2275. BuildAllPorts(
  2276. PINISPOOLER pIniSpooler
  2277. )
  2278. {
  2279. DWORD cchData, cbDll, cMonitors;
  2280. WCHAR Dll[MAX_PATH];
  2281. WCHAR MonitorName[MAX_PATH];
  2282. WCHAR RegistryPath[MAX_PATH];
  2283. HKEY hKey, hKey1, hKeyOut;
  2284. LPWSTR pszPathOut;
  2285. LONG Status;
  2286. PINIMONITOR pReturnValue = (PINIMONITOR)-1;
  2287. PINISPOOLER pIniSpoolerMonitor;
  2288. //
  2289. // For pLocalIniSpooler or clustered spooler, read the monitors out
  2290. // of HKLM (the same monitors used in pLocalIniMonitor). This is because
  2291. // you install a monitor for each node, then that monitor is initialized
  2292. // for the local spooler and all clustered spoolers.
  2293. //
  2294. // You install monitors on the node, not on specific cluster groups.
  2295. //
  2296. if( pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL ){
  2297. pIniSpoolerMonitor = pLocalIniSpooler;
  2298. } else {
  2299. pIniSpoolerMonitor = pIniSpooler;
  2300. }
  2301. GetRegistryLocation( pIniSpoolerMonitor->hckRoot,
  2302. pIniSpooler->pszRegistryMonitors,
  2303. &hKeyOut,
  2304. &pszPathOut );
  2305. Status = RegOpenKeyEx( hKeyOut,
  2306. pszPathOut,
  2307. 0,
  2308. KEY_READ,
  2309. &hKey);
  2310. if (Status != ERROR_SUCCESS)
  2311. return FALSE;
  2312. cMonitors=0;
  2313. cchData = COUNTOF( MonitorName );
  2314. while (RegEnumKeyEx(hKey, cMonitors, MonitorName, &cchData, NULL, NULL,
  2315. NULL, NULL) == ERROR_SUCCESS) {
  2316. DBGMSG(DBG_TRACE, ("Found monitor %ws\n", MonitorName));
  2317. if (RegOpenKeyEx(hKey, MonitorName, 0, KEY_READ, &hKey1)
  2318. == ERROR_SUCCESS) {
  2319. cbDll = sizeof(Dll);
  2320. if (RegQueryValueEx(hKey1, L"Driver", NULL, NULL,
  2321. (LPBYTE)Dll, &cbDll)
  2322. == ERROR_SUCCESS) {
  2323. CreateMonitorEntry(Dll, MonitorName, pIniSpooler);
  2324. }
  2325. RegCloseKey(hKey1);
  2326. }
  2327. cMonitors++;
  2328. cchData = COUNTOF( MonitorName );
  2329. }
  2330. RegCloseKey(hKey);
  2331. return TRUE;
  2332. }
  2333. /*
  2334. Current Directory == <NT directory>\system32\spool\printers
  2335. pFindFileData->cFileName == 0
  2336. */
  2337. BOOL
  2338. BuildPrinterInfo(
  2339. PINISPOOLER pIniSpooler,
  2340. BOOL UpdateChangeID
  2341. )
  2342. {
  2343. WCHAR PrinterName[MAX_PRINTER_NAME];
  2344. WCHAR szData[MAX_PATH];
  2345. WCHAR szDefaultPrinterDirectory[MAX_PATH];
  2346. DWORD cbData, i;
  2347. DWORD cbSecurity, dwLastError;
  2348. DWORD cPrinters, Type;
  2349. HKEY hPrinterKey;
  2350. PINIPRINTER pIniPrinter;
  2351. PINIPORT pIniPort;
  2352. LONG Status;
  2353. SECURITY_ATTRIBUTES SecurityAttributes;
  2354. PKEYDATA pKeyData = NULL;
  2355. BOOL bUpdateRegistryForThisPrinter = UpdateChangeID;
  2356. BOOL bWriteDirectory = FALSE;
  2357. BOOL bAllocMem = FALSE;
  2358. BOOL bNoPorts = FALSE;
  2359. LPWSTR szPortData;
  2360. //
  2361. // Has user specified Default Spool Directory ?
  2362. //
  2363. cbData = sizeof( szData );
  2364. *szData = (WCHAR)0;
  2365. Status = SplRegQueryValue( pIniSpooler->hckPrinters,
  2366. SPLREG_DEFAULT_SPOOL_DIRECTORY,
  2367. NULL,
  2368. (LPBYTE)szData,
  2369. &cbData,
  2370. pIniSpooler );
  2371. if (Status == ERROR_SUCCESS) { // found a value, so verify the directory
  2372. if (!(pIniSpooler->pDefaultSpoolDir = AllocSplStr( szData ))) // Copies szData to pDefaultSpoolDir
  2373. return FALSE;
  2374. } else {
  2375. bWriteDirectory = TRUE; // No registry directory, so create one
  2376. }
  2377. // Copy pDefaultSpoolDir to szDefaultPrinterDirectory
  2378. GetPrinterDirectory(NULL, FALSE, szDefaultPrinterDirectory, COUNTOF(szDefaultPrinterDirectory), pIniSpooler);
  2379. if (!pIniSpooler->pDefaultSpoolDir)
  2380. return FALSE;
  2381. // Create the directory with the proper security, or fail trying
  2382. SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  2383. SecurityAttributes.lpSecurityDescriptor = CreateEverybodySecurityDescriptor();
  2384. SecurityAttributes.bInheritHandle = FALSE;
  2385. //
  2386. // CreateDirectory limits the length of a directory to 248 (MAX_PATH-12)
  2387. // characters. By calculating the length, we ensure that an escape sequence
  2388. // will not lead to the creation of a directory with a name longer than 248
  2389. //
  2390. if (wcslen(szDefaultPrinterDirectory) > MAX_PATH - 12 ||
  2391. !CreateDirectory(szDefaultPrinterDirectory, &SecurityAttributes)) {
  2392. // Failed to create the directory? Back to factory default
  2393. bWriteDirectory = TRUE;
  2394. if (GetLastError() != ERROR_ALREADY_EXISTS) {
  2395. //
  2396. // In the clustered case, just fail.
  2397. //
  2398. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  2399. return FALSE;
  2400. }
  2401. DBGMSG(DBG_WARNING, ("Failed to create DefaultSpoolDirectory %ws\n", szDefaultPrinterDirectory));
  2402. FreeSplStr(pIniSpooler->pDefaultSpoolDir);
  2403. pIniSpooler->pDefaultSpoolDir = NULL; // This tells GetPrinterDirectory to alloc pDefaultSpoolDir
  2404. GetPrinterDirectory(NULL, FALSE, szDefaultPrinterDirectory, COUNTOF(szDefaultPrinterDirectory), pIniSpooler);
  2405. if (!pIniSpooler->pDefaultSpoolDir)
  2406. return FALSE;
  2407. Status = CreateDirectory(szDefaultPrinterDirectory, &SecurityAttributes);
  2408. if (Status != ERROR_SUCCESS && Status != ERROR_ALREADY_EXISTS) {
  2409. DBGMSG(DBG_WARNING, ("Failed to create DefaultSpoolDirectory %ws\n", szDefaultPrinterDirectory));
  2410. FreeSplStr(pIniSpooler->pDefaultSpoolDir);
  2411. pIniSpooler->pDefaultSpoolDir = NULL;
  2412. return FALSE;
  2413. }
  2414. }
  2415. }
  2416. LocalFree(SecurityAttributes.lpSecurityDescriptor);
  2417. if (bWriteDirectory) {
  2418. Status = SetPrinterDataServer( pIniSpooler,
  2419. SPLREG_DEFAULT_SPOOL_DIRECTORY,
  2420. REG_SZ,
  2421. (LPBYTE) pIniSpooler->pDefaultSpoolDir,
  2422. wcslen(pIniSpooler->pDefaultSpoolDir)*sizeof(WCHAR) + sizeof(WCHAR));
  2423. }
  2424. cPrinters=0;
  2425. cbData = COUNTOF(PrinterName);
  2426. while( SplRegEnumKey( pIniSpooler->hckPrinters,
  2427. cPrinters,
  2428. PrinterName,
  2429. &cbData,
  2430. NULL,
  2431. pIniSpooler ) == ERROR_SUCCESS) {
  2432. DBGMSG(DBG_TRACE, ("Found printer %ws\n", PrinterName));
  2433. if( SplRegCreateKey( pIniSpooler->hckPrinters,
  2434. PrinterName,
  2435. 0,
  2436. KEY_READ,
  2437. NULL,
  2438. &hPrinterKey,
  2439. NULL,
  2440. pIniSpooler ) == ERROR_SUCCESS ){
  2441. if ( pIniPrinter = AllocSplMem(sizeof(INIPRINTER) )) {
  2442. //
  2443. // Reference count the pIniSpooler.
  2444. //
  2445. INCSPOOLERREF( pIniSpooler );
  2446. pIniPrinter->signature = IP_SIGNATURE;
  2447. GetSystemTime( &pIniPrinter->stUpTime );
  2448. // Give the printer a unique session ID to pass around in notifications
  2449. pIniPrinter->dwUniqueSessionID = dwUniquePrinterSessionID++;
  2450. cbData = sizeof(szData);
  2451. *szData = (WCHAR)0;
  2452. if (SplRegQueryValue(hPrinterKey,
  2453. szName,
  2454. NULL,
  2455. (LPBYTE)szData,
  2456. &cbData,
  2457. pIniSpooler) == ERROR_SUCCESS)
  2458. pIniPrinter->pName = AllocSplStr(szData);
  2459. //
  2460. // Get Spool Directory for this printer
  2461. //
  2462. cbData = sizeof(szData);
  2463. *szData = (WCHAR)0;
  2464. if (SplRegQueryValue( hPrinterKey,
  2465. szSpoolDir,
  2466. &Type,
  2467. (LPBYTE)szData,
  2468. &cbData,
  2469. pIniSpooler) == ERROR_SUCCESS) {
  2470. if ( *szData != (WCHAR)0 ) {
  2471. pIniPrinter->pSpoolDir = AllocSplStr(szData);
  2472. }
  2473. }
  2474. //
  2475. // Get ObjectGUID for this printer
  2476. //
  2477. cbData = sizeof(szData);
  2478. *szData = (WCHAR)0;
  2479. if (SplRegQueryValue( hPrinterKey,
  2480. szObjectGUID,
  2481. &Type,
  2482. (LPBYTE)szData,
  2483. &cbData,
  2484. pIniSpooler) == ERROR_SUCCESS) {
  2485. if ( *szData != (WCHAR)0 ) {
  2486. pIniPrinter->pszObjectGUID = AllocSplStr(szData);
  2487. }
  2488. }
  2489. //
  2490. // Get DsKeyUpdate and DsKeyUpdateForeground for this printer
  2491. //
  2492. cbData = sizeof(pIniPrinter->DsKeyUpdate );
  2493. SplRegQueryValue( hPrinterKey,
  2494. szDsKeyUpdate,
  2495. &Type,
  2496. (LPBYTE) &pIniPrinter->DsKeyUpdate,
  2497. &cbData,
  2498. pIniSpooler);
  2499. cbData = sizeof(pIniPrinter->DsKeyUpdateForeground );
  2500. SplRegQueryValue( hPrinterKey,
  2501. szDsKeyUpdateForeground,
  2502. &Type,
  2503. (LPBYTE) &pIniPrinter->DsKeyUpdateForeground,
  2504. &cbData,
  2505. pIniSpooler);
  2506. if ( !(pIniSpooler->SpoolerFlags & SPL_TYPE_CACHE) ) {
  2507. // We make sure that DsKeyUpdateForeground is consistent
  2508. // when the spooler startsup. Otherwise DsKeyUpdateForeground might be
  2509. // set without dwAction being set and the printer will always be in the
  2510. // IO_PENDING state.
  2511. if (pIniPrinter->DsKeyUpdateForeground & (DS_KEY_PUBLISH | DS_KEY_REPUBLISH | DS_KEY_UNPUBLISH)) {
  2512. if (pIniPrinter->DsKeyUpdateForeground & DS_KEY_PUBLISH) {
  2513. pIniPrinter->dwAction |= DSPRINT_PUBLISH;
  2514. } else if (pIniPrinter->DsKeyUpdateForeground & DS_KEY_REPUBLISH) {
  2515. pIniPrinter->dwAction |= DSPRINT_REPUBLISH;
  2516. } else if (pIniPrinter->DsKeyUpdateForeground & DS_KEY_UNPUBLISH) {
  2517. pIniPrinter->dwAction |= DSPRINT_UNPUBLISH;
  2518. }
  2519. pIniPrinter->DsKeyUpdateForeground &= ~(DS_KEY_PUBLISH | DS_KEY_REPUBLISH | DS_KEY_UNPUBLISH);
  2520. } else {
  2521. pIniPrinter->DsKeyUpdateForeground = 0;
  2522. }
  2523. } else {
  2524. //
  2525. // For connections, dwAction is read from registry. It is updated by
  2526. // caching code with the value on the server.
  2527. //
  2528. cbData = sizeof(pIniPrinter->dwAction);
  2529. SplRegQueryValue( hPrinterKey,
  2530. szAction,
  2531. &Type,
  2532. (LPBYTE) &pIniPrinter->dwAction,
  2533. &cbData,
  2534. pIniSpooler);
  2535. }
  2536. // Make Certain this Printers Printer directory exists
  2537. // with correct security
  2538. if ((pIniPrinter->pSpoolDir) &&
  2539. (wcscmp(pIniPrinter->pSpoolDir, szDefaultPrinterDirectory) != 0)) {
  2540. SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  2541. SecurityAttributes.lpSecurityDescriptor = CreateEverybodySecurityDescriptor();
  2542. SecurityAttributes.bInheritHandle = FALSE;
  2543. if (!CreateDirectory(pIniPrinter->pSpoolDir, &SecurityAttributes)) {
  2544. // Failed to Create the Directory, revert back
  2545. // to the default
  2546. if (GetLastError() != ERROR_ALREADY_EXISTS) {
  2547. DBGMSG(DBG_WARNING, ("Could not create printer spool directory %ws %d\n",
  2548. pIniPrinter->pSpoolDir, GetLastError() ));
  2549. pIniPrinter->pSpoolDir = NULL;
  2550. }
  2551. }
  2552. LocalFree(SecurityAttributes.lpSecurityDescriptor);
  2553. }
  2554. cbData = sizeof(szData);
  2555. *szData = (WCHAR)0;
  2556. if (SplRegQueryValue( hPrinterKey,
  2557. szShare,
  2558. &Type,
  2559. (LPBYTE)szData,
  2560. &cbData,
  2561. pIniSpooler) == ERROR_SUCCESS)
  2562. pIniPrinter->pShareName = AllocSplStr(szData);
  2563. cbData = sizeof(szData);
  2564. *szData = (WCHAR)0;
  2565. dwLastError = SplRegQueryValue( hPrinterKey,
  2566. szPort,
  2567. &Type,
  2568. (LPBYTE)szData,
  2569. &cbData,
  2570. pIniSpooler );
  2571. if ((dwLastError == ERROR_MORE_DATA) &&
  2572. (szPortData = AllocSplMem(cbData)))
  2573. {
  2574. bAllocMem = TRUE;
  2575. dwLastError = SplRegQueryValue( hPrinterKey,
  2576. szPort,
  2577. &Type,
  2578. (LPBYTE)szPortData,
  2579. &cbData,
  2580. pIniSpooler );
  2581. }
  2582. else
  2583. {
  2584. bAllocMem = FALSE;
  2585. szPortData = szData;
  2586. }
  2587. if (dwLastError == ERROR_SUCCESS)
  2588. {
  2589. if (pKeyData = CreateTokenList(szPortData)) {
  2590. if (!ValidatePortTokenList( pKeyData, pIniSpooler, TRUE, &bNoPorts)) {
  2591. LogFatalPortError(pIniSpooler, pIniPrinter->pName);
  2592. FreePortTokenList(pKeyData);
  2593. pKeyData = NULL;
  2594. } else {
  2595. //
  2596. // If there are no ports on the printer, just log
  2597. // a warning message, but only for pooled printers.
  2598. //
  2599. if (bNoPorts && pKeyData->cTokens > 1) {
  2600. SplLogEvent( pIniSpooler,
  2601. LOG_WARNING,
  2602. MSG_NO_PORT_FOUND_FOR_PRINTER,
  2603. TRUE,
  2604. pIniPrinter->pName,
  2605. szPortData,
  2606. NULL );
  2607. }
  2608. pIniPrinter->ppIniPorts = AllocSplMem(pKeyData->cTokens * sizeof(PINIPORT));
  2609. }
  2610. }
  2611. }
  2612. if (bAllocMem)
  2613. {
  2614. FreeSplMem(szPortData);
  2615. szPortData = NULL;
  2616. }
  2617. cbData = sizeof(szData);
  2618. *szData = (WCHAR)0;
  2619. if (SplRegQueryValue( hPrinterKey,
  2620. szPrintProcessor,
  2621. &Type,
  2622. (LPBYTE)szData,
  2623. &cbData,
  2624. pIniSpooler ) == ERROR_SUCCESS)
  2625. {
  2626. //
  2627. // We are trying to find the environment relative to the pIniSpooler.
  2628. // The local spooler and cluster spoolers do not share the same
  2629. // environment strucutres anymore
  2630. //
  2631. PINIENVIRONMENT pIniEnv;
  2632. if (pIniEnv = FindEnvironment(szEnvironment, pIniSpooler))
  2633. {
  2634. pIniPrinter->pIniPrintProc = FindPrintProc(szData, pIniEnv);
  2635. }
  2636. }
  2637. cbData = sizeof(szData);
  2638. *szData = (WCHAR)0;
  2639. if (SplRegQueryValue( hPrinterKey,
  2640. szDatatype,
  2641. &Type,
  2642. (LPBYTE)szData,
  2643. &cbData,
  2644. pIniSpooler ) == ERROR_SUCCESS)
  2645. pIniPrinter->pDatatype = AllocSplStr(szData);
  2646. cbData = sizeof(szData);
  2647. *szData = (WCHAR)0;
  2648. if (SplRegQueryValue( hPrinterKey,
  2649. szDriver,
  2650. &Type,
  2651. (LPBYTE)szData,
  2652. &cbData,
  2653. pIniSpooler ) == ERROR_SUCCESS) {
  2654. pIniPrinter->pIniDriver = (PINIDRIVER)FindLocalDriver(pIniSpooler, szData);
  2655. if (!pIniPrinter->pIniDriver)
  2656. {
  2657. //
  2658. // The hosting node of the cluster spooler was upgraded to Whistler.
  2659. //
  2660. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  2661. pIniSpooler->dwClusNodeUpgraded &&
  2662. //
  2663. // The driver was not found in the cluster spooler, not on the cluster disk.
  2664. // We attempt to install the driver from the local spooler to our cluster
  2665. // spooler. This will get the driver files on the cluster disk.
  2666. //
  2667. AddLocalDriverToClusterSpooler(szData, pIniSpooler) == ERROR_SUCCESS)
  2668. {
  2669. //
  2670. // Search again for the driver that must have been added
  2671. //
  2672. pIniPrinter->pIniDriver = (PINIDRIVER)FindLocalDriver(pIniSpooler, szData);
  2673. }
  2674. }
  2675. if (!pIniPrinter->pIniDriver)
  2676. {
  2677. SplLogEvent(pLocalIniSpooler,
  2678. LOG_ERROR,
  2679. MSG_NO_DRIVER_FOUND_FOR_PRINTER,
  2680. TRUE,
  2681. pIniPrinter->pName,
  2682. szData,
  2683. NULL);
  2684. }
  2685. }
  2686. cbData = sizeof(szData);
  2687. *szData = (WCHAR)0;
  2688. if (SplRegQueryValue( hPrinterKey,
  2689. szLocation,
  2690. &Type,
  2691. (LPBYTE)szData,
  2692. &cbData,
  2693. pIniSpooler ) == ERROR_SUCCESS)
  2694. pIniPrinter->pLocation = AllocSplStr(szData);
  2695. cbData = sizeof(szData);
  2696. *szData = (WCHAR)0;
  2697. if (SplRegQueryValue( hPrinterKey,
  2698. szDescription,
  2699. &Type,
  2700. (LPBYTE)szData,
  2701. &cbData, pIniSpooler ) == ERROR_SUCCESS)
  2702. pIniPrinter->pComment = AllocSplStr(szData);
  2703. cbData = sizeof(szData);
  2704. *szData = (WCHAR)0;
  2705. if (SplRegQueryValue( hPrinterKey,
  2706. szParameters,
  2707. &Type,
  2708. (LPBYTE)szData,
  2709. &cbData, pIniSpooler ) == ERROR_SUCCESS)
  2710. pIniPrinter->pParameters = AllocSplStr(szData);
  2711. cbData = sizeof(szData);
  2712. *szData = (WCHAR)0;
  2713. if (SplRegQueryValue( hPrinterKey,
  2714. szSepFile,
  2715. &Type,
  2716. (LPBYTE)szData,
  2717. &cbData, pIniSpooler ) == ERROR_SUCCESS)
  2718. pIniPrinter->pSepFile = AllocSplStr(szData);
  2719. cbData = sizeof(pIniPrinter->Attributes);
  2720. SplRegQueryValue( hPrinterKey,
  2721. szAttributes,
  2722. NULL,
  2723. (LPBYTE)&pIniPrinter->Attributes,
  2724. &cbData,
  2725. pIniSpooler );
  2726. cbData = sizeof(pIniPrinter->Status);
  2727. Status = SplRegQueryValue( hPrinterKey,
  2728. szStatus,
  2729. &Type,
  2730. (LPBYTE)&pIniPrinter->Status,
  2731. &cbData,
  2732. pIniSpooler );
  2733. pIniPrinter->Status |= PRINTER_FROM_REG;
  2734. if ( Status == ERROR_SUCCESS ) {
  2735. pIniPrinter->Status &= ( PRINTER_PAUSED |
  2736. PRINTER_PENDING_DELETION |
  2737. PRINTER_ZOMBIE_OBJECT |
  2738. PRINTER_FROM_REG |
  2739. PRINTER_OK |
  2740. PRINTER_PENDING_CREATION );
  2741. } else {
  2742. pIniPrinter->Status |= PRINTER_PENDING_CREATION ;
  2743. }
  2744. // Half formed printers should be deleted
  2745. // before they cause us trouble
  2746. if ( pIniPrinter->Status & PRINTER_PENDING_CREATION ) {
  2747. pIniPrinter->Status |= PRINTER_PENDING_DELETION ;
  2748. }
  2749. cbData = sizeof(pIniPrinter->Priority);
  2750. SplRegQueryValue( hPrinterKey,
  2751. szPriority,
  2752. &Type,
  2753. (LPBYTE)&pIniPrinter->Priority,
  2754. &cbData,
  2755. pIniSpooler );
  2756. cbData = sizeof(pIniPrinter->DefaultPriority);
  2757. SplRegQueryValue( hPrinterKey,
  2758. szDefaultPriority,
  2759. &Type,
  2760. (LPBYTE)&pIniPrinter->DefaultPriority,
  2761. &cbData,
  2762. pIniSpooler );
  2763. cbData = sizeof(pIniPrinter->UntilTime);
  2764. SplRegQueryValue( hPrinterKey,
  2765. szUntilTime,
  2766. &Type,
  2767. (LPBYTE)&pIniPrinter->UntilTime,
  2768. &cbData,
  2769. pIniSpooler );
  2770. cbData = sizeof(pIniPrinter->StartTime);
  2771. SplRegQueryValue( hPrinterKey,
  2772. szStartTime,
  2773. &Type,
  2774. (LPBYTE)&pIniPrinter->StartTime,
  2775. &cbData,
  2776. pIniSpooler );
  2777. cbData = sizeof(pIniPrinter->dnsTimeout);
  2778. if ( SplRegQueryValue( hPrinterKey,
  2779. szDNSTimeout,
  2780. &Type,
  2781. (LPBYTE)&pIniPrinter->dnsTimeout,
  2782. &cbData,
  2783. pIniSpooler ) != ERROR_SUCCESS ) {
  2784. pIniPrinter->dnsTimeout = DEFAULT_DNS_TIMEOUT;
  2785. }
  2786. cbData = sizeof(pIniPrinter->txTimeout);
  2787. if ( SplRegQueryValue( hPrinterKey,
  2788. szTXTimeout,
  2789. &Type,
  2790. (LPBYTE)&pIniPrinter->txTimeout,
  2791. &cbData,
  2792. pIniSpooler ) != ERROR_SUCCESS ) {
  2793. pIniPrinter->txTimeout = DEFAULT_TX_TIMEOUT;
  2794. }
  2795. cbData = sizeof( pIniPrinter->cChangeID ) ;
  2796. if ( SplRegQueryValue( hPrinterKey,
  2797. szTimeLastChange,
  2798. &Type,
  2799. (LPBYTE)&pIniPrinter->cChangeID,
  2800. &cbData,
  2801. pIniSpooler ) != ERROR_SUCCESS ) {
  2802. // Current Registry Doesn't have a UniqueID
  2803. // Make sure one gets written
  2804. bUpdateRegistryForThisPrinter = TRUE;
  2805. }
  2806. pIniPrinter->dwPrivateFlag = 0;
  2807. pIniPrinter->cbDevMode = 0;
  2808. pIniPrinter->pDevMode = NULL;
  2809. if (SplRegQueryValue( hPrinterKey,
  2810. szDevMode,
  2811. &Type,
  2812. NULL,
  2813. &pIniPrinter->cbDevMode,
  2814. pIniSpooler ) == ERROR_SUCCESS) {
  2815. if (pIniPrinter->cbDevMode) {
  2816. pIniPrinter->pDevMode = AllocSplMem(pIniPrinter->cbDevMode);
  2817. SplRegQueryValue( hPrinterKey,
  2818. szDevMode,
  2819. &Type,
  2820. (LPBYTE)pIniPrinter->pDevMode,
  2821. &pIniPrinter->cbDevMode,
  2822. pIniSpooler );
  2823. }
  2824. }
  2825. //
  2826. // A Provider might want to Read Extra Data from Registry
  2827. //
  2828. if ( pIniSpooler->pfnReadRegistryExtra != NULL ) {
  2829. pIniPrinter->pExtraData = (LPBYTE)(*pIniSpooler->pfnReadRegistryExtra)(hPrinterKey);
  2830. }
  2831. /* SECURITY */
  2832. Status = SplRegQueryValue( hPrinterKey,
  2833. szSecurity,
  2834. NULL,
  2835. NULL,
  2836. &cbSecurity,
  2837. pIniSpooler );
  2838. if ((Status == ERROR_MORE_DATA) || (Status == ERROR_SUCCESS)) {
  2839. /* Use the process' heap to allocate security descriptors,
  2840. * so that they can be passed to the security API, which
  2841. * may need to reallocate them.
  2842. */
  2843. if (pIniPrinter->pSecurityDescriptor =
  2844. LocalAlloc(0, cbSecurity)) {
  2845. if (Status = SplRegQueryValue( hPrinterKey,
  2846. szSecurity,
  2847. NULL,
  2848. pIniPrinter->pSecurityDescriptor,
  2849. &cbSecurity,
  2850. pIniSpooler ) != ERROR_SUCCESS) {
  2851. LocalFree(pIniPrinter->pSecurityDescriptor);
  2852. pIniPrinter->pSecurityDescriptor = NULL;
  2853. DBGMSG( DBG_WARNING,
  2854. ( "RegQueryValue returned %d on Permissions for %ws (%ws)\n",
  2855. Status,
  2856. pIniPrinter->pName ?
  2857. pIniPrinter->pName :
  2858. szNull,
  2859. PrinterName) );
  2860. }
  2861. }
  2862. } else {
  2863. pIniPrinter->pSecurityDescriptor = NULL;
  2864. DBGMSG( DBG_WARNING,
  2865. ( "RegQueryValue (2) returned %d on Permissions for %ws (%ws)\n",
  2866. Status,
  2867. pIniPrinter->pName ?
  2868. pIniPrinter->pName :
  2869. szNull,
  2870. PrinterName) );
  2871. }
  2872. pIniPrinter->MasqCache.bThreadRunning = FALSE;
  2873. pIniPrinter->MasqCache.cJobs = 0;
  2874. pIniPrinter->MasqCache.Status = 0;
  2875. pIniPrinter->MasqCache.dwError = ERROR_SUCCESS;
  2876. /* END SECURITY */
  2877. if ( pIniPrinter->pName &&
  2878. pIniPrinter->pShareName &&
  2879. pKeyData &&
  2880. pIniPrinter->ppIniPorts &&
  2881. pIniPrinter->pIniPrintProc &&
  2882. pIniPrinter->pIniDriver &&
  2883. pIniPrinter->pLocation &&
  2884. pIniPrinter->pComment &&
  2885. pIniPrinter->pSecurityDescriptor
  2886. #if DBG
  2887. && ( IsValidSecurityDescriptor (pIniPrinter->pSecurityDescriptor)
  2888. ? TRUE
  2889. : (DBGMSG( DBG_SECURITY,
  2890. ( "The security descriptor for %ws (%ws) is invalid\n",
  2891. pIniPrinter->pName ?
  2892. pIniPrinter->pName :
  2893. szNull,
  2894. PrinterName)), /* (sequential evaluation) */
  2895. FALSE) )
  2896. #endif /* DBG */
  2897. ) {
  2898. pIniPrinter->pIniFirstJob = pIniPrinter->pIniLastJob = NULL;
  2899. pIniPrinter->pIniPrintProc->cRef++;
  2900. INCDRIVERREF( pIniPrinter->pIniDriver );
  2901. for (i=0; i<pKeyData->cTokens; i++) {
  2902. pIniPort = (PINIPORT)pKeyData->pTokens[i];
  2903. pIniPrinter->ppIniPorts[i] = pIniPort;
  2904. pIniPort->ppIniPrinter =
  2905. ReallocSplMem(pIniPort->ppIniPrinter,
  2906. pIniPort->cPrinters *
  2907. sizeof(pIniPort->ppIniPrinter),
  2908. (pIniPort->cPrinters+1) *
  2909. sizeof(pIniPort->ppIniPrinter));
  2910. if (!pIniPort->ppIniPrinter) {
  2911. DBGMSG(DBG_WARNING, ("Failed to allocate memory for printer info\n." ));
  2912. }
  2913. pIniPort->ppIniPrinter[pIniPort->cPrinters] =
  2914. pIniPrinter;
  2915. //
  2916. // With the new monitors localspl does the
  2917. // redirection for LPT, COM ports
  2918. //
  2919. if ( !pIniPort->cPrinters++ )
  2920. CreateRedirectionThread(pIniPort);
  2921. }
  2922. pIniPrinter->cPorts = pKeyData->cTokens;
  2923. pIniPrinter->Priority =
  2924. pIniPrinter->Priority ? pIniPrinter->Priority
  2925. : DEF_PRIORITY;
  2926. if ((pIniPrinter->Attributes &
  2927. (PRINTER_ATTRIBUTE_QUEUED | PRINTER_ATTRIBUTE_DIRECT)) ==
  2928. (PRINTER_ATTRIBUTE_QUEUED | PRINTER_ATTRIBUTE_DIRECT))
  2929. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_DIRECT;
  2930. //
  2931. // I f we're upgrading, fix the NT4 bug that broke Masc printers.
  2932. // UpdateChangeID is passed into us as dwUpgradeFlag, so it determines
  2933. // if we're in an upgrade state.
  2934. //
  2935. // The rules: Printer name starts with \\
  2936. // Port Name starts with \\
  2937. // It's on a local IniSpooler.
  2938. // The NETWORK and LOCAL bits are not set.
  2939. //
  2940. // If all the rules are met, set the NETWORK and LOCAL bits so the printer
  2941. // will behave properly.
  2942. //
  2943. if ( UpdateChangeID && (wcslen(pIniPrinter->pName) > 2) && pIniPrinter->cPorts &&
  2944. (*pIniPrinter->ppIniPorts)->pName && (wcslen((*pIniPrinter->ppIniPorts)->pName) > 2) &&
  2945. pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL)
  2946. {
  2947. WCHAR * pNameStr = pIniPrinter->pName;
  2948. WCHAR * pPortStr = (*pIniPrinter->ppIniPorts)->pName;
  2949. DWORD MascAttr = (PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL);
  2950. if ((pNameStr[0] == L'\\') && (pNameStr[1] == L'\\') &&
  2951. (pPortStr[0] == L'\\') && (pPortStr[1] == L'\\') &&
  2952. ((pIniPrinter->Attributes & MascAttr) == 0))
  2953. {
  2954. pIniPrinter->Attributes |= MascAttr;
  2955. }
  2956. }
  2957. //
  2958. // If there were no ports for the printer, we set the state to
  2959. // work offline, but not if this was a masque printer. (In
  2960. // which case PRINTER_ATTRIBUTE_NETWORK is also set).
  2961. //
  2962. if (bNoPorts && !(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_NETWORK)) {
  2963. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_WORK_OFFLINE;
  2964. }
  2965. pIniPrinter->pNext = pIniSpooler->pIniPrinter;
  2966. pIniPrinter->pIniSpooler = pIniSpooler;
  2967. pIniSpooler->pIniPrinter = pIniPrinter;
  2968. if ( bUpdateRegistryForThisPrinter ) {
  2969. UpdatePrinterIni( pIniPrinter , UPDATE_CHANGEID );
  2970. bUpdateRegistryForThisPrinter = UpdateChangeID;
  2971. }
  2972. } else {
  2973. DBGMSG( DBG_WARNING,
  2974. ( "Initialization of printer failed:\
  2975. \n\tpPrinterName:\t%ws\
  2976. \n\tKeyName:\t%ws\
  2977. \n\tpShareName:\t%ws\
  2978. \n\tpKeyData:\t%08x\
  2979. \n\tpIniPrintProc:\t%08x",
  2980. pIniPrinter->pName ? pIniPrinter->pName : szNull,
  2981. PrinterName,
  2982. pIniPrinter->pShareName ? pIniPrinter->pShareName : szNull ,
  2983. pKeyData,
  2984. pIniPrinter->pIniPrintProc ) );
  2985. /* Do this in two lumps, because otherwise NTSD might crash.
  2986. * (Raid bug #10650)
  2987. */
  2988. DBGMSG( DBG_WARNING,
  2989. ( " \n\tpIniDriver:\t%08x\
  2990. \n\tpLocation:\t%ws\
  2991. \n\tpComment:\t%ws\
  2992. \n\tpSecurity:\t%08x\
  2993. \n\tStatus:\t\t%08x %s\n\n",
  2994. pIniPrinter->pIniDriver,
  2995. pIniPrinter->pLocation ? pIniPrinter->pLocation : szNull,
  2996. pIniPrinter->pComment ? pIniPrinter->pComment : szNull,
  2997. pIniPrinter->pSecurityDescriptor,
  2998. pIniPrinter->Status,
  2999. ( pIniPrinter->Status & PRINTER_PENDING_DELETION
  3000. ? "Pending deletion" : "" ) ) );
  3001. FreeStructurePointers((LPBYTE)pIniPrinter,
  3002. NULL,
  3003. IniPrinterOffsets);
  3004. if (pIniPrinter->pSecurityDescriptor) {
  3005. LocalFree(pIniPrinter->pSecurityDescriptor);
  3006. pIniPrinter->pSecurityDescriptor = NULL;
  3007. }
  3008. if (( pIniSpooler->pfnFreePrinterExtra != NULL ) &&
  3009. ( pIniPrinter->pExtraData != NULL )) {
  3010. (*pIniSpooler->pfnFreePrinterExtra)( pIniPrinter->pExtraData );
  3011. }
  3012. //
  3013. // Reference count the pIniSpooler.
  3014. //
  3015. DECSPOOLERREF( pIniSpooler );
  3016. FreeSplMem(pIniPrinter);
  3017. }
  3018. FreePortTokenList(pKeyData);
  3019. pKeyData = NULL;
  3020. }
  3021. SplRegCloseKey( hPrinterKey, pIniSpooler );
  3022. }
  3023. cPrinters++;
  3024. cbData = COUNTOF(PrinterName);
  3025. }
  3026. if ( pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL) {
  3027. WCHAR szFilename[MAX_PATH];
  3028. HRESULT RetVal;
  3029. szFilename[0] = L'\0';
  3030. //
  3031. // FP Change
  3032. // Initialize the File pool.
  3033. //
  3034. if (pIniSpooler->hFilePool == INVALID_HANDLE_VALUE)
  3035. {
  3036. if (GetPrinterDirectory(NULL, FALSE, szFilename, MAX_PATH, pIniSpooler))
  3037. {
  3038. RetVal = CreateFilePool(
  3039. &pIniSpooler->hFilePool,
  3040. szFilename,
  3041. L"FP",
  3042. L".SPL",
  3043. L".SHD",
  3044. POOL_TIMEOUT,
  3045. MAX_POOL_FILES
  3046. );
  3047. if (FAILED(RetVal))
  3048. {
  3049. DBGMSG( DBG_WARN,
  3050. ( "SplCreateSpooler: Initialization of FilePool Failed %x\n",
  3051. RetVal ));
  3052. }
  3053. }
  3054. else
  3055. {
  3056. DBGMSG( DBG_WARN, ("CreateFilePool: GetPrinterDirectory Failed\n"));
  3057. }
  3058. }
  3059. // Read .SHD/.SPL files from common printer directory
  3060. ProcessShadowJobs( NULL, pIniSpooler );
  3061. // If any printer has a separate Printer directory process them
  3062. // also
  3063. if( GetPrinterDirectory(NULL, FALSE, szData, COUNTOF(szData), pIniSpooler) ) {
  3064. for ( pIniPrinter = pIniSpooler->pIniPrinter;
  3065. pIniPrinter;
  3066. pIniPrinter = pIniPrinter->pNext ) {
  3067. if ((pIniPrinter->pSpoolDir != NULL) &&
  3068. (_wcsicmp(szData, pIniPrinter->pSpoolDir) != 0)) {
  3069. ProcessShadowJobs(pIniPrinter, pIniSpooler);
  3070. }
  3071. }
  3072. }
  3073. }
  3074. UpdateReferencesToChainedJobs( pIniSpooler );
  3075. // Finally, go through all Printers looking for PENDING_DELETION
  3076. // if there are no jobs for that Printer, then we can delete it now
  3077. CleanupDeletedPrinters(pIniSpooler);
  3078. DBGMSG( DBG_TRACE, ("BuildPrinterInfo returned\n"));
  3079. return TRUE;
  3080. }
  3081. /* InitializePrintProcessor
  3082. *
  3083. * Allocates and initialises an INIPRINTPROC structure for the specified
  3084. * print processor and environment.
  3085. *
  3086. * Arguments:
  3087. *
  3088. * hLibrary - Handle to a previously loaded library ,
  3089. *
  3090. * pIniEnvironment - Data structure for the requested environment
  3091. * The pIniPrintProc field is initialised with the chain of print
  3092. * processor structures
  3093. *
  3094. * pPrintProcessorName - The Print Processor name e.g. WinPrint
  3095. *
  3096. * pDLLName - The DLL name, e.g. WINPRINT
  3097. *
  3098. * Returns:
  3099. *
  3100. * The allocated PiniPrintProc if no error was detected, otherwise FALSE.
  3101. *
  3102. *
  3103. */
  3104. PINIPRINTPROC
  3105. InitializePrintProcessor(
  3106. HINSTANCE hLibrary,
  3107. PINIENVIRONMENT pIniEnvironment,
  3108. LPWSTR pPrintProcessorName,
  3109. LPWSTR pDLLName
  3110. )
  3111. {
  3112. DWORD cb, cbNeeded, cReturned;
  3113. PINIPRINTPROC pIniPrintProc;
  3114. BOOL rc;
  3115. DWORD Error;
  3116. SIZE_T cchString = 0;
  3117. DBGMSG(DBG_TRACE, ("InitializePrintProcessor( %08x, %08x ,%ws, %ws)\n",
  3118. hLibrary, pPrintProcessorName, pPrintProcessorName, pDLLName));
  3119. cb = sizeof(INIPRINTPROC) +
  3120. wcslen(pPrintProcessorName)*sizeof(WCHAR) +
  3121. sizeof(WCHAR) +
  3122. wcslen(pDLLName)*sizeof(WCHAR) +
  3123. sizeof(WCHAR);
  3124. if (!(pIniPrintProc = (PINIPRINTPROC)AllocSplMem(cb))) {
  3125. DBGMSG(DBG_WARNING, ("Failed to allocate %d bytes for print processor\n.", cb));
  3126. return NULL;
  3127. }
  3128. __try {
  3129. InitializeCriticalSection(&pIniPrintProc->CriticalSection);
  3130. } __except(EXCEPTION_EXECUTE_HANDLER) {
  3131. FreeSplMem(pIniPrintProc);
  3132. SetLastError(GetExceptionCode());
  3133. return NULL;
  3134. }
  3135. /* Typical strings used to build the full path of the DLL:
  3136. *
  3137. * pPathName = C:\NT\SYSTEM32\SPOOL\PRTPROCS
  3138. * pEnvironment = W32X86
  3139. * pDLLName = WINPRINT.DLL
  3140. */
  3141. pIniPrintProc->hLibrary = hLibrary;
  3142. if (!pIniPrintProc->hLibrary) {
  3143. DeleteCriticalSection(&pIniPrintProc->CriticalSection);
  3144. FreeSplMem(pIniPrintProc);
  3145. DBGMSG(DBG_WARNING, ("Failed to LoadLibrary(%ws)\n", pDLLName));
  3146. return NULL;
  3147. }
  3148. pIniPrintProc->EnumDatatypes = (pfnEnumDatatypes) GetProcAddress(pIniPrintProc->hLibrary,
  3149. "EnumPrintProcessorDatatypesW");
  3150. if (!pIniPrintProc->EnumDatatypes) {
  3151. DBGMSG(DBG_WARNING, ("Failed to GetProcAddress(EnumDatatypes)\n"));
  3152. DeleteCriticalSection(&pIniPrintProc->CriticalSection);
  3153. FreeLibrary(pIniPrintProc->hLibrary);
  3154. FreeSplMem(pIniPrintProc);
  3155. return NULL;
  3156. }
  3157. rc = (*pIniPrintProc->EnumDatatypes)(NULL, pPrintProcessorName, 1, NULL, 0, &cbNeeded, &cReturned);
  3158. if (!rc && ((Error = GetLastError()) == ERROR_INSUFFICIENT_BUFFER)) {
  3159. pIniPrintProc->cbDatatypes = cbNeeded;
  3160. if (!(pIniPrintProc->pDatatypes = AllocSplMem(cbNeeded))) {
  3161. DBGMSG(DBG_WARNING, ("Failed to allocate %d bytes for print proc datatypes\n.", cbNeeded));
  3162. DeleteCriticalSection(&pIniPrintProc->CriticalSection);
  3163. FreeLibrary(pIniPrintProc->hLibrary);
  3164. FreeSplMem(pIniPrintProc);
  3165. return NULL;
  3166. }
  3167. if (!(*pIniPrintProc->EnumDatatypes)(NULL, pPrintProcessorName, 1,
  3168. (LPBYTE)pIniPrintProc->pDatatypes,
  3169. cbNeeded, &cbNeeded,
  3170. &pIniPrintProc->cDatatypes)) {
  3171. Error = GetLastError();
  3172. DBGMSG(DBG_WARNING, ("EnumPrintProcessorDatatypes(%ws) failed: Error %d\n",
  3173. pPrintProcessorName, Error));
  3174. }
  3175. } else if(rc) {
  3176. DBGMSG(DBG_WARNING, ("EnumPrintProcessorDatatypes(%ws) returned no data\n",
  3177. pPrintProcessorName));
  3178. } else {
  3179. DBGMSG(DBG_WARNING, ("EnumPrintProcessorDatatypes(%ws) failed: Error %d\n",
  3180. pPrintProcessorName, Error));
  3181. }
  3182. pIniPrintProc->Install = (pfnInstallPrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3183. "InstallPrintProcessor");
  3184. pIniPrintProc->Open = (pfnOpenPrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3185. "OpenPrintProcessor");
  3186. pIniPrintProc->Print = (pfnPrintDocOnPrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3187. "PrintDocumentOnPrintProcessor");
  3188. pIniPrintProc->Close = (pfnClosePrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3189. "ClosePrintProcessor");
  3190. pIniPrintProc->Control = (pfnControlPrintProcessor) GetProcAddress(pIniPrintProc->hLibrary,
  3191. "ControlPrintProcessor");
  3192. pIniPrintProc->GetPrintProcCaps = (pfnGetPrintProcCaps) GetProcAddress(pIniPrintProc->hLibrary,
  3193. "GetPrintProcessorCapabilities");
  3194. /* pName and pDLLName are contiguous with the INIPRINTPROC structure:
  3195. */
  3196. pIniPrintProc->pName = (LPWSTR)(pIniPrintProc+1);
  3197. StringCbCopy(pIniPrintProc->pName, cb - sizeof(*pIniPrintProc), pPrintProcessorName);
  3198. cchString = wcslen(pIniPrintProc->pName) + 1;
  3199. pIniPrintProc->pDLLName = (LPWSTR)(pIniPrintProc->pName + cchString);
  3200. StringCbCopy(pIniPrintProc->pDLLName, cb - sizeof(*pIniPrintProc) - cchString*sizeof(WCHAR), pDLLName);
  3201. pIniPrintProc->signature = IPP_SIGNATURE;
  3202. pIniPrintProc->pNext = pIniEnvironment->pIniPrintProc;
  3203. pIniEnvironment->pIniPrintProc = pIniPrintProc;
  3204. return pIniPrintProc;
  3205. }
  3206. /*++
  3207. Routine Name:
  3208. InitializeLocalPrintProcessor
  3209. Routine Description:
  3210. We start up the local print processor, we need to bump the reference count
  3211. on it library instance so that the cleanup code does not accidentally
  3212. unload localspl.dll while it is running.
  3213. Arguments:
  3214. pIniEnvironment - The environment to add the print processor to.
  3215. Return Value:
  3216. An HRESULT.
  3217. --*/
  3218. HRESULT
  3219. InitializeLocalPrintProcessor(
  3220. IN PINIENVIRONMENT pIniEnvironment
  3221. )
  3222. {
  3223. HRESULT hRetval = E_FAIL;
  3224. HINSTANCE hLocalSpl = NULL;
  3225. WCHAR szFilename[MAX_PATH];
  3226. hRetval = pIniEnvironment ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  3227. if (SUCCEEDED(hRetval))
  3228. {
  3229. hRetval = GetModuleFileName(hInst, szFilename, COUNTOF(szFilename)) ? S_OK : GetLastErrorAsHResult();
  3230. }
  3231. if (SUCCEEDED(hRetval))
  3232. {
  3233. hLocalSpl = LoadLibrary(szFilename);
  3234. hRetval = hLocalSpl ? S_OK : GetLastErrorAsHResult();
  3235. }
  3236. if (SUCCEEDED(hRetval))
  3237. {
  3238. hRetval = InitializePrintProcessor(hLocalSpl, pIniEnvironment, L"WinPrint", L"localspl.dll") ? S_OK : GetLastErrorAsHResult();
  3239. if (SUCCEEDED(hRetval))
  3240. {
  3241. hLocalSpl = NULL;
  3242. }
  3243. }
  3244. FreeLibrary(hLocalSpl);
  3245. return hRetval;
  3246. }
  3247. /* LoadPrintProcessor
  3248. *
  3249. * Loads the DLL for the required Print Processor and then calls
  3250. * InitializePrintProcessor for the necesary allocation and
  3251. * initialization of an INIPRINTPROC structure for the specified
  3252. * print processor and environment.
  3253. *
  3254. * Arguments:
  3255. *
  3256. * pIniEnvironment - Data structure for the requested environment
  3257. * The pIniPrintProc field is initialised with the chain of print
  3258. * processor structures
  3259. *
  3260. * pPrintProcessorName - The Print Processor name e.g. WinPrint
  3261. *
  3262. * pDLLName - The DLL name, e.g. WINPRINT
  3263. *
  3264. * pInitSpooler
  3265. *
  3266. * Returns:
  3267. *
  3268. * PINIPRINTPROC if no error was detected, otherwise NULL.
  3269. *
  3270. *
  3271. */
  3272. PINIPRINTPROC
  3273. LoadPrintProcessor(
  3274. PINIENVIRONMENT pIniEnvironment,
  3275. LPWSTR pPrintProcessorName,
  3276. LPWSTR pDLLName,
  3277. PINISPOOLER pIniSpooler
  3278. )
  3279. {
  3280. WCHAR string[MAX_PATH];
  3281. DWORD dwOldErrMode = 0;
  3282. HINSTANCE hLibrary;
  3283. DWORD MinorVersion = 0;
  3284. DWORD MajorVersion = 0;
  3285. PINIPRINTPROC pIniProc;
  3286. DBGMSG(DBG_TRACE, ("LoadPrintProcessor( %08x, %ws, %ws )\n", pIniEnvironment, pPrintProcessorName, pDLLName));
  3287. /* Originally:
  3288. * Typical strings used to build the full path of the DLL:
  3289. *
  3290. * pPathName = C:\NT\SYSTEM32\SPOOL\PRTPROCS
  3291. * pEnvironment = W32X86
  3292. * pDLLName = WINPRINT.DLL
  3293. * But after merging winprint and localspl , e.g. of setting
  3294. * pPathName = C:\NT\SYSTEM32
  3295. * pDllName = LOCALSPL.DLL
  3296. */
  3297. if( StrNCatBuff ( string,
  3298. COUNTOF(string),
  3299. pIniSpooler->pDir,
  3300. L"\\PRTPROCS\\",
  3301. pIniEnvironment->pDirectory,
  3302. L"\\",
  3303. pDLLName,
  3304. NULL) != ERROR_SUCCESS) {
  3305. SetLastError(ERROR_BAD_PATHNAME);
  3306. return NULL;
  3307. }
  3308. dwOldErrMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  3309. hLibrary = LoadLibrary(string);
  3310. //
  3311. // We are a cluster spooler and we cannot find the library for a print
  3312. // processor. We will try to copy the print processor from the cluster.
  3313. // disk.
  3314. //
  3315. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  3316. !hLibrary &&
  3317. GetLastError() == ERROR_MOD_NOT_FOUND)
  3318. {
  3319. WCHAR szSourceFile[MAX_PATH];
  3320. WCHAR szDestDir[MAX_PATH];
  3321. DWORD dwError;
  3322. DBGMSG(DBG_CLUSTER, ("LoadPrintProcessor File not found "TSTR"\n", string));
  3323. if ((dwError = StrNCatBuff(szDestDir,
  3324. COUNTOF(szDestDir),
  3325. pIniSpooler->pDir,
  3326. L"\\PRTPROCS\\",
  3327. pIniEnvironment->pDirectory,
  3328. NULL)) == ERROR_SUCCESS &&
  3329. (dwError = StrNCatBuff(szSourceFile,
  3330. COUNTOF(szSourceFile),
  3331. pIniSpooler->pszClusResDriveLetter,
  3332. L"\\",
  3333. szClusterDriverRoot,
  3334. L"\\",
  3335. pIniEnvironment->pDirectory,
  3336. L"\\",
  3337. pDLLName,
  3338. NULL)) == ERROR_SUCCESS)
  3339. {
  3340. //
  3341. // Make sure the destination directory exists
  3342. //
  3343. CreateCompleteDirectory(szDestDir);
  3344. //
  3345. // Try to copy the print proc file from the cluster disk
  3346. //
  3347. if (CopyFile(szSourceFile, string, FALSE) &&
  3348. (hLibrary = LoadLibrary(string)))
  3349. {
  3350. DBGMSG(DBG_CLUSTER, ("LoadPrintProc copied "TSTR" to "TSTR"\n", szSourceFile, string));
  3351. }
  3352. else
  3353. {
  3354. dwError = GetLastError();
  3355. }
  3356. }
  3357. }
  3358. if (hLibrary)
  3359. {
  3360. if (!GetBinaryVersion(string, &MajorVersion, &MinorVersion))
  3361. {
  3362. DBGMSG(DBG_ERROR, ("GetBinaryVersion failed. Error %u\n", GetLastError()));
  3363. }
  3364. }
  3365. SetErrorMode( dwOldErrMode ); /* Restore error mode */
  3366. pIniProc = InitializePrintProcessor(hLibrary,
  3367. pIniEnvironment,
  3368. pPrintProcessorName,
  3369. pDLLName);
  3370. if (pIniProc)
  3371. {
  3372. pIniProc->FileMajorVersion = MajorVersion;
  3373. pIniProc->FileMinorVersion = MinorVersion;
  3374. }
  3375. return pIniProc;
  3376. }
  3377. /*
  3378. Current Directory == c:\winspool\drivers
  3379. pFindFileData->cFileName == win32.x86
  3380. */
  3381. /* BuildEnvironmentInfo
  3382. *
  3383. *
  3384. * The registry tree for Environments is as follows:
  3385. *
  3386. * Print
  3387. *
  3388. * Environments
  3389. *
  3390. * Windows NT x86
  3391. *
  3392. * Drivers
  3393. *
  3394. * Agfa Compugraphic Genics (e.g.)
  3395. *
  3396. * :
  3397. * :
  3398. *
  3399. * Print Processors
  3400. *
  3401. * WINPRINT : WINPRINT.DLL (e.g.)
  3402. *
  3403. * :
  3404. * :
  3405. *
  3406. * Windows NT R4000
  3407. *
  3408. * Printers
  3409. *
  3410. *
  3411. *
  3412. */
  3413. BOOL
  3414. BuildEnvironmentInfo(
  3415. PINISPOOLER pIniSpooler
  3416. )
  3417. {
  3418. WCHAR Environment[MAX_PATH];
  3419. WCHAR szData[MAX_PATH];
  3420. DWORD cbData, cb;
  3421. DWORD cchBuffer = COUNTOF(Environment);
  3422. DWORD cEnvironments=0, Type;
  3423. HKEY hEnvironmentsKey, hEnvironmentKey;
  3424. LPWSTR pDirectory;
  3425. PINIENVIRONMENT pIniEnvironment;
  3426. LONG Status;
  3427. //
  3428. // The local spooler and cluster spooler have each different places
  3429. // where they store information about environments
  3430. //
  3431. if (pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG)
  3432. {
  3433. Status = SplRegOpenKey(pIniSpooler->hckRoot,
  3434. pIniSpooler->pszRegistryEnvironments,
  3435. KEY_READ,
  3436. &hEnvironmentsKey,
  3437. pIniSpooler);
  3438. }
  3439. else
  3440. {
  3441. Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryEnvironments, 0, KEY_READ, &hEnvironmentsKey);
  3442. }
  3443. if (Status != ERROR_SUCCESS)
  3444. {
  3445. DBGMSG(DBG_CLUSTER, ("RegOpenKey of %ws Failed: Error = %d\n", szEnvironmentsKey, Status));
  3446. return FALSE;
  3447. }
  3448. //
  3449. // Enumerate the subkeys of "Environment".
  3450. // This will give us "Windows NT x86", "Windows NT R4000", * and maybe others:
  3451. //
  3452. while (SplRegEnumKey(hEnvironmentsKey, cEnvironments, Environment, &cchBuffer, NULL, pIniSpooler) == ERROR_SUCCESS) {
  3453. DBGMSG(DBG_CLUSTER, ("Found environment "TSTR"\n", Environment));
  3454. //
  3455. // For each environment found, create or open the key:
  3456. //
  3457. if (SplRegCreateKey(hEnvironmentsKey, Environment, 0, KEY_READ, NULL, &hEnvironmentKey, NULL, pIniSpooler) == ERROR_SUCCESS) {
  3458. cbData = sizeof(szData);
  3459. pDirectory = NULL;
  3460. //
  3461. // Find the name of the directory associated with this environment,
  3462. // e.g. "Windows NT x86" -> "W32X86"
  3463. // "Windows NT R4000" -> "W32MIPS"
  3464. //
  3465. if (RegGetString(hEnvironmentKey, szDirectory, &pDirectory, &cbData, &Status, TRUE, pIniSpooler)) {
  3466. DBGMSG(DBG_CLUSTER, ("BuildEnvInfo pDirectory "TSTR"\n", pDirectory));
  3467. }
  3468. cb = sizeof(INIENVIRONMENT) + wcslen(Environment)*sizeof(WCHAR) + sizeof(WCHAR);
  3469. if (pDirectory && (pIniEnvironment=AllocSplMem(cb))) {
  3470. StringCbCopy((LPWSTR)(pIniEnvironment+1), cb - sizeof(*pIniEnvironment), Environment);
  3471. pIniEnvironment->pName = (LPWSTR)(pIniEnvironment+1);
  3472. pIniEnvironment->signature = IE_SIGNATURE;
  3473. pIniEnvironment->pDirectory = pDirectory;
  3474. pIniEnvironment->pNext = pIniSpooler->pIniEnvironment;
  3475. pIniSpooler->pIniEnvironment = pIniEnvironment;
  3476. pIniEnvironment->pIniVersion = NULL;
  3477. pIniEnvironment->pIniPrintProc = NULL;
  3478. pIniEnvironment->pIniSpooler = pIniSpooler;
  3479. if(!_wcsicmp(Environment,LOCAL_ENVIRONMENT)) {
  3480. (VOID)InitializeLocalPrintProcessor(pIniEnvironment);
  3481. }
  3482. BuildDriverInfo(hEnvironmentKey, pIniEnvironment, pIniSpooler);
  3483. BuildPrintProcInfo (hEnvironmentKey, pIniEnvironment, pIniSpooler);
  3484. DBGMSG(DBG_TRACE, ("Data for environment %ws created:\
  3485. \n\tpDirectory: %ws\n",
  3486. Environment,
  3487. pDirectory));
  3488. }
  3489. SplRegCloseKey(hEnvironmentKey, pIniSpooler);
  3490. }
  3491. cEnvironments++;
  3492. cchBuffer = COUNTOF(Environment);
  3493. }
  3494. SplRegCloseKey(hEnvironmentsKey, pIniSpooler);
  3495. if (!(pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER))
  3496. {
  3497. pThisEnvironment = FindEnvironment(szEnvironment, pIniSpooler);
  3498. }
  3499. return FALSE;
  3500. }
  3501. BOOL
  3502. BuildDriverInfo(
  3503. HKEY hKeyEnvironment,
  3504. PINIENVIRONMENT pIniEnvironment,
  3505. PINISPOOLER pIniSpooler
  3506. )
  3507. /*++
  3508. Routine Description:
  3509. Creates driver and version ini structures based on environment.
  3510. Arguments:
  3511. hKeyEnvironment - Registry key specifying environment.
  3512. pIniEnvironment - Structure for environemnt. Will be initialized
  3513. to hold pIniVersions and pIniDrivers.
  3514. Return Value:
  3515. TRUE - Success,
  3516. False - Failure.
  3517. --*/
  3518. {
  3519. WCHAR szVersionName[MAX_PATH];
  3520. DWORD cchBuffer;
  3521. DWORD cVersion;
  3522. HKEY hDriversKey;
  3523. DWORD Status;
  3524. PINIVERSION pIniVersionList, pIniVersion;
  3525. Status = SplRegCreateKey(hKeyEnvironment,szDriversKey, 0, KEY_READ, NULL, &hDriversKey, NULL, pIniSpooler);
  3526. if (Status != ERROR_SUCCESS) {
  3527. DBGMSG(DBG_ERROR, ("RegOpenKeyEx of %ws failed: Error = %d\n", szDriversKey, Status));
  3528. return FALSE;
  3529. }
  3530. DBGMSG(DBG_TRACE,("RegCreateKeyEx succeeded in BuildDriverInfo\n"));
  3531. for( pIniVersionList = NULL, cVersion = 0;
  3532. cchBuffer = COUNTOF( szVersionName ),
  3533. SplRegEnumKey(hDriversKey, cVersion, szVersionName, &cchBuffer, NULL, pIniSpooler) == ERROR_SUCCESS;
  3534. cVersion++ ){
  3535. DBGMSG(DBG_TRACE,("Version found %ws\n", szVersionName));
  3536. //
  3537. // If it isn't a version -- remember we look for current
  3538. // drivers before we upgrade, just move on.
  3539. //
  3540. if (_wcsnicmp(szVersionName, L"Version-", 8)) {
  3541. continue;
  3542. }
  3543. pIniVersion = GetVersionDrivers( hDriversKey,
  3544. szVersionName,
  3545. pIniSpooler,
  3546. pIniEnvironment );
  3547. if( pIniVersion ){
  3548. InsertVersionList( &pIniVersionList, pIniVersion );
  3549. }
  3550. }
  3551. SplRegCloseKey(hDriversKey, pIniSpooler);
  3552. pIniEnvironment->pIniVersion = pIniVersionList;
  3553. return TRUE;
  3554. }
  3555. /* BuildPrintProcInfo
  3556. *
  3557. * Opens the printproc subkey for the specified environment and enumerates
  3558. * the print processors listed.
  3559. *
  3560. * For each print processor found, calls InitializePrintProcessor to allocate
  3561. * and inintialize a data structure.
  3562. *
  3563. * This function was adapted to use SplReg functions. Those functions are
  3564. * cluster aware.
  3565. *
  3566. * Arguments:
  3567. *
  3568. * hKeyEnvironment - The key for the specified environment,
  3569. * used for Registry API calls.
  3570. *
  3571. * pIniEnvironment - Data structure for the environment.
  3572. * The pIniPrintProc field will be initialised to contain a chain
  3573. * of one or more print processors enumerated from the registry.
  3574. *
  3575. * Return:
  3576. *
  3577. * TRUE if operation was successful, otherwise FALSE
  3578. */
  3579. BOOL
  3580. BuildPrintProcInfo(
  3581. HKEY hKeyEnvironment,
  3582. PINIENVIRONMENT pIniEnvironment,
  3583. PINISPOOLER pIniSpooler
  3584. )
  3585. {
  3586. WCHAR PrintProcName[MAX_PATH];
  3587. WCHAR DLLName[MAX_PATH];
  3588. DWORD cchBuffer, cbDLLName;
  3589. DWORD cPrintProcs = 0;
  3590. HKEY hPrintProcKey, hPrintProc;
  3591. DWORD Status;
  3592. PINIPRINTPROC pIniPrintProc;
  3593. if ((Status = SplRegOpenKey(hKeyEnvironment,
  3594. szPrintProcKey,
  3595. KEY_READ,
  3596. &hPrintProcKey,
  3597. pIniSpooler)) == ERROR_SUCCESS)
  3598. {
  3599. cchBuffer = COUNTOF(PrintProcName);
  3600. while (SplRegEnumKey(hPrintProcKey,
  3601. cPrintProcs,
  3602. (LPTSTR)PrintProcName,
  3603. &cchBuffer,
  3604. NULL,
  3605. pIniSpooler) == ERROR_SUCCESS)
  3606. {
  3607. DBGMSG(DBG_TRACE, ("BuildPrintProcInfo Print processor found: %ws\n", PrintProcName));
  3608. if (SplRegOpenKey(hPrintProcKey,
  3609. PrintProcName,
  3610. KEY_READ,
  3611. &hPrintProc,
  3612. pIniSpooler) == ERROR_SUCCESS)
  3613. {
  3614. cbDLLName = sizeof(DLLName);
  3615. if (SplRegQueryValue(hPrintProc,
  3616. szDriverFile,
  3617. NULL,
  3618. (LPBYTE)DLLName,
  3619. &cbDLLName,
  3620. pIniSpooler) == ERROR_SUCCESS)
  3621. {
  3622. pIniPrintProc = LoadPrintProcessor(pIniEnvironment,
  3623. PrintProcName,
  3624. DLLName,
  3625. pIniSpooler);
  3626. }
  3627. SplRegCloseKey(hPrintProc, pIniSpooler);
  3628. }
  3629. //
  3630. // Don't delete the key !! If winprint.dll was corrupt,
  3631. // then we nuke it and we are hosed since there is no UI
  3632. // to add print procs.
  3633. // We can afford to be a little slow on init, since we only
  3634. // do it once.
  3635. //
  3636. cchBuffer = COUNTOF(PrintProcName);
  3637. cPrintProcs++;
  3638. }
  3639. SplRegCloseKey(hPrintProcKey, pIniSpooler);
  3640. DBGMSG(DBG_TRACE, ("End of print processor initialization.\n"));
  3641. } else {
  3642. DBGMSG (DBG_WARNING, ("SplRegOpenKey failed: Error = %d\n", Status));
  3643. return FALSE;
  3644. }
  3645. return TRUE;
  3646. }
  3647. #define SetOffset(Dest, Source, End) \
  3648. if (Source) { \
  3649. Dest=End; \
  3650. End+=wcslen(Source)+1; \
  3651. }
  3652. #define SetPointer(struc, off) \
  3653. if (struc->off) { \
  3654. struc->off += (ULONG_PTR)struc/sizeof(*struc->off); \
  3655. }
  3656. #define WriteString(hFile, pStr) \
  3657. if (pStr) {\
  3658. rc = WriteFile(hFile, pStr, wcslen(pStr)*sizeof(WCHAR) + \
  3659. sizeof(WCHAR), &BytesWritten, NULL); \
  3660. if (!rc) { \
  3661. DBGMSG(DBG_WARNING, ("WriteShadowJob: WriteFile failed %d\n", \
  3662. GetLastError())); \
  3663. } \
  3664. }
  3665. #define AddSize(pStr, dwSize) \
  3666. if (pStr) { \
  3667. dwSize = dwSize + (wcslen(pStr) + 1)*sizeof(WCHAR); \
  3668. }
  3669. VOID
  3670. __inline
  3671. CopyString(
  3672. IN OUT BYTE *pBuffer,
  3673. IN OUT ULONG_PTR *pdwOffset,
  3674. IN OUT SIZE_T *pcbRemaining,
  3675. IN PCWSTR pStr)
  3676. {
  3677. if (pStr) {
  3678. PWSTR pszEnd = 0;
  3679. StrCbCopyMultipleStr((LPWSTR)(pBuffer + *pdwOffset), *pcbRemaining, pStr, &pszEnd, pcbRemaining);
  3680. *pdwOffset = (pszEnd - (LPWSTR)pBuffer) * sizeof(WCHAR);
  3681. }
  3682. }
  3683. BOOL
  3684. WriteShadowJob(
  3685. IN PINIJOB pIniJob,
  3686. IN BOOL bLeaveCS
  3687. )
  3688. {
  3689. BOOL bAllocBuffer = FALSE;
  3690. BOOL bRet = FALSE;
  3691. BOOL bFileCreated = FALSE;
  3692. HANDLE hFile = INVALID_HANDLE_VALUE;
  3693. HANDLE hImpersonationToken = INVALID_HANDLE_VALUE;
  3694. DWORD BytesWritten, cbSize, dwType, dwData, dwcbData;
  3695. SIZE_T cbRemaining = 0;
  3696. ULONG_PTR dwOffset, cb;
  3697. SHADOWFILE_3 ShadowFile = {0};
  3698. LPWSTR pEnd;
  3699. WCHAR szFileName[MAX_PATH];
  3700. BYTE ShdFileBuffer[MAX_STATIC_ALLOC];
  3701. LPBYTE pBuffer;
  3702. HKEY hPrintRegKey = NULL;
  3703. BOOL UsePools = TRUE;
  3704. SplInSem();
  3705. //
  3706. // Only update if this is not a direct job and the spooler requests it.
  3707. // Also don't update if the shadow file has been deleted at some other point.
  3708. // This check must be performed in the CS else the FilePool starts leaking
  3709. // jobs.
  3710. //
  3711. if ( (pIniJob->Status & JOB_DIRECT) ||
  3712. (pIniJob->pIniPrinter->pIniSpooler->SpoolerFlags
  3713. & SPL_NO_UPDATE_JOBSHD) ||
  3714. (pIniJob->Status & JOB_SHADOW_DELETED) ) {
  3715. bRet = TRUE;
  3716. //
  3717. // Setting this to FALSE prevents us reentering the CS accidentally.
  3718. //
  3719. bLeaveCS = FALSE;
  3720. goto CleanUp;
  3721. }
  3722. if (bLeaveCS) {
  3723. LeaveSplSem();
  3724. SplOutSem();
  3725. }
  3726. //
  3727. // FP Change
  3728. // if we don't have a handle to a filepool item, we
  3729. // revert to the old methods.
  3730. //
  3731. if (pIniJob->hFileItem == INVALID_HANDLE_VALUE)
  3732. {
  3733. UsePools = FALSE;
  3734. }
  3735. if (!UsePools)
  3736. {
  3737. GetFullNameFromId(pIniJob->pIniPrinter, pIniJob->JobId, FALSE, szFileName, COUNTOF(szFileName), FALSE);
  3738. }
  3739. hImpersonationToken = RevertToPrinterSelf();
  3740. if (UsePools)
  3741. {
  3742. HRESULT RetVal = S_OK;
  3743. //
  3744. // FP Change
  3745. // We Get a write handle from the pool for the shadow files and
  3746. // truncate it for use.
  3747. //
  3748. RetVal = GetWriterFromHandle(pIniJob->hFileItem, &hFile, FALSE);
  3749. if (SUCCEEDED(RetVal))
  3750. {
  3751. //
  3752. // Even if we can't set the file pointer, we have signalled to the
  3753. // file pool that a writer is busy with this file pool object.
  3754. //
  3755. bFileCreated = TRUE;
  3756. if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
  3757. {
  3758. DBGMSG( DBG_WARNING,
  3759. ( "WriteShadowJob Failed to set File pointer. Error %d\n", GetLastError() ));
  3760. hFile = INVALID_HANDLE_VALUE;
  3761. }
  3762. }
  3763. else
  3764. {
  3765. DBGMSG( DBG_WARNING,
  3766. ( "WriteShadowJob Failed to get File Handle from Pool Item. Error %x\n", RetVal ));
  3767. hFile = INVALID_HANDLE_VALUE;
  3768. }
  3769. }
  3770. else
  3771. {
  3772. //
  3773. // Open file in Cached IO. Big performance gain.
  3774. //
  3775. hFile = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_READ,
  3776. NULL, CREATE_ALWAYS,
  3777. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  3778. NULL);
  3779. if (hFile != INVALID_HANDLE_VALUE) {
  3780. bFileCreated = TRUE;
  3781. }
  3782. }
  3783. bRet = ImpersonatePrinterClient(hImpersonationToken);
  3784. if(!bRet)
  3785. {
  3786. DBGMSG( DBG_WARNING,
  3787. ( "Failed ot impersonate client \n" ));
  3788. goto CleanUp;
  3789. }
  3790. if ( hFile == INVALID_HANDLE_VALUE ) {
  3791. DBGMSG( DBG_WARNING,
  3792. ( "WriteShadowJob failed to open shadow file "TSTR"\n Error %d\n",
  3793. szFileName, GetLastError() ));
  3794. bRet = FALSE;
  3795. goto CleanUp;
  3796. }
  3797. //
  3798. // We need to be able to tell if a shadow file was saved in .NET or in a previous OS
  3799. // version before an upgrade.
  3800. //
  3801. ShadowFile.signature = SF_SIGNATURE_3_DOTNET;
  3802. ShadowFile.cbSize = sizeof( SHADOWFILE_3 );
  3803. ShadowFile.Version = SF_VERSION_3;
  3804. ShadowFile.Status = pIniJob->Status;
  3805. ShadowFile.JobId = pIniJob->JobId;
  3806. ShadowFile.Priority = pIniJob->Priority;
  3807. ShadowFile.Submitted = pIniJob->Submitted;
  3808. ShadowFile.StartTime = pIniJob->StartTime;
  3809. ShadowFile.UntilTime = pIniJob->UntilTime;
  3810. ShadowFile.Size = pIniJob->Size;
  3811. ShadowFile.dwValidSize = pIniJob->dwValidSize;
  3812. ShadowFile.cPages = pIniJob->cPages;
  3813. ShadowFile.dwReboots = pIniJob->dwReboots;
  3814. if(pIniJob->pSecurityDescriptor)
  3815. ShadowFile.cbSecurityDescriptor=GetSecurityDescriptorLength(
  3816. pIniJob->pSecurityDescriptor);
  3817. pEnd=(LPWSTR)sizeof(ShadowFile);
  3818. if (pIniJob->pDevMode) {
  3819. ShadowFile.pDevMode=(LPDEVMODE)pEnd;
  3820. cb = pIniJob->pDevMode->dmSize + pIniJob->pDevMode->dmDriverExtra;
  3821. cb = ALIGN_UP(cb,ULONG_PTR);
  3822. cb /= sizeof(WCHAR);
  3823. pEnd += cb;
  3824. }
  3825. if (pIniJob->pSecurityDescriptor) {
  3826. ShadowFile.pSecurityDescriptor=(PSECURITY_DESCRIPTOR)pEnd;
  3827. cb = ShadowFile.cbSecurityDescriptor;
  3828. cb = ALIGN_UP(cb,ULONG_PTR);
  3829. cb /= sizeof(WCHAR);
  3830. pEnd += cb;
  3831. }
  3832. ShadowFile.NextJobId = pIniJob->NextJobId;
  3833. SetOffset( ShadowFile.pNotify, pIniJob->pNotify, pEnd );
  3834. SetOffset( ShadowFile.pUser, pIniJob->pUser, pEnd );
  3835. SetOffset( ShadowFile.pDocument, pIniJob->pDocument, pEnd );
  3836. SetOffset( ShadowFile.pOutputFile, pIniJob->pOutputFile, pEnd );
  3837. SetOffset( ShadowFile.pPrinterName, pIniJob->pIniPrinter->pName, pEnd );
  3838. SetOffset( ShadowFile.pDriverName, pIniJob->pIniDriver->pName, pEnd );
  3839. SetOffset( ShadowFile.pPrintProcName, pIniJob->pIniPrintProc->pName, pEnd );
  3840. SetOffset( ShadowFile.pDatatype, pIniJob->pDatatype, pEnd );
  3841. SetOffset( ShadowFile.pParameters, pIniJob->pParameters, pEnd );
  3842. SetOffset( ShadowFile.pMachineName, pIniJob->pMachineName, pEnd );
  3843. cbSize = (DWORD)ALIGN_UP(pEnd, ULONG_PTR);
  3844. if (cbSize > MAX_STATIC_ALLOC) {
  3845. if (!(pBuffer = (LPBYTE) AllocSplMem(cbSize))) {
  3846. DBGMSG( DBG_WARNING, ("WriteShadowJob: Memory Allocation failed %d\n", GetLastError()));
  3847. bRet = FALSE;
  3848. goto CleanUp;
  3849. }
  3850. bAllocBuffer = TRUE;
  3851. cbRemaining = cbSize;
  3852. } else {
  3853. pBuffer = (LPBYTE) ShdFileBuffer;
  3854. cbRemaining = COUNTOF(ShdFileBuffer);
  3855. }
  3856. //
  3857. // Copy SHADOWFILE_3 and data pointed thru it, into the buffer
  3858. //
  3859. dwOffset = 0;
  3860. CopyMemory(pBuffer + dwOffset, &ShadowFile, sizeof(SHADOWFILE_3));
  3861. dwOffset += sizeof(SHADOWFILE_3);
  3862. if (pIniJob->pDevMode) {
  3863. CopyMemory(pBuffer + dwOffset, pIniJob->pDevMode, pIniJob->pDevMode->dmSize + pIniJob->pDevMode->dmDriverExtra);
  3864. dwOffset += (pIniJob->pDevMode->dmSize + pIniJob->pDevMode->dmDriverExtra);
  3865. dwOffset = ALIGN_UP(dwOffset,ULONG_PTR);
  3866. }
  3867. if (pIniJob->pSecurityDescriptor) {
  3868. CopyMemory(pBuffer + dwOffset, pIniJob->pSecurityDescriptor, ShadowFile.cbSecurityDescriptor);
  3869. dwOffset += ShadowFile.cbSecurityDescriptor;
  3870. dwOffset = ALIGN_UP(dwOffset,ULONG_PTR);
  3871. }
  3872. //
  3873. // CopyString is defined at the start of the function
  3874. //
  3875. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pNotify);
  3876. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pUser);
  3877. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pDocument);
  3878. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pOutputFile);
  3879. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pIniPrinter->pName);
  3880. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pIniDriver->pName);
  3881. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pIniPrintProc->pName);
  3882. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pDatatype);
  3883. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pParameters);
  3884. CopyString(pBuffer, &dwOffset, &cbRemaining, pIniJob->pMachineName);
  3885. //
  3886. // Copy the structure into the Shadow file. Buffers need not be buffered since the
  3887. // file is opened in WRITE_THROUGH mode.
  3888. //
  3889. bRet = WriteFile( hFile, pBuffer, cbSize, &BytesWritten, NULL);
  3890. //
  3891. // Flush the file buffers if the corresponding flag is set in the registry
  3892. //
  3893. if (dwFlushShadowFileBuffers == 0) {
  3894. // Avoid repeated initializations
  3895. dwFlushShadowFileBuffers = 2;
  3896. // flag has to be initialized from the registry
  3897. dwcbData = sizeof(DWORD);
  3898. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3899. szRegistryRoot,
  3900. 0,
  3901. KEY_READ,
  3902. &hPrintRegKey) == ERROR_SUCCESS) {
  3903. if (RegQueryValueEx(hPrintRegKey,
  3904. szFlushShadowFileBuffers,
  3905. NULL,
  3906. &dwType,
  3907. (LPBYTE) &dwData,
  3908. &dwcbData) == ERROR_SUCCESS) {
  3909. if (dwData == 1) {
  3910. // Flush the shadow file buffers
  3911. dwFlushShadowFileBuffers = 1;
  3912. }
  3913. }
  3914. RegCloseKey(hPrintRegKey);
  3915. }
  3916. }
  3917. if (dwFlushShadowFileBuffers == 1) {
  3918. bRet = FlushFileBuffers(hFile);
  3919. }
  3920. if (!bRet) {
  3921. DBGMSG( DBG_WARNING, ("WriteShadowJob: WriteFile failed %d\n", GetLastError()));
  3922. }
  3923. CleanUp:
  3924. if (bAllocBuffer) {
  3925. FreeSplMem(pBuffer);
  3926. }
  3927. if (!UsePools && hFile != INVALID_HANDLE_VALUE)
  3928. {
  3929. //
  3930. // FP Change
  3931. // Only close the file if it's a non-pooled file.
  3932. //
  3933. if (!CloseHandle(hFile)) {
  3934. DBGMSG(DBG_WARNING, ("WriteShadowJob CloseHandle failed %d %d\n",
  3935. hFile, GetLastError()));
  3936. }
  3937. }
  3938. //
  3939. // Reenter the CS if we were asked to leave it.
  3940. //
  3941. if (bLeaveCS) {
  3942. EnterSplSem();
  3943. }
  3944. //
  3945. // We can be called just before the shadow file was deleted (or sent back to
  3946. // the file pool) and then either recreate the shadow file on the disk or
  3947. // potentially leak a file pool handle. The final DeleteJob when the reference
  3948. // count is zero will see that the shadow file has already been deleted and will
  3949. // not attempt to clean it up. So, we remove the JOB_SHADOW_DELETED bit here to
  3950. // ensure that this will not happen.
  3951. //
  3952. if (bFileCreated) {
  3953. InterlockedAnd((LONG*)&(pIniJob->Status), ~JOB_SHADOW_DELETED);
  3954. }
  3955. return bRet;
  3956. }
  3957. #undef CopyString
  3958. #undef AddSize
  3959. VOID
  3960. ProcessShadowJobs(
  3961. PINIPRINTER pIniPrinter,
  3962. PINISPOOLER pIniSpooler
  3963. )
  3964. {
  3965. WCHAR wczPrintDirAllSpools[MAX_PATH];
  3966. WCHAR wczPrinterDirectory[MAX_PATH];
  3967. HANDLE fFile;
  3968. BOOL b;
  3969. PWIN32_FIND_DATA pFindFileData;
  3970. PINIJOB pIniJob;
  3971. UINT ErrorMode;
  3972. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  3973. //
  3974. // Don't Process Shadow Jobs during Upgrade
  3975. //
  3976. if ( dwUpgradeFlag != 0 || !( pIniSpooler->SpoolerFlags & SPL_PRINT )) {
  3977. return;
  3978. }
  3979. ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  3980. if( GetPrinterDirectory(pIniPrinter,
  3981. FALSE,
  3982. wczPrintDirAllSpools,
  3983. (COUNTOF(wczPrintDirAllSpools) - COUNTOF(szAllSpools)),
  3984. pIniSpooler) &&
  3985. GetPrinterDirectory(pIniPrinter,
  3986. FALSE,
  3987. wczPrinterDirectory,
  3988. COUNTOF(wczPrinterDirectory),
  3989. pIniSpooler) ) {
  3990. StringCchCat(wczPrintDirAllSpools, COUNTOF(wczPrintDirAllSpools), szAllSpools);
  3991. if ( pFindFileData = AllocSplMem(sizeof(WIN32_FIND_DATA) )) {
  3992. fFile = FindFirstFile( wczPrintDirAllSpools, pFindFileData );
  3993. if ( fFile != (HANDLE)-1 ) {
  3994. b=TRUE;
  3995. while( b ) {
  3996. if ( !(pFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  3997. ReadShadowJob(wczPrinterDirectory, pFindFileData, pIniSpooler);
  3998. }
  3999. b = FindNextFile(fFile, pFindFileData);
  4000. }
  4001. FindClose( fFile );
  4002. }
  4003. FreeSplMem( pFindFileData );
  4004. }
  4005. }
  4006. SetErrorMode(ErrorMode);
  4007. }
  4008. #define CheckPointer( strptr ) \
  4009. if( strptr ) { \
  4010. if( (ULONG_PTR)(strptr + wcslen(strptr) + 1) > (ULONG_PTR)pEnd ) { \
  4011. bRet = FALSE; \
  4012. goto BailOut; \
  4013. } \
  4014. }
  4015. //
  4016. // make sure all pointers contain embedded data bounded within the pShadowFile (not passed the end).
  4017. //
  4018. BOOL
  4019. CheckAllPointers(
  4020. PSHADOWFILE_3 pShadowFile,
  4021. DWORD dwSize
  4022. )
  4023. {
  4024. LPBYTE pEnd = (LPBYTE)pShadowFile + dwSize;
  4025. BOOL bRet = TRUE;
  4026. try {
  4027. CheckPointer(pShadowFile->pDatatype);
  4028. CheckPointer(pShadowFile->pNotify);
  4029. CheckPointer(pShadowFile->pUser);
  4030. CheckPointer(pShadowFile->pDocument);
  4031. CheckPointer(pShadowFile->pOutputFile);
  4032. CheckPointer(pShadowFile->pPrinterName);
  4033. CheckPointer(pShadowFile->pDriverName);
  4034. CheckPointer(pShadowFile->pPrintProcName);
  4035. CheckPointer(pShadowFile->pParameters);
  4036. CheckPointer(pShadowFile->pMachineName);
  4037. // Now check the rest of the two data structures
  4038. if( (ULONG_PTR)pShadowFile->pSecurityDescriptor + pShadowFile->cbSecurityDescriptor > (ULONG_PTR)pEnd ) {
  4039. bRet = FALSE;
  4040. goto BailOut;
  4041. }
  4042. if( pShadowFile->pDevMode ) {
  4043. bRet = ((ULONG_PTR)pShadowFile->pDevMode < (ULONG_PTR)pEnd) ?
  4044. BoolFromHResult(SplIsValidDevmodeW((PDEVMODE)pShadowFile->pDevMode,
  4045. (ULONG_PTR)pEnd - (ULONG_PTR)pShadowFile->pDevMode)) :
  4046. FALSE;
  4047. }
  4048. } except (EXCEPTION_EXECUTE_HANDLER) {
  4049. bRet = FALSE;
  4050. }
  4051. BailOut:
  4052. return bRet;
  4053. }
  4054. #undef CheckPointer
  4055. PINIJOB
  4056. ReadShadowJob(
  4057. LPWSTR szDir,
  4058. PWIN32_FIND_DATA pFindFileData,
  4059. PINISPOOLER pIniSpooler
  4060. )
  4061. /*++
  4062. Routine Description:
  4063. Reads a *.spl/*.shd file and partially validates the file.
  4064. Arguments:
  4065. szDir -- pointer to spool directory string
  4066. pFindFileData -- found file data (spl file)
  4067. pIniSpooler -- spooler the *.spl belongs to
  4068. Return Value:
  4069. Allocated pIniJob.
  4070. Notes:
  4071. Warning: Changing the format of SHADOWFILE requires modifying the
  4072. data integrity checks performed here!
  4073. If the shadow file structure size is grown, then when reading,
  4074. you must check the old sizes before touching memory. Current layout is:
  4075. | DWORD | ... | String | DWORD | DWORD | StringData | StringData |
  4076. *--------------------------------------*
  4077. ^ This is the SHADOWFILE_3 structure.
  4078. If you grow it, then the next field will point to StringData, and
  4079. won't be valid--you can't touch it since you'll corrupt the string.
  4080. --*/
  4081. {
  4082. HANDLE hFile = INVALID_HANDLE_VALUE;
  4083. HANDLE hFileSpl = INVALID_HANDLE_VALUE;
  4084. DWORD BytesRead;
  4085. PSHADOWFILE_3 pShadowFile3 = NULL;
  4086. PSHADOWFILE_3 pShadowFile = NULL;
  4087. PINIJOB pIniJob;
  4088. DWORD cb,i;
  4089. WCHAR szFileName[MAX_PATH];
  4090. LPWSTR pExt;
  4091. BOOL rc;
  4092. LPWSTR pFileSpec;
  4093. DWORD nFileSizeLow;
  4094. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  4095. if (!BoolFromStatus(StrNCatBuff(szFileName, COUNTOF(szFileName), szDir, L"\\", pFindFileData->cFileName, NULL))) {
  4096. goto Fail;
  4097. }
  4098. hFileSpl = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  4099. if (hFileSpl == INVALID_HANDLE_VALUE) {
  4100. DBGMSG(DBG_WARNING, ("ReadShadowJob CreateFile( %ws ) failed: LastError = %d\n",
  4101. szFileName, GetLastError()));
  4102. goto Fail;
  4103. }
  4104. CharUpper(szFileName);
  4105. pExt = wcsstr(szFileName, L".SPL");
  4106. if (!pExt)
  4107. goto Fail;
  4108. pExt[2] = L'H';
  4109. pExt[3] = L'D';
  4110. hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  4111. if (hFile == INVALID_HANDLE_VALUE) {
  4112. DBGMSG(DBG_WARNING, ("ReadShadowJob CreateFile( %ws ) failed: LastError = %d\n",
  4113. szFileName, GetLastError()));
  4114. goto Fail;
  4115. }
  4116. nFileSizeLow = GetFileSize(hFile, NULL);
  4117. if (nFileSizeLow == 0xffffffff)
  4118. {
  4119. DBGMSG(DBG_WARNING, ("ReadShadowJob GetFileSize( %ws ) failed: LastError = %d\n",
  4120. szFileName, GetLastError()));
  4121. goto Fail;
  4122. }
  4123. if ( nFileSizeLow < sizeof( SHADOWFILE ) ||
  4124. !(pShadowFile=AllocSplMem(nFileSizeLow))) {
  4125. goto Fail;
  4126. }
  4127. rc = ReadFile(hFile, pShadowFile, nFileSizeLow, &BytesRead, NULL);
  4128. // If Shadow file is old style, then convert it to new
  4129. if (rc && (BytesRead == nFileSizeLow) &&
  4130. ( pShadowFile->signature == SF_SIGNATURE ||
  4131. pShadowFile->signature == SF_SIGNATURE_2 )) {
  4132. BOOL bStatus;
  4133. if (!(pShadowFile3 = AllocSplMem(nFileSizeLow +
  4134. sizeof(SHADOWFILE_3) - sizeof(SHADOWFILE))) ) {
  4135. goto Fail;
  4136. }
  4137. bStatus = Old2NewShadow((PSHADOWFILE)pShadowFile, pShadowFile3, &BytesRead);
  4138. nFileSizeLow = BytesRead; // This is used in CheckAllPointers, below
  4139. FreeSplMem(pShadowFile);
  4140. pShadowFile = pShadowFile3;
  4141. if( !bStatus ){
  4142. goto Fail;
  4143. }
  4144. }
  4145. //
  4146. // Initial size of SF_3/SF_3_DOTNET must include pMachineName.
  4147. //
  4148. if (!rc ||
  4149. (pShadowFile->signature != SF_SIGNATURE_3 && pShadowFile->signature != SF_SIGNATURE_3_DOTNET) ||
  4150. (BytesRead != nFileSizeLow) ||
  4151. (BytesRead < pShadowFile->cbSize ) ||
  4152. (BytesRead < sizeof( SHADOWFILE_3 )) ||
  4153. (pShadowFile->Status & (JOB_SPOOLING | JOB_PENDING_DELETION))) {
  4154. DBGMSG(DBG_WARNING, ( "Error reading shadow job:\
  4155. \n\tReadFile returned %d: Error %d\
  4156. \n\tsignature = %08x\
  4157. \n\tBytes read = %d; expected %d\
  4158. \n\tFile size = %d; expected %d\
  4159. \n\tStatus = %08x %s\n",
  4160. rc, ( rc ? 0 : GetLastError() ),
  4161. pShadowFile->signature,
  4162. BytesRead, nFileSizeLow,
  4163. sizeof(*pShadowFile), pShadowFile->Size,
  4164. pShadowFile->Status,
  4165. ( (pShadowFile->Status & JOB_SPOOLING) ?
  4166. "Job is spooling!" : "" ) ) );
  4167. goto Fail;
  4168. }
  4169. if (!CloseHandle(hFile)) {
  4170. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFileSpl, GetLastError()));
  4171. }
  4172. hFile = INVALID_HANDLE_VALUE;
  4173. if (!CloseHandle(hFileSpl)) {
  4174. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFileSpl, GetLastError()));
  4175. }
  4176. hFileSpl = INVALID_HANDLE_VALUE;
  4177. // Check number of reboots on this file & delete if too many
  4178. if (pShadowFile->dwReboots > 1) {
  4179. DBGMSG(DBG_WARNING, ("Corrupt shadow file %ws\n", szFileName));
  4180. if ( pShadowFile->pDocument && pShadowFile->pDriverName ) {
  4181. SplLogEvent(pIniSpooler,
  4182. LOG_ERROR,
  4183. MSG_BAD_JOB,
  4184. FALSE,
  4185. pShadowFile->pDocument + (ULONG_PTR)pShadowFile/sizeof(*pShadowFile->pDocument),
  4186. pShadowFile->pDriverName + (ULONG_PTR)pShadowFile/sizeof(*pShadowFile->pDriverName),
  4187. NULL);
  4188. }
  4189. goto Fail;
  4190. }
  4191. //
  4192. // If the job is a TS Job, and the registry printer policies DiscardTSJobs
  4193. // key is set, we just discard it.
  4194. //
  4195. if ((pShadowFile->Status & JOB_TS) && (pIniSpooler->dwSpoolerSettings & SPOOLER_DISCARDTSJOBS)) {
  4196. goto Fail;
  4197. }
  4198. if (pIniJob = AllocSplMem(sizeof(INIJOB))) {
  4199. pIniJob->signature = IJ_SIGNATURE;
  4200. pIniJob->Status = pShadowFile->Status & (JOB_PAUSED | JOB_REMOTE | JOB_PRINTED | JOB_COMPLETE );
  4201. pIniJob->JobId = pShadowFile->JobId;
  4202. pIniJob->Priority = pShadowFile->Priority;
  4203. pIniJob->Submitted = pShadowFile->Submitted;
  4204. pIniJob->StartTime = pShadowFile->StartTime;
  4205. pIniJob->UntilTime = pShadowFile->UntilTime;
  4206. pIniJob->Size = pShadowFile->Size;
  4207. pIniJob->dwValidSize = pShadowFile->dwValidSize;
  4208. pIniJob->cPages = pShadowFile->cPages;
  4209. pIniJob->cbPrinted = 0;
  4210. pIniJob->NextJobId = pShadowFile->NextJobId;
  4211. pIniJob->dwReboots = pShadowFile->dwReboots;
  4212. pIniJob->dwJobNumberOfPagesPerSide = 0;
  4213. pIniJob->dwDrvNumberOfPagesPerSide = 0;
  4214. pIniJob->cLogicalPages = 0;
  4215. pIniJob->cLogicalPagesPrinted = 0;
  4216. pIniJob->WaitForWrite = NULL;
  4217. pIniJob->WaitForRead = NULL;
  4218. pIniJob->hWriteFile = INVALID_HANDLE_VALUE;
  4219. // Additional fields for SeekPrinter.
  4220. pIniJob->WaitForSeek = NULL;
  4221. pIniJob->bWaitForEnd = FALSE;
  4222. pIniJob->bWaitForSeek = FALSE;
  4223. pIniJob->liFileSeekPosn.u.HighPart = 0;
  4224. pIniJob->liFileSeekPosn.u.LowPart = 0;
  4225. SetPointer(pShadowFile, pDatatype);
  4226. SetPointer(pShadowFile, pNotify);
  4227. SetPointer(pShadowFile, pUser);
  4228. SetPointer(pShadowFile, pDocument);
  4229. SetPointer(pShadowFile, pOutputFile);
  4230. SetPointer(pShadowFile, pPrinterName);
  4231. SetPointer(pShadowFile, pDriverName);
  4232. SetPointer(pShadowFile, pPrintProcName);
  4233. SetPointer(pShadowFile, pParameters);
  4234. SetPointer(pShadowFile, pMachineName);
  4235. if( (pShadowFile->cbSecurityDescriptor > 0) && pShadowFile->pSecurityDescriptor )
  4236. pShadowFile->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)((LPBYTE)pShadowFile +
  4237. (ULONG_PTR)pShadowFile->pSecurityDescriptor);
  4238. if (pShadowFile->pDevMode)
  4239. pShadowFile->pDevMode = (LPDEVMODEW)((LPBYTE)pShadowFile +
  4240. (ULONG_PTR)pShadowFile->pDevMode);
  4241. // check the length of the embedded strings as well as DevMode and Security structs.
  4242. if( !CheckAllPointers( pShadowFile, nFileSizeLow )) {
  4243. DBGMSG( DBG_WARNING, ("CheckAllPointers() failed; bad shadow file %ws\n", pFindFileData->cFileName ));
  4244. FreeSplMem(pIniJob);
  4245. goto Fail;
  4246. }
  4247. //
  4248. // Discard any jobs which were NT JNL 1.000 since the fonts might not
  4249. // be correct
  4250. if ( pShadowFile->pDatatype != NULL ) {
  4251. if (!lstrcmpi( pShadowFile->pDatatype, L"NT JNL 1.000" )) {
  4252. DBGMSG(DBG_WARNING, ("Deleteing job Datatype %ws %ws %ws\n",
  4253. pShadowFile->pDatatype,
  4254. pFindFileData->cFileName, szFileName));
  4255. FreeSplMem(pIniJob);
  4256. goto Fail;
  4257. }
  4258. }
  4259. pIniJob->pIniDriver = (PINIDRIVER)FindLocalDriver(pIniSpooler, pShadowFile->pDriverName);
  4260. if ((pIniJob->pIniPrinter = FindPrinter(pShadowFile->pPrinterName,pIniSpooler)) &&
  4261. pIniJob->pIniDriver &&
  4262. (pIniJob->pIniPrintProc = FindPrintProc(pShadowFile->pPrintProcName, FindEnvironment(szEnvironment, pIniSpooler)))) {
  4263. // Notice that MaxJobId is really the number of job slots in the pJobIdMap, so
  4264. // the maximum job id we can allow is (MaxJobId - 1).
  4265. if (pIniJob->JobId >= MaxJobId( pIniSpooler->hJobIdMap )) {
  4266. // If the job id is too huge (i.e. from a corrupt file) then we might allocate
  4267. // too much unnecessary memory for the JobIdMap!
  4268. // Notice we need to ask for (JobId+1) number of slots in the map!.
  4269. if( !ReallocJobIdMap( pIniSpooler->hJobIdMap,
  4270. pIniJob->JobId + 1 )) {
  4271. // probably a bad job id, dump the job!
  4272. DBGMSG( DBG_WARNING, ("Failed to alloc JobIdMap in ShadowFile %ws for JobId %d\n", pFindFileData->cFileName, pIniJob->JobId ));
  4273. FreeSplMem(pIniJob);
  4274. goto Fail;
  4275. }
  4276. }
  4277. else {
  4278. if( bBitOn( pIniSpooler->hJobIdMap, pIniJob->JobId )) {
  4279. // A bad job id from a corrupt shadowfile; dump the job!
  4280. DBGMSG( DBG_WARNING, ("Duplicate Job Id in ShadowFile %ws for JobId %d\n", pFindFileData->cFileName, pIniJob->JobId ));
  4281. FreeSplMem(pIniJob);
  4282. goto Fail;
  4283. }
  4284. }
  4285. SPLASSERT( pIniSpooler->hJobIdMap != NULL );
  4286. vMarkOn( pIniSpooler->hJobIdMap, pIniJob->JobId);
  4287. pIniJob->pIniPrinter->cJobs++;
  4288. pIniJob->pIniPrinter->cTotalJobs++;
  4289. INCDRIVERREF( pIniJob->pIniDriver );
  4290. pIniJob->pIniPrintProc->cRef++;
  4291. pIniJob->pIniPort = NULL;
  4292. if (pShadowFile->pSecurityDescriptor)
  4293. {
  4294. if (pIniJob->pSecurityDescriptor = LocalAlloc(LPTR, pShadowFile->cbSecurityDescriptor))
  4295. {
  4296. memcpy(pIniJob->pSecurityDescriptor, pShadowFile->pSecurityDescriptor, pShadowFile->cbSecurityDescriptor);
  4297. if (pShadowFile->signature != SF_SIGNATURE_3_DOTNET && !GrantJobReadPermissionToLocalSystem(&pIniJob->pSecurityDescriptor))
  4298. {
  4299. LocalFree(pIniJob->pSecurityDescriptor);
  4300. pIniJob->pSecurityDescriptor = NULL;
  4301. goto Fail;
  4302. }
  4303. }
  4304. else
  4305. {
  4306. DBGMSG(DBG_WARNING, ("Failed to alloc ini job security descriptor.\n"));
  4307. }
  4308. }
  4309. if (pShadowFile->pDevMode) {
  4310. cb=pShadowFile->pDevMode->dmSize +
  4311. pShadowFile->pDevMode->dmDriverExtra;
  4312. if (pIniJob->pDevMode=AllocSplMem(cb))
  4313. memcpy(pIniJob->pDevMode, pShadowFile->pDevMode, cb);
  4314. else
  4315. DBGMSG(DBG_WARNING, ("Failed to alloc ini job devmode.\n"));
  4316. }
  4317. pIniJob->pNotify = AllocSplStr( pShadowFile->pNotify);
  4318. pIniJob->pUser = AllocSplStr( pShadowFile->pUser);
  4319. pIniJob->pDocument = AllocSplStr( pShadowFile->pDocument);
  4320. pIniJob->pOutputFile = AllocSplStr( pShadowFile->pOutputFile);
  4321. pIniJob->pDatatype = AllocSplStr( pShadowFile->pDatatype);
  4322. pIniJob->pParameters = AllocSplStr( pShadowFile->pParameters);
  4323. if( pShadowFile->pMachineName ){
  4324. pIniJob->pMachineName = AllocSplStr( pShadowFile->pMachineName );
  4325. } else {
  4326. pIniJob->pMachineName = AllocSplStr( pIniSpooler->pMachineName );
  4327. }
  4328. //
  4329. // FP Change
  4330. // Add the files to the File pool if :-
  4331. // a. We dont want to KeepPrintedJobs for the printer,
  4332. // b. the printer does not have its own spool directory; or
  4333. // c. SpoolerSettings do not have filepooling disabled.
  4334. //
  4335. if ( !(pIniJob->pIniPrinter->Attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) &&
  4336. pIniJob->pIniPrinter->pSpoolDir == NULL &&
  4337. !(pIniSpooler->dwSpoolerSettings & SPOOLER_NOFILEPOOLING))
  4338. {
  4339. pIniJob->pszSplFileName = AllocSplStr( szFileName );
  4340. if ((pIniJob->pIniPrinter->pIniSpooler->hFilePool != INVALID_HANDLE_VALUE)
  4341. && pIniJob->pszSplFileName && SUCCEEDED(ConvertFileExt(pIniJob->pszSplFileName, L".SHD", L".SPL")))
  4342. {
  4343. if (FAILED(GetFileItemHandle(
  4344. pIniJob->pIniPrinter->pIniSpooler->hFilePool,
  4345. &pIniJob->hFileItem,
  4346. pIniJob->pszSplFileName )))
  4347. {
  4348. pIniJob->hFileItem = INVALID_HANDLE_VALUE;
  4349. FreeSplStr(pIniJob->pszSplFileName);
  4350. pIniJob->pszSplFileName = NULL;
  4351. }
  4352. }
  4353. else
  4354. {
  4355. FreeSplStr(pIniJob->pszSplFileName);
  4356. pIniJob->pszSplFileName = NULL;
  4357. }
  4358. }
  4359. else
  4360. {
  4361. pIniJob->pszSplFileName = NULL;
  4362. pIniJob->hFileItem = INVALID_HANDLE_VALUE;
  4363. }
  4364. pIniJob->pIniNextJob = NULL;
  4365. pIniJob->pStatus = NULL;
  4366. if (pIniJob->pIniPrevJob = pIniJob->pIniPrinter->pIniLastJob)
  4367. pIniJob->pIniPrevJob->pIniNextJob=pIniJob;
  4368. if (!pIniJob->pIniPrinter->pIniFirstJob)
  4369. pIniJob->pIniPrinter->pIniFirstJob = pIniJob;
  4370. pIniJob->pIniPrinter->pIniLastJob=pIniJob;
  4371. } else {
  4372. DBGMSG( DBG_WARNING, ("Failed to find printer %ws\n",pShadowFile->pPrinterName));
  4373. FreeSplMem(pIniJob);
  4374. goto Fail;
  4375. }
  4376. } else {
  4377. DBGMSG(DBG_WARNING, ("Failed to allocate ini job.\n"));
  4378. }
  4379. FreeSplMem( pShadowFile );
  4380. return pIniJob;
  4381. Fail:
  4382. if (pShadowFile) {
  4383. FreeSplMem(pShadowFile);
  4384. }
  4385. if (hFile != INVALID_HANDLE_VALUE && !CloseHandle(hFile)) {
  4386. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFile, GetLastError()));
  4387. }
  4388. if (hFileSpl != INVALID_HANDLE_VALUE && !CloseHandle(hFileSpl)) {
  4389. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFileSpl, GetLastError()));
  4390. }
  4391. DeleteFile(szFileName);
  4392. pFileSpec = wcsrchr(szFileName, L'\\');
  4393. if (pFileSpec) {
  4394. pFileSpec++;
  4395. StringCchCopy(pFileSpec, COUNTOF(szFileName) - (pFileSpec - szFileName), pFindFileData->cFileName);
  4396. }
  4397. DeleteFile(szFileName);
  4398. return FALSE;
  4399. }
  4400. VOID
  4401. GetDiscardTSJobsSettings(
  4402. PINISPOOLER pIniSpooler
  4403. )
  4404. {
  4405. //
  4406. // If the Printer Policy to Discard TS Jobs is set we shall
  4407. // discard the jobs on spooler restart as a security precaution
  4408. // otherwise the normal behaviour is that we keep the jobs.
  4409. // However this by design causes a job to print on the TS port
  4410. // irrespective of the current user or printer.
  4411. //
  4412. DWORD RegValue = 0;
  4413. DWORD RegValueSize = sizeof(RegValue);
  4414. HKEY RegKey = NULL;
  4415. DWORD dwError = ERROR_SUCCESS;
  4416. DWORD RegValueType;
  4417. dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  4418. szPrintPublishPolicy,
  4419. 0,
  4420. KEY_READ,
  4421. &RegKey );
  4422. if (dwError == ERROR_SUCCESS)
  4423. {
  4424. dwError = RegQueryValueEx( RegKey,
  4425. szDiscardTSJobs,
  4426. NULL,
  4427. (LPDWORD) &RegValueType,
  4428. (LPBYTE) &RegValue,
  4429. &RegValueSize );
  4430. if ( RegValueType == REG_DWORD && dwError == ERROR_SUCCESS && RegValue > 0)
  4431. {
  4432. pIniSpooler->dwSpoolerSettings |= SPOOLER_DISCARDTSJOBS;
  4433. }
  4434. }
  4435. if (RegKey)
  4436. {
  4437. RegCloseKey( RegKey );
  4438. }
  4439. }
  4440. BOOL
  4441. Old2NewShadow(
  4442. PSHADOWFILE pShadowFile1,
  4443. PSHADOWFILE_3 pShadowFile3,
  4444. DWORD *pnBytes
  4445. )
  4446. /*++
  4447. Routine Description:
  4448. Converts an original format *.shd file to a new format (version 2).
  4449. Arguments:
  4450. pShadowFile1 -- pointer to version 1 shadow file
  4451. pShadowFile2 -- pointer to version 2 shadow file
  4452. *pnBytes -- pointer to number of bytes read from version 1 shadow file. On
  4453. return, pnBytes contains the number of bytes in the version 2 shadow file.
  4454. Return Value:
  4455. None
  4456. Author: Steve Wilson (NT)
  4457. --*/
  4458. {
  4459. DWORD cbOld;
  4460. DWORD cbDiff;
  4461. switch( pShadowFile1->signature ){
  4462. case SF_SIGNATURE:
  4463. cbOld = sizeof( SHADOWFILE );
  4464. cbDiff = sizeof( SHADOWFILE_3 ) - sizeof( SHADOWFILE );
  4465. break;
  4466. case SF_SIGNATURE_2:
  4467. cbOld = sizeof ( SHADOWFILE_2 );
  4468. cbDiff = sizeof( SHADOWFILE_3 ) - sizeof( SHADOWFILE_2 );
  4469. break;
  4470. default:
  4471. return FALSE;
  4472. }
  4473. if( *pnBytes < cbOld ){
  4474. return FALSE;
  4475. }
  4476. //
  4477. // Copy everything except signature.
  4478. //
  4479. MoveMemory((PVOID)(&pShadowFile3->Status),
  4480. (PVOID)(&pShadowFile1->Status),
  4481. cbOld - sizeof( pShadowFile1->signature ));
  4482. //
  4483. // Now update signature and size.
  4484. //
  4485. pShadowFile3->signature = SF_SIGNATURE_3_DOTNET;
  4486. pShadowFile3->cbSize = *pnBytes + cbDiff;
  4487. //
  4488. // Move strings.
  4489. //
  4490. MoveMemory((PVOID)(pShadowFile3 + 1),
  4491. ((PBYTE)pShadowFile1) + cbOld,
  4492. *pnBytes - cbOld );
  4493. pShadowFile3->pNotify += pShadowFile1->pNotify ? cbDiff/sizeof *pShadowFile1->pNotify : 0;
  4494. pShadowFile3->pUser += pShadowFile1->pUser ? cbDiff/sizeof *pShadowFile1->pUser : 0;
  4495. pShadowFile3->pDocument += pShadowFile1->pDocument ? cbDiff/sizeof *pShadowFile3->pDocument : 0;
  4496. pShadowFile3->pOutputFile += pShadowFile1->pOutputFile ? cbDiff/sizeof *pShadowFile3->pOutputFile : 0;
  4497. pShadowFile3->pPrinterName += pShadowFile1->pPrinterName ? cbDiff/sizeof *pShadowFile3->pPrinterName : 0;
  4498. pShadowFile3->pDriverName += pShadowFile1->pDriverName ? cbDiff/sizeof *pShadowFile3->pDriverName : 0;
  4499. pShadowFile3->pPrintProcName += pShadowFile1->pPrintProcName ? cbDiff/sizeof *pShadowFile3->pPrintProcName : 0;
  4500. pShadowFile3->pDatatype += pShadowFile1->pDatatype ? cbDiff/sizeof *pShadowFile3->pDatatype : 0;
  4501. pShadowFile3->pParameters += pShadowFile1->pParameters ? cbDiff/sizeof *pShadowFile3->pParameters : 0;
  4502. pShadowFile3->pDevMode = (PDEVMODE) (pShadowFile1->pDevMode ?
  4503. (ULONG_PTR) pShadowFile1->pDevMode + cbDiff : 0);
  4504. pShadowFile3->pSecurityDescriptor = (PSECURITY_DESCRIPTOR) (pShadowFile1->pSecurityDescriptor ?
  4505. (ULONG_PTR) pShadowFile1->pSecurityDescriptor + cbDiff : 0);
  4506. pShadowFile3->Version = SF_VERSION_3;
  4507. //
  4508. // The first shadow file didn't have dwReboots.
  4509. //
  4510. if( pShadowFile1->signature == SF_SIGNATURE ){
  4511. pShadowFile3->dwReboots = 0;
  4512. }
  4513. pShadowFile3->pMachineName = NULL;
  4514. *pnBytes += cbDiff;
  4515. return TRUE;
  4516. }
  4517. PINIVERSION
  4518. GetVersionDrivers(
  4519. HKEY hDriversKey,
  4520. LPWSTR szVersionName,
  4521. PINISPOOLER pIniSpooler,
  4522. PINIENVIRONMENT pIniEnvironment
  4523. )
  4524. {
  4525. HKEY hVersionKey;
  4526. WCHAR szDirectoryValue[MAX_PATH];
  4527. PINIDRIVER pIniDriver;
  4528. DWORD cMajorVersion, cMinorVersion;
  4529. DWORD cbData;
  4530. DWORD Type;
  4531. PINIVERSION pIniVersion = NULL;
  4532. if (SplRegOpenKey(hDriversKey, szVersionName, KEY_READ, &hVersionKey, pIniSpooler) != ERROR_SUCCESS)
  4533. {
  4534. DBGMSG(DBG_TRACE, ("GetVersionDrivers SplRegOpenKey on "TSTR" failed\n", szVersionName));
  4535. return NULL;
  4536. }
  4537. cbData = sizeof(szDirectoryValue);
  4538. if (SplRegQueryValue(hVersionKey, szDirectory, &Type, (LPBYTE)szDirectoryValue, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4539. {
  4540. DBGMSG(DBG_TRACE, ("Couldn't query for directory in version structure\n"));
  4541. goto Done;
  4542. }
  4543. cbData = sizeof(DWORD);
  4544. if (SplRegQueryValue(hVersionKey, szMajorVersion, &Type, (LPBYTE)&cMajorVersion, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4545. {
  4546. DBGMSG(DBG_TRACE, ("Couldn't query for major version in version structure\n"));
  4547. goto Done;
  4548. }
  4549. cbData = sizeof(DWORD);
  4550. if (SplRegQueryValue(hVersionKey, szMinorVersion, &Type, (LPBYTE)&cMinorVersion, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4551. {
  4552. DBGMSG(DBG_TRACE, ("Couldn't query for minor version in version structure\n"));
  4553. goto Done;
  4554. }
  4555. DBGMSG(DBG_TRACE, ("Got all information to build the version entry\n"));
  4556. //
  4557. // Now build the version node structure.
  4558. //
  4559. pIniVersion = AllocSplMem(sizeof(INIVERSION));
  4560. if( pIniVersion ){
  4561. pIniVersion->signature = IV_SIGNATURE;
  4562. pIniVersion->pName = AllocSplStr(szVersionName);
  4563. pIniVersion->szDirectory = AllocSplStr(szDirectoryValue);
  4564. pIniVersion->cMajorVersion = cMajorVersion;
  4565. pIniVersion->cMinorVersion = cMinorVersion;
  4566. pIniVersion->pDrvRefCnt = NULL;
  4567. if (!pIniVersion->pName || !pIniVersion->szDirectory) {
  4568. FreeIniVersion(pIniVersion);
  4569. pIniVersion = NULL;
  4570. } else {
  4571. pIniDriver = GetDriverList(hVersionKey,
  4572. pIniSpooler,
  4573. pIniEnvironment,
  4574. pIniVersion);
  4575. pIniVersion->pIniDriver = pIniDriver;
  4576. while (pIniDriver) {
  4577. if (!UpdateDriverFileRefCnt(pIniEnvironment,pIniVersion,pIniDriver,NULL,0,TRUE)) {
  4578. FreeIniVersion(pIniVersion);
  4579. pIniVersion = NULL;
  4580. break;
  4581. }
  4582. pIniDriver = pIniDriver->pNext;
  4583. }
  4584. }
  4585. }
  4586. Done:
  4587. SplRegCloseKey(hVersionKey, pIniSpooler);
  4588. return pIniVersion;
  4589. }
  4590. /*++
  4591. Routine Name:
  4592. FreeIniDriver
  4593. Routine Description:
  4594. This handles the memory in an inidriver after first decrementing the driver
  4595. ref-count correctly.
  4596. Arguments:
  4597. pIniEnvironment - The environment of the driver.
  4598. pIniVersion - The version of the driver.
  4599. pIniDriver - The driver to delete.
  4600. Return Value:
  4601. None.
  4602. --*/
  4603. VOID
  4604. FreeIniDriver(
  4605. IN PINIENVIRONMENT pIniEnvironment,
  4606. IN PINIVERSION pIniVersion,
  4607. IN PINIDRIVER pIniDriver
  4608. )
  4609. {
  4610. if (pIniEnvironment && pIniVersion && pIniDriver)
  4611. {
  4612. //
  4613. // This is to reverse the ref-count for when the spooler is first created.
  4614. //
  4615. UpdateDriverFileRefCnt(pIniEnvironment, pIniVersion, pIniDriver, NULL, 0, FALSE);
  4616. //
  4617. // The monitors will be deleted shortly. So we don't need to worry about
  4618. // the language monitors.
  4619. //
  4620. FreeStructurePointers((LPBYTE) pIniDriver, NULL, IniDriverOffsets);
  4621. FreeSplMem(pIniDriver);
  4622. }
  4623. }
  4624. /*++
  4625. Routine Name:
  4626. FreeIniVersion
  4627. Routine Description:
  4628. This frees all the memory in an ini-version without handling either the
  4629. drivers or the driver ref-counts in it.
  4630. Arguments:
  4631. pIniVersion - The version to delete.
  4632. Return Value:
  4633. None.
  4634. --*/
  4635. VOID
  4636. FreeIniVersion(
  4637. IN PINIVERSION pIniVersion
  4638. )
  4639. {
  4640. PDRVREFCNT pdrc,pdrctemp;
  4641. FreeSplStr( pIniVersion->pName );
  4642. FreeSplStr( pIniVersion->szDirectory );
  4643. pdrc = pIniVersion->pDrvRefCnt;
  4644. while (pdrc) {
  4645. FreeSplStr(pdrc->szDrvFileName);
  4646. pdrctemp = pdrc->pNext;
  4647. FreeSplMem(pdrc);
  4648. pdrc = pdrctemp;
  4649. }
  4650. FreeSplMem( pIniVersion );
  4651. }
  4652. /*++
  4653. Routine Name:
  4654. DeleteIniVersion
  4655. Routine Description:
  4656. This runs all of the drivers in an iniVersion and then calls FreeIniVersion
  4657. to free the contents of the iniversion.
  4658. Arguments:
  4659. pIniEnvironment - The environment used for handling driver ref-counts.
  4660. pIniVersion - The version to delete.
  4661. Return Value:
  4662. None.
  4663. --*/
  4664. VOID
  4665. DeleteIniVersion(
  4666. IN PINIENVIRONMENT pIniEnvironment,
  4667. IN PINIVERSION pIniVersion
  4668. )
  4669. {
  4670. if (pIniVersion && pIniEnvironment)
  4671. {
  4672. PINIDRIVER pIniDriver = NULL;
  4673. PINIDRIVER pNextIniDriver = NULL;
  4674. for(pIniDriver = pIniVersion->pIniDriver; pIniDriver; pIniDriver = pNextIniDriver)
  4675. {
  4676. pNextIniDriver = pIniDriver->pNext;
  4677. FreeIniDriver(pIniEnvironment, pIniVersion, pIniDriver);
  4678. }
  4679. FreeIniVersion(pIniVersion);
  4680. }
  4681. }
  4682. /*++
  4683. Routine Name:
  4684. FreeIniEnvironment
  4685. Routine Description:
  4686. This runs all of the ini-versions in an environvironment
  4687. and then deletes the environment.
  4688. Arguments:
  4689. pIniEnvironment - The environment to free.
  4690. Return Value:
  4691. None.
  4692. --*/
  4693. VOID
  4694. FreeIniEnvironment(
  4695. IN PINIENVIRONMENT pIniEnvironment
  4696. )
  4697. {
  4698. if (pIniEnvironment)
  4699. {
  4700. PINIVERSION pIniVersion = NULL;
  4701. PINIVERSION pNextIniVersion = NULL;
  4702. for(pIniVersion = pIniEnvironment->pIniVersion; pIniVersion; pIniVersion = pNextIniVersion)
  4703. {
  4704. pNextIniVersion = pIniVersion->pNext;
  4705. DeleteIniVersion(pIniEnvironment, pIniVersion);
  4706. }
  4707. FreeIniPrintProc(pIniEnvironment->pIniPrintProc);
  4708. FreeStructurePointers((LPBYTE)pIniEnvironment, NULL, IniEnvironmentOffsets);
  4709. FreeSplMem(pIniEnvironment);
  4710. }
  4711. }
  4712. /*++
  4713. Routine Name:
  4714. FreeIniPrintProc
  4715. Routine Description:
  4716. This deletes all of the print processor fields.
  4717. Arguments:
  4718. pIniPrintProc - The print processor to delete.
  4719. Return Value:
  4720. None.
  4721. --*/
  4722. VOID
  4723. FreeIniPrintProc(
  4724. IN PINIPRINTPROC pIniPrintProc
  4725. )
  4726. {
  4727. if (pIniPrintProc)
  4728. {
  4729. FreeLibrary(pIniPrintProc->hLibrary);
  4730. DeleteCriticalSection(&pIniPrintProc->CriticalSection);
  4731. FreeStructurePointers((LPBYTE)pIniPrintProc, NULL, IniPrintProcOffsets);
  4732. FreeSplMem(pIniPrintProc);
  4733. }
  4734. }
  4735. PINIDRIVER
  4736. GetDriverList(
  4737. HKEY hVersionKey,
  4738. PINISPOOLER pIniSpooler,
  4739. PINIENVIRONMENT pIniEnvironment,
  4740. PINIVERSION pIniVersion
  4741. )
  4742. {
  4743. PINIDRIVER pIniDriverList = NULL;
  4744. DWORD cDrivers = 0;
  4745. PINIDRIVER pIniDriver;
  4746. WCHAR DriverName[MAX_PATH];
  4747. DWORD cchBuffer =0;
  4748. pIniDriverList = NULL;
  4749. cchBuffer = COUNTOF(DriverName);
  4750. while (SplRegEnumKey(hVersionKey, cDrivers++, DriverName, &cchBuffer, NULL, pIniSpooler) == ERROR_SUCCESS)
  4751. {
  4752. cchBuffer = COUNTOF(DriverName);
  4753. DBGMSG(DBG_TRACE, ("Found a driver - "TSTR"\n", DriverName));
  4754. pIniDriver = GetDriver(hVersionKey, DriverName, pIniSpooler, pIniEnvironment, pIniVersion);
  4755. if (pIniDriver != NULL)
  4756. {
  4757. pIniDriver->pNext = pIniDriverList;
  4758. pIniDriverList = pIniDriver;
  4759. }
  4760. //
  4761. // On a cluster, a driver may have changed while the cluster spooler
  4762. // was hosted by another node. Here we check if we need to update or
  4763. // add a new driver
  4764. //
  4765. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  4766. ClusterCheckDriverChanged(hVersionKey,
  4767. DriverName,
  4768. pIniEnvironment->pName,
  4769. pIniVersion->pName,
  4770. pIniSpooler))
  4771. {
  4772. DWORD dwError;
  4773. //
  4774. // Add or update the driver.
  4775. //
  4776. LeaveSplSem();
  4777. if ((dwError = ClusterAddOrUpdateDriverFromClusterDisk(hVersionKey,
  4778. DriverName,
  4779. pIniEnvironment->pName,
  4780. pIniEnvironment->pDirectory,
  4781. pIniSpooler)) != ERROR_SUCCESS)
  4782. {
  4783. WCHAR szError[20];
  4784. DBGMSG(DBG_CLUSTER, ("GetDriverList failed to add/update driver "TSTR". Win32 error %u\n",
  4785. DriverName, dwError));
  4786. StringCchPrintf(szError, COUNTOF(szError), L"%u", dwError);
  4787. SplLogEvent(pIniSpooler,
  4788. LOG_ERROR,
  4789. MSG_CANT_ADD_UPDATE_CLUSTER_DRIVER,
  4790. FALSE,
  4791. DriverName,
  4792. pIniSpooler->pMachineName,
  4793. szError,
  4794. NULL);
  4795. }
  4796. EnterSplSem();
  4797. }
  4798. }
  4799. return pIniDriverList;
  4800. }
  4801. PINIDRIVER
  4802. GetDriver(
  4803. HKEY hVersionKey,
  4804. LPWSTR DriverName,
  4805. PINISPOOLER pIniSpooler,
  4806. PINIENVIRONMENT pIniEnvironment,
  4807. PINIVERSION pIniVersion
  4808. )
  4809. {
  4810. HKEY hDriverKey = NULL;
  4811. DWORD Type;
  4812. WCHAR szData[MAX_PATH];
  4813. WCHAR szTempDir[MAX_PATH];
  4814. DWORD cbData;
  4815. DWORD Version;
  4816. DWORD DriverAttributes;
  4817. LPWSTR pConfigFile, pDataFile, pDriver;
  4818. LPWSTR pHelpFile, pMonitorName, pDefaultDataType, pDependentFiles, pTemp;
  4819. LPWSTR pDriverName, pszzPreviousNames;
  4820. LPWSTR pszMfgName, pszOEMUrl, pszHardwareID, pszProvider;
  4821. FILETIME DriverDate;
  4822. DWORDLONG DriverVersion;
  4823. PINIDRIVER pIniDriver = NULL;
  4824. DWORD cb, cLen, cchDependentFiles = 0, cchPreviousNames = 0;
  4825. DWORD dwTempDir, dwLastError = ERROR_SUCCESS;
  4826. pDriverName = pConfigFile = pDataFile = pDriver = pHelpFile = pTemp = NULL;
  4827. pMonitorName = pDefaultDataType = pDependentFiles = pszzPreviousNames = NULL;
  4828. pszMfgName = pszOEMUrl = pszHardwareID = pszProvider = NULL;
  4829. if ((dwLastError = SplRegOpenKey(hVersionKey, DriverName, KEY_READ, &hDriverKey, pIniSpooler)) != ERROR_SUCCESS) {
  4830. goto Fail;
  4831. }
  4832. else {
  4833. if ( !(pDriverName=AllocSplStr(DriverName)) ) {
  4834. dwLastError = GetLastError();
  4835. goto Fail;
  4836. }
  4837. RegGetString( hDriverKey, szConfigurationKey, &pConfigFile, &cLen, &dwLastError, TRUE, pIniSpooler );
  4838. if (!pConfigFile) {
  4839. goto Fail;
  4840. }
  4841. RegGetString( hDriverKey, szDataFileKey, &pDataFile, &cLen, &dwLastError, TRUE, pIniSpooler );
  4842. if ( !pDataFile ) {
  4843. goto Fail;
  4844. }
  4845. RegGetString( hDriverKey, szDriverFile, &pDriver, &cLen, &dwLastError, TRUE, pIniSpooler );
  4846. if ( !pDriver ) {
  4847. goto Fail;
  4848. }
  4849. RegGetString( hDriverKey, szHelpFile, &pHelpFile, &cLen, &dwLastError, FALSE, pIniSpooler );
  4850. RegGetString( hDriverKey, szMonitor, &pMonitorName, &cLen, &dwLastError, FALSE, pIniSpooler );
  4851. RegGetString( hDriverKey, szDatatype, &pDefaultDataType, &cLen, &dwLastError, FALSE, pIniSpooler );
  4852. RegGetMultiSzString( hDriverKey, szDependentFiles, &pDependentFiles, &cchDependentFiles, &dwLastError, FALSE, pIniSpooler );
  4853. RegGetMultiSzString( hDriverKey, szPreviousNames, &pszzPreviousNames, &cchPreviousNames, &dwLastError, FALSE, pIniSpooler );
  4854. RegGetString( hDriverKey, szMfgName, &pszMfgName, &cLen, &dwLastError, FALSE, pIniSpooler );
  4855. RegGetString( hDriverKey, szOEMUrl, &pszOEMUrl, &cLen, &dwLastError, FALSE, pIniSpooler );
  4856. RegGetString( hDriverKey, szHardwareID, &pszHardwareID, &cLen, &dwLastError, TRUE, pIniSpooler );
  4857. RegGetString( hDriverKey, szProvider, &pszProvider, &cLen, &dwLastError, TRUE, pIniSpooler );
  4858. cbData = sizeof(DriverDate);
  4859. if (SplRegQueryValue(hDriverKey, szDriverDate, NULL, (LPBYTE)&DriverDate, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4860. {
  4861. //
  4862. // don't leave the data uninitialized
  4863. //
  4864. DriverDate.dwLowDateTime = DriverDate.dwHighDateTime = 0;
  4865. }
  4866. cbData = sizeof(DriverVersion);
  4867. if (SplRegQueryValue(hDriverKey, szLongVersion, NULL, (LPBYTE)&DriverVersion, &cbData, pIniSpooler)!=ERROR_SUCCESS)
  4868. {
  4869. //
  4870. // don't leave the data uninitialized
  4871. //
  4872. DriverVersion = 0;
  4873. }
  4874. // Retrieve the version number
  4875. cbData = sizeof(DWORD);
  4876. if (SplRegQueryValue(hDriverKey, szDriverAttributes, &Type, (LPBYTE)&DriverAttributes, &cbData, pIniSpooler) != ERROR_SUCCESS)
  4877. {
  4878. DriverAttributes = 0;
  4879. }
  4880. // Retrieve the version number
  4881. cbData = sizeof(DWORD);
  4882. if (SplRegQueryValue(hDriverKey, szDriverVersion, &Type, (LPBYTE)&Version, &cbData, pIniSpooler) != ERROR_SUCCESS)
  4883. {
  4884. Version = 0;
  4885. }
  4886. // Retrieve the TempDir number
  4887. cbData = sizeof(DWORD);
  4888. if (SplRegQueryValue(hDriverKey, szTempDir, &Type, (LPBYTE)&dwTempDir, &cbData, pIniSpooler) != ERROR_SUCCESS)
  4889. {
  4890. dwTempDir = 0;
  4891. }
  4892. // After REBOOT temp directories are deleted. So check for the presence of the
  4893. // directory on spooler startup.
  4894. if (dwTempDir && pIniEnvironment && pIniVersion)
  4895. {
  4896. StringCchPrintf(szTempDir, COUNTOF(szTempDir), L"%d", dwTempDir);
  4897. if(StrNCatBuff(szData,
  4898. COUNTOF(szData),
  4899. pIniSpooler->pDir,
  4900. L"\\drivers\\",
  4901. pIniEnvironment->pDirectory,
  4902. L"\\",
  4903. pIniVersion->szDirectory,
  4904. L"\\",
  4905. szTempDir,
  4906. NULL) == ERROR_SUCCESS)
  4907. {
  4908. if (!DirectoryExists(szData))
  4909. {
  4910. // Files must have been moved in Reboot, reset dwTempDir to 0
  4911. dwTempDir = 0;
  4912. }
  4913. }
  4914. }
  4915. SplRegCloseKey(hDriverKey, pIniSpooler);
  4916. hDriverKey = NULL;
  4917. }
  4918. //
  4919. // Win95 driver needs every file as a dependent file for point and print.
  4920. // For others we eliminate duplicates
  4921. //
  4922. if ( pIniEnvironment && _wcsicmp(pIniEnvironment->pName, szWin95Environment) ) {
  4923. pTemp = pDependentFiles;
  4924. pDependentFiles = NULL;
  4925. if ( !BuildTrueDependentFileField(pDriver,
  4926. pDataFile,
  4927. pConfigFile,
  4928. pHelpFile,
  4929. pTemp,
  4930. &pDependentFiles) )
  4931. goto Fail;
  4932. FreeSplMem(pTemp);
  4933. for ( pTemp = pDependentFiles ; pTemp && *pTemp ;
  4934. pTemp += wcslen(pTemp) + 1 )
  4935. ;
  4936. if ( pTemp )
  4937. cchDependentFiles = (DWORD) (pTemp - pDependentFiles + 1);
  4938. else
  4939. cchDependentFiles = 0;
  4940. pTemp = NULL;
  4941. }
  4942. cb = sizeof( INIDRIVER );
  4943. if ( pIniDriver = AllocSplMem( cb )) {
  4944. pIniDriver->signature = ID_SIGNATURE;
  4945. pIniDriver->pName = pDriverName;
  4946. pIniDriver->pDriverFile = pDriver;
  4947. pIniDriver->pDataFile = pDataFile;
  4948. pIniDriver->pConfigFile = pConfigFile;
  4949. pIniDriver->cVersion = Version;
  4950. pIniDriver->pHelpFile = pHelpFile;
  4951. pIniDriver->pMonitorName = pMonitorName;
  4952. pIniDriver->pDefaultDataType = pDefaultDataType;
  4953. pIniDriver->pDependentFiles = pDependentFiles;
  4954. pIniDriver->cchDependentFiles = cchDependentFiles;
  4955. pIniDriver->pszzPreviousNames = pszzPreviousNames;
  4956. pIniDriver->cchPreviousNames = cchPreviousNames;
  4957. pIniDriver->dwTempDir = dwTempDir;
  4958. pIniDriver->pszMfgName = pszMfgName;
  4959. pIniDriver->pszOEMUrl = pszOEMUrl;
  4960. pIniDriver->pszHardwareID = pszHardwareID;
  4961. pIniDriver->pszProvider = pszProvider;
  4962. pIniDriver->dwlDriverVersion = DriverVersion;
  4963. pIniDriver->ftDriverDate = DriverDate;
  4964. pIniDriver->dwDriverAttributes = DriverAttributes;
  4965. DBGMSG( DBG_TRACE, ("Data for driver %ws created:\
  4966. \n\tpDriverFile:\t%ws\
  4967. \n\tpDataFile:\t%ws\
  4968. \n\tpConfigFile:\t%ws\n\n",
  4969. pDriverName, pDriver, pDataFile, pConfigFile));
  4970. if ( pIniDriver->pMonitorName && *pIniDriver->pMonitorName ) {
  4971. //
  4972. // Don't we add ref the monitor here?
  4973. //
  4974. pIniDriver->pIniLangMonitor = FindMonitor(pIniDriver->pMonitorName, pIniSpooler);
  4975. //
  4976. // Cluster spoolers do not have keep their own lists of language monitors.
  4977. // This is because most language monitors are not cluster aware. Therefore,
  4978. // cluster spooler share language monitors with the local spooler.
  4979. //
  4980. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  4981. !pIniDriver->pIniLangMonitor &&
  4982. pLocalIniSpooler)
  4983. {
  4984. //
  4985. // We try to find the langauge monitor off the local spooler
  4986. //
  4987. pIniDriver->pIniLangMonitor = FindMonitor(pIniDriver->pMonitorName, pLocalIniSpooler);
  4988. }
  4989. if (!pIniDriver->pIniLangMonitor)
  4990. {
  4991. DBGMSG(DBG_TRACE, ("Can't find print monitor %ws\n", pIniDriver->pMonitorName));
  4992. }
  4993. }
  4994. return pIniDriver;
  4995. }
  4996. Fail:
  4997. FreeSplStr( pDriverName );
  4998. FreeSplStr( pConfigFile );
  4999. FreeSplStr( pDataFile );
  5000. FreeSplStr( pHelpFile );
  5001. FreeSplStr( pMonitorName );
  5002. FreeSplStr( pDefaultDataType );
  5003. FreeSplStr( pDependentFiles );
  5004. FreeSplStr( pszzPreviousNames );
  5005. FreeSplStr( pDriver );
  5006. FreeSplStr( pTemp);
  5007. FreeSplStr( pszMfgName);
  5008. FreeSplStr( pszOEMUrl);
  5009. FreeSplStr( pszProvider);
  5010. FreeSplStr( pszHardwareID);
  5011. if( hDriverKey ) {
  5012. SplRegCloseKey(hDriverKey, pIniSpooler);
  5013. }
  5014. SetLastError( dwLastError );
  5015. return NULL;
  5016. }
  5017. PINIDRIVER
  5018. FindLocalDriver(
  5019. PINISPOOLER pIniSpooler,
  5020. LPWSTR pz
  5021. )
  5022. {
  5023. PINIVERSION pIniVersion;
  5024. if ( !pz || !*pz ) {
  5025. return NULL;
  5026. }
  5027. //
  5028. // During Upgrade we load any driver so we have a valid printer, which might not be able to boot.
  5029. //
  5030. return FindCompatibleDriver(GetLocalArchEnv(pIniSpooler),
  5031. &pIniVersion,
  5032. pz,
  5033. dwMajorVersion,
  5034. dwUpgradeFlag);
  5035. }
  5036. BOOL
  5037. FindLocalDriverAndVersion(
  5038. PINISPOOLER pIniSpooler,
  5039. LPWSTR pz,
  5040. PINIDRIVER *ppIniDriver,
  5041. PINIVERSION *ppIniVersion
  5042. )
  5043. {
  5044. if ( !pz || !*pz || !ppIniDriver || !ppIniVersion) {
  5045. return FALSE;
  5046. }
  5047. //
  5048. // During Upgrade we load any driver so we have a valid printer, which might not be able to boot.
  5049. //
  5050. *ppIniDriver = FindCompatibleDriver( GetLocalArchEnv(pIniSpooler),
  5051. ppIniVersion,
  5052. pz,
  5053. dwMajorVersion,
  5054. dwUpgradeFlag );
  5055. if ( !*ppIniDriver || !*ppIniVersion ) {
  5056. return FALSE;
  5057. }
  5058. return TRUE;
  5059. }
  5060. #if DBG
  5061. VOID
  5062. InitializeDebug(
  5063. PINISPOOLER pIniSpooler
  5064. )
  5065. {
  5066. DWORD Status;
  5067. HKEY hKey = pIniSpooler->hckRoot;
  5068. DWORD cbData;
  5069. INT TimeOut = 60;
  5070. cbData = sizeof(DWORD);
  5071. Status = SplRegQueryValue( hKey,
  5072. szDebugFlags,
  5073. NULL,
  5074. (LPBYTE)&MODULE_DEBUG,
  5075. &cbData,
  5076. pIniSpooler );
  5077. // Wait until someone turns off the Pause Flag
  5078. if ( Status != NO_ERROR )
  5079. return;
  5080. while ( MODULE_DEBUG & DBG_PAUSE ) {
  5081. Sleep(1*1000);
  5082. if ( TimeOut-- == 0)
  5083. break;
  5084. }
  5085. DBGMSG(DBG_TRACE, ("DebugFlags %x\n", MODULE_DEBUG));
  5086. }
  5087. #endif
  5088. VOID
  5089. GetPrintSystemVersion(
  5090. PINISPOOLER pIniSpooler
  5091. )
  5092. {
  5093. DWORD Status;
  5094. HKEY hKey;
  5095. DWORD cbData;
  5096. hKey = pIniSpooler->hckRoot;
  5097. cbData = sizeof(DWORD);
  5098. RegQueryValueEx(hKey, szMinorVersion, NULL, NULL,
  5099. (LPBYTE)&dwMinorVersion, &cbData);
  5100. DBGMSG(DBG_TRACE, ("This Minor Version - %d\n", dwMinorVersion));
  5101. cbData = sizeof(DWORD);
  5102. RegQueryValueEx(hKey, L"FastPrintWaitTimeout", NULL, NULL,
  5103. (LPBYTE)&dwFastPrintWaitTimeout, &cbData);
  5104. DBGMSG(DBG_TRACE, ("dwFastPrintWaitTimeout - %d\n", dwFastPrintWaitTimeout));
  5105. cbData = sizeof(DWORD);
  5106. RegQueryValueEx(hKey, L"FastPrintThrottleTimeout", NULL, NULL,
  5107. (LPBYTE)&dwFastPrintThrottleTimeout, &cbData);
  5108. DBGMSG(DBG_TRACE, ("dwFastPrintThrottleTimeout - %d\n", dwFastPrintThrottleTimeout));
  5109. // If the values look invalid use Defaults
  5110. if (( dwFastPrintThrottleTimeout == 0) ||
  5111. ( dwFastPrintWaitTimeout < dwFastPrintThrottleTimeout)) {
  5112. DBGMSG( DBG_WARNING, ("Bad timeout values FastPrintThrottleTimeout %d FastPrintWaitTimeout %d using defaults\n",
  5113. dwFastPrintThrottleTimeout, dwFastPrintWaitTimeout));
  5114. dwFastPrintThrottleTimeout = FASTPRINT_THROTTLE_TIMEOUT;
  5115. dwFastPrintWaitTimeout = FASTPRINT_WAIT_TIMEOUT;
  5116. }
  5117. // Calculate a reasonable Threshold based on the two timeouts
  5118. dwFastPrintSlowDownThreshold = dwFastPrintWaitTimeout / dwFastPrintThrottleTimeout;
  5119. // FastPrintSlowDownThreshold
  5120. cbData = sizeof(DWORD);
  5121. RegQueryValueEx(hKey, L"FastPrintSlowDownThreshold", NULL, NULL,
  5122. (LPBYTE)&dwFastPrintSlowDownThreshold, &cbData);
  5123. DBGMSG(DBG_TRACE, ("dwFastPrintSlowDownThreshold - %d\n", dwFastPrintSlowDownThreshold));
  5124. // PortThreadPriority
  5125. cbData = sizeof dwPortThreadPriority;
  5126. Status = RegQueryValueEx(hKey, SPLREG_PORT_THREAD_PRIORITY, NULL, NULL,
  5127. (LPBYTE)&dwPortThreadPriority, &cbData);
  5128. if (Status != ERROR_SUCCESS ||
  5129. (dwPortThreadPriority != THREAD_PRIORITY_LOWEST &&
  5130. dwPortThreadPriority != THREAD_PRIORITY_BELOW_NORMAL &&
  5131. dwPortThreadPriority != THREAD_PRIORITY_NORMAL &&
  5132. dwPortThreadPriority != THREAD_PRIORITY_ABOVE_NORMAL &&
  5133. dwPortThreadPriority != THREAD_PRIORITY_HIGHEST)) {
  5134. dwPortThreadPriority = DEFAULT_PORT_THREAD_PRIORITY;
  5135. SetPrinterDataServer( pIniSpooler,
  5136. SPLREG_PORT_THREAD_PRIORITY,
  5137. REG_DWORD,
  5138. (LPBYTE) &dwPortThreadPriority,
  5139. sizeof dwPortThreadPriority
  5140. );
  5141. }
  5142. DBGMSG(DBG_TRACE, ("dwPortThreadPriority - %d\n", dwPortThreadPriority));
  5143. // SchedulerThreadPriority
  5144. cbData = sizeof dwSchedulerThreadPriority;
  5145. Status = RegQueryValueEx(hKey, SPLREG_SCHEDULER_THREAD_PRIORITY, NULL, NULL,
  5146. (LPBYTE)&dwSchedulerThreadPriority, &cbData);
  5147. if (Status != ERROR_SUCCESS ||
  5148. (dwSchedulerThreadPriority != THREAD_PRIORITY_LOWEST &&
  5149. dwSchedulerThreadPriority != THREAD_PRIORITY_BELOW_NORMAL &&
  5150. dwSchedulerThreadPriority != THREAD_PRIORITY_NORMAL &&
  5151. dwSchedulerThreadPriority != THREAD_PRIORITY_ABOVE_NORMAL &&
  5152. dwSchedulerThreadPriority != THREAD_PRIORITY_HIGHEST)) {
  5153. dwSchedulerThreadPriority = DEFAULT_SCHEDULER_THREAD_PRIORITY;
  5154. SetPrinterDataServer( pIniSpooler,
  5155. SPLREG_SCHEDULER_THREAD_PRIORITY,
  5156. REG_DWORD,
  5157. (LPBYTE) &dwSchedulerThreadPriority,
  5158. sizeof dwSchedulerThreadPriority
  5159. );
  5160. }
  5161. DBGMSG(DBG_TRACE, ("dwSchedulerThreadPriority - %d\n", dwSchedulerThreadPriority));
  5162. // WritePrinterSleepTime
  5163. cbData = sizeof(DWORD);
  5164. RegQueryValueEx(hKey, L"WritePrinterSleepTime", NULL, NULL,
  5165. (LPBYTE)&dwWritePrinterSleepTime, &cbData);
  5166. DBGMSG(DBG_TRACE, ("dwWritePrinterSleepTime - %d\n", dwWritePrinterSleepTime));
  5167. // ServerThreadPriority
  5168. cbData = sizeof(DWORD);
  5169. RegQueryValueEx(hKey, L"ServerThreadPriority", NULL, NULL,
  5170. (LPBYTE)&dwServerThreadPriority, &cbData);
  5171. DBGMSG(DBG_TRACE, ("dwServerThreadPriority - %d\n", dwServerThreadPriority));
  5172. // ServerThreadTimeout
  5173. cbData = sizeof(DWORD);
  5174. RegQueryValueEx(hKey, L"ServerThreadTimeout", NULL, NULL,
  5175. (LPBYTE)&ServerThreadTimeout, &cbData);
  5176. DBGMSG(DBG_TRACE, ("ServerThreadTimeout - %d\n", ServerThreadTimeout));
  5177. // EnableBroadcastSpoolerStatus
  5178. cbData = sizeof(DWORD);
  5179. RegQueryValueEx(hKey, L"EnableBroadcastSpoolerStatus", NULL, NULL,
  5180. (LPBYTE)&dwEnableBroadcastSpoolerStatus, &cbData);
  5181. DBGMSG(DBG_TRACE, ("EnableBroadcastSpoolerStatus - %d\n",
  5182. dwEnableBroadcastSpoolerStatus ));
  5183. // NetPrinterDecayPeriod
  5184. cbData = sizeof(DWORD);
  5185. RegQueryValueEx(hKey, L"NetPrinterDecayPeriod", NULL, NULL,
  5186. (LPBYTE)&NetPrinterDecayPeriod, &cbData);
  5187. DBGMSG(DBG_TRACE, ("NetPrinterDecayPeriod - %d\n", NetPrinterDecayPeriod));
  5188. // RefreshTimesPerDecayPeriod
  5189. cbData = sizeof(DWORD);
  5190. RegQueryValueEx(hKey, L"RefreshTimesPerDecayPeriod", NULL, NULL,
  5191. (LPBYTE)&RefreshTimesPerDecayPeriod, &cbData);
  5192. DBGMSG(DBG_TRACE, ("RefreshTimesPerDecayPeriod - %d\n", RefreshTimesPerDecayPeriod));
  5193. if ( RefreshTimesPerDecayPeriod == 0 ) {
  5194. RefreshTimesPerDecayPeriod = DEFAULT_REFRESH_TIMES_PER_DECAY_PERIOD;
  5195. }
  5196. // BrowsePrintWorkstations
  5197. cbData = sizeof( BrowsePrintWorkstations );
  5198. RegQueryValueEx( hKey, L"BrowsePrintWorkstations", NULL, NULL, (LPBYTE)&BrowsePrintWorkstations, &cbData );
  5199. DBGMSG( DBG_TRACE, ("BrowsePrintWorkstations - %d\n", BrowsePrintWorkstations ));
  5200. }
  5201. /*++
  5202. Routine Name:
  5203. AllowFaxSharing
  5204. Routine Description:
  5205. This routine looks at the sku to determine whether we should allowing sharing
  5206. out and printing to a fax driver.
  5207. We don't allow sharing the fax printer on Personal & Professional.
  5208. We also don't allow sharing of the fax printer on a Web Blade.
  5209. Arguments:
  5210. None.
  5211. Return Value:
  5212. TRUE - We can share out the fax driver.
  5213. --*/
  5214. BOOL
  5215. AllowFaxSharing(
  5216. VOID
  5217. )
  5218. {
  5219. BOOL bAllowFaxSharing = TRUE;
  5220. DWORDLONG dwlConditionMask = 0;
  5221. OSVERSIONINFOEX osvi = { 0 };
  5222. osvi.dwOSVersionInfoSize = sizeof(osvi);
  5223. osvi.wProductType = VER_NT_WORKSTATION;
  5224. VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_LESS_EQUAL);
  5225. //
  5226. // We allow sharing if it isn't WORKSTATION or PRO.
  5227. //
  5228. bAllowFaxSharing = !VerifyVersionInfo(&osvi, VER_PRODUCT_TYPE, dwlConditionMask);
  5229. if (bAllowFaxSharing)
  5230. {
  5231. ZeroMemory(&osvi, sizeof(osvi));
  5232. osvi.dwOSVersionInfoSize = sizeof(osvi);
  5233. osvi.wSuiteMask = VER_SUITE_BLADE;
  5234. VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
  5235. //
  5236. // We allow sharing if it isn't a web blade.
  5237. //
  5238. bAllowFaxSharing = !VerifyVersionInfo(&osvi, VER_SUITENAME, dwlConditionMask);
  5239. }
  5240. return bAllowFaxSharing;
  5241. }
  5242. VOID
  5243. InitializeSpoolerSettings(
  5244. PINISPOOLER pIniSpooler
  5245. )
  5246. {
  5247. HKEY hKey;
  5248. HKEY hKeyProvider;
  5249. DWORD cbData;
  5250. DWORD dwLastError;
  5251. DWORD Status;
  5252. DWORD CacheMasqPrinters;
  5253. DWORDLONG dwlConditionMask = 0;
  5254. OSVERSIONINFOEX osvi;
  5255. hKey = pIniSpooler->hckRoot;
  5256. //
  5257. // BeepEnabled
  5258. //
  5259. cbData = sizeof pIniSpooler->dwBeepEnabled;
  5260. Status = SplRegQueryValue(hKey,
  5261. SPLREG_BEEP_ENABLED,
  5262. NULL,
  5263. (LPBYTE)&pIniSpooler->dwBeepEnabled,
  5264. &cbData,
  5265. pIniSpooler);
  5266. if (Status!=ERROR_SUCCESS) {
  5267. DBGMSG(DBG_TRACE, ("BeepEnabled - SplRegQueryValue failed with error %u\n", Status));
  5268. }
  5269. pIniSpooler->dwBeepEnabled = !!pIniSpooler->dwBeepEnabled;
  5270. SetPrinterDataServer(pIniSpooler,
  5271. SPLREG_BEEP_ENABLED,
  5272. REG_DWORD,
  5273. (LPBYTE) &pIniSpooler->dwBeepEnabled,
  5274. sizeof pIniSpooler->dwBeepEnabled);
  5275. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  5276. //
  5277. // Restart job time.
  5278. //
  5279. cbData = sizeof( pIniSpooler->dwJobCompletionTimeout );
  5280. Status = SplRegQueryValue( hKey,
  5281. L"JobCompletionTimeout",
  5282. NULL,
  5283. (LPBYTE)&pIniSpooler->dwJobCompletionTimeout,
  5284. &cbData,
  5285. pIniSpooler );
  5286. if( Status != ERROR_SUCCESS ){
  5287. pIniSpooler->dwJobCompletionTimeout = DEFAULT_JOB_COMPLETION_TIMEOUT;
  5288. }
  5289. DBGMSG( DBG_TRACE, ("JobCompletionTimeout - %d\n", pIniSpooler->dwJobCompletionTimeout ));
  5290. }
  5291. //
  5292. // Retrieve whether we want to cache masq printer settings, default is FALSE.
  5293. //
  5294. cbData = sizeof(CacheMasqPrinters);
  5295. Status = SplRegQueryValue(hKey,
  5296. gszCacheMasqPrinters,
  5297. NULL,
  5298. (BYTE *)&CacheMasqPrinters,
  5299. &cbData,
  5300. pIniSpooler);
  5301. //
  5302. // We only set the bit for caching masq printers if CacbeMasqPrinters is
  5303. // non-NULL.
  5304. //
  5305. if (Status == ERROR_SUCCESS && CacheMasqPrinters != 0) {
  5306. pIniSpooler->dwSpoolerSettings |= SPOOLER_CACHEMASQPRINTERS;
  5307. }
  5308. //
  5309. // Some Folks like the NT FAX Service Don't want people to be able
  5310. // to remotely print with specific printer drivers.
  5311. //
  5312. if (!AllowFaxSharing()) {
  5313. pIniSpooler->pNoRemotePrintDrivers = AllocSplStr(szNTFaxDriver);
  5314. pIniSpooler->cchNoRemotePrintDrivers = wcslen(szNTFaxDriver) + 1;
  5315. gbRemoteFax = FALSE;
  5316. }
  5317. //
  5318. // If this is embedded NT, then allow masq printers to get non-RAW
  5319. // jobs. This is for Xerox.
  5320. //
  5321. dwlConditionMask = 0;
  5322. ZeroMemory(&osvi, sizeof(osvi));
  5323. osvi.wSuiteMask = VER_SUITE_EMBEDDEDNT;
  5324. VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
  5325. if (VerifyVersionInfo( &osvi,
  5326. VER_SUITENAME,
  5327. dwlConditionMask)) {
  5328. pIniSpooler->SpoolerFlags |= SPL_NON_RAW_TO_MASQ_PRINTERS;
  5329. }
  5330. Status = SplRegCreateKey( pIniSpooler->hckRoot,
  5331. pIniSpooler->pszRegistryProviders,
  5332. 0,
  5333. KEY_READ,
  5334. NULL,
  5335. &hKeyProvider,
  5336. NULL,
  5337. pIniSpooler );
  5338. if( Status == NO_ERROR ){
  5339. DWORD Flags;
  5340. // NonRawToMasqPrinters
  5341. cbData = sizeof( Flags );
  5342. Status = SplRegQueryValue( hKeyProvider,
  5343. SPLREG_NON_RAW_TO_MASQ_PRINTERS,
  5344. NULL,
  5345. (LPBYTE)&Flags,
  5346. &cbData,
  5347. pIniSpooler );
  5348. if (Status == ERROR_SUCCESS) {
  5349. if (Flags) {
  5350. pIniSpooler->SpoolerFlags |= SPL_NON_RAW_TO_MASQ_PRINTERS;
  5351. }
  5352. }
  5353. // EventLog
  5354. cbData = sizeof( Flags );
  5355. Status = SplRegQueryValue( hKeyProvider,
  5356. SPLREG_EVENT_LOG,
  5357. NULL,
  5358. (LPBYTE)&Flags,
  5359. &cbData,
  5360. pIniSpooler );
  5361. if (Status == ERROR_SUCCESS) {
  5362. pIniSpooler->dwEventLogging = Flags;
  5363. } else {
  5364. Status = SetPrinterDataServer( pIniSpooler,
  5365. SPLREG_EVENT_LOG,
  5366. REG_DWORD,
  5367. (LPBYTE)&pIniSpooler->dwEventLogging,
  5368. sizeof( pIniSpooler->dwEventLogging ));
  5369. }
  5370. // NetPopup
  5371. cbData = sizeof( Flags );
  5372. Status = SplRegQueryValue( hKeyProvider,
  5373. SPLREG_NET_POPUP,
  5374. NULL,
  5375. (LPBYTE)&Flags,
  5376. &cbData,
  5377. pIniSpooler );
  5378. if (Status == ERROR_SUCCESS) {
  5379. pIniSpooler->bEnableNetPopups = !!Flags;
  5380. if (Flags != 1 && Flags != 0) {
  5381. Status = SetPrinterDataServer( pIniSpooler,
  5382. SPLREG_NET_POPUP,
  5383. REG_DWORD,
  5384. (LPBYTE)&pIniSpooler->bEnableNetPopups,
  5385. sizeof( pIniSpooler->bEnableNetPopups ));
  5386. }
  5387. } else {
  5388. Status = SetPrinterDataServer( pIniSpooler,
  5389. SPLREG_NET_POPUP,
  5390. REG_DWORD,
  5391. (LPBYTE)&pIniSpooler->bEnableNetPopups,
  5392. sizeof( pIniSpooler->bEnableNetPopups ));
  5393. }
  5394. // NetPopupToComputer
  5395. cbData = sizeof( Flags );
  5396. Status = SplRegQueryValue( hKeyProvider,
  5397. SPLREG_NET_POPUP_TO_COMPUTER,
  5398. NULL,
  5399. (LPBYTE)&Flags,
  5400. &cbData,
  5401. pIniSpooler );
  5402. if (Status == ERROR_SUCCESS) {
  5403. pIniSpooler->bEnableNetPopupToComputer = !!Flags;
  5404. if (Flags != 1 && Flags != 0) {
  5405. Status = SetPrinterDataServer( pIniSpooler,
  5406. SPLREG_NET_POPUP_TO_COMPUTER,
  5407. REG_DWORD,
  5408. (LPBYTE)&pIniSpooler->bEnableNetPopupToComputer,
  5409. sizeof( pIniSpooler->bEnableNetPopupToComputer ));
  5410. }
  5411. } else {
  5412. Status = SetPrinterDataServer( pIniSpooler,
  5413. SPLREG_NET_POPUP_TO_COMPUTER,
  5414. REG_DWORD,
  5415. (LPBYTE)&pIniSpooler->bEnableNetPopupToComputer,
  5416. sizeof( pIniSpooler->bEnableNetPopupToComputer ));
  5417. }
  5418. // RetryPopup
  5419. cbData = sizeof( Flags );
  5420. Status = SplRegQueryValue( hKeyProvider,
  5421. SPLREG_RETRY_POPUP,
  5422. NULL,
  5423. (LPBYTE)&Flags,
  5424. &cbData,
  5425. pIniSpooler );
  5426. if (Status == ERROR_SUCCESS) {
  5427. pIniSpooler->bEnableRetryPopups = !!Flags;
  5428. if (Flags != 1 && Flags != 0) {
  5429. Status = SetPrinterDataServer( pIniSpooler,
  5430. SPLREG_RETRY_POPUP,
  5431. REG_DWORD,
  5432. (LPBYTE)&pIniSpooler->bEnableRetryPopups,
  5433. sizeof( pIniSpooler->bEnableRetryPopups ));
  5434. }
  5435. } else {
  5436. Status = SetPrinterDataServer( pIniSpooler,
  5437. SPLREG_RETRY_POPUP,
  5438. REG_DWORD,
  5439. (LPBYTE)&pIniSpooler->bEnableRetryPopups,
  5440. sizeof( pIniSpooler->bEnableRetryPopups ));
  5441. }
  5442. // RestartJobOnPoolError
  5443. cbData = sizeof( Flags );
  5444. Status = SplRegQueryValue( hKeyProvider,
  5445. SPLREG_RESTART_JOB_ON_POOL_ERROR,
  5446. NULL,
  5447. (LPBYTE)&Flags,
  5448. &cbData,
  5449. pIniSpooler );
  5450. if (Status == ERROR_SUCCESS) {
  5451. pIniSpooler->dwRestartJobOnPoolTimeout = Flags;
  5452. } else {
  5453. Status = SetPrinterDataServer( pIniSpooler,
  5454. SPLREG_RESTART_JOB_ON_POOL_ERROR,
  5455. REG_DWORD,
  5456. (LPBYTE)&pIniSpooler->dwRestartJobOnPoolTimeout,
  5457. sizeof( pIniSpooler->dwRestartJobOnPoolTimeout ));
  5458. }
  5459. // RestartJobOnPoolEnabled
  5460. cbData = sizeof( Flags );
  5461. Status = SplRegQueryValue( hKeyProvider,
  5462. SPLREG_RESTART_JOB_ON_POOL_ENABLED,
  5463. NULL,
  5464. (LPBYTE)&Flags,
  5465. &cbData,
  5466. pIniSpooler );
  5467. if (Status == ERROR_SUCCESS) {
  5468. pIniSpooler->bRestartJobOnPoolEnabled = !!Flags;
  5469. if (Flags != 1 && Flags != 0) {
  5470. Status = SetPrinterDataServer( pIniSpooler,
  5471. SPLREG_RESTART_JOB_ON_POOL_ENABLED,
  5472. REG_DWORD,
  5473. (LPBYTE)&pIniSpooler->bRestartJobOnPoolEnabled,
  5474. sizeof( pIniSpooler->bRestartJobOnPoolEnabled ));
  5475. }
  5476. } else {
  5477. Status = SetPrinterDataServer( pIniSpooler,
  5478. SPLREG_RESTART_JOB_ON_POOL_ENABLED,
  5479. REG_DWORD,
  5480. (LPBYTE)&pIniSpooler->bRestartJobOnPoolEnabled,
  5481. sizeof( pIniSpooler->bRestartJobOnPoolEnabled ));
  5482. }
  5483. SplRegCloseKey( hKeyProvider, pIniSpooler );
  5484. }
  5485. GetDiscardTSJobsSettings( pIniSpooler );
  5486. GetServerFilePoolSettings( pIniSpooler );
  5487. }
  5488. VOID
  5489. GetServerFilePoolSettings(
  5490. PINISPOOLER pIniSpooler
  5491. )
  5492. {
  5493. //
  5494. // We read the registry key DisableServerFilePooling from
  5495. // HKLM\System\CurrentControlSet\Control\Print once on spooler startup.
  5496. // If the value is set, filepooling for the server is disabled.
  5497. //
  5498. DWORD RegValue = 0;
  5499. DWORD RegValueSize = sizeof(RegValue);
  5500. HKEY RegKey = NULL;
  5501. DWORD dwError = ERROR_SUCCESS;
  5502. DWORD RegValueType;
  5503. dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  5504. ipszRegistryRoot,
  5505. 0,
  5506. KEY_READ,
  5507. &RegKey );
  5508. if (dwError == ERROR_SUCCESS)
  5509. {
  5510. dwError = RegQueryValueEx( RegKey,
  5511. szDisableFilePooling,
  5512. NULL,
  5513. (LPDWORD) &RegValueType,
  5514. (LPBYTE) &RegValue,
  5515. &RegValueSize );
  5516. if ( RegValueType == REG_DWORD && dwError == ERROR_SUCCESS && RegValue > 0)
  5517. {
  5518. pIniSpooler->dwSpoolerSettings |= SPOOLER_NOFILEPOOLING;
  5519. }
  5520. }
  5521. if (RegKey)
  5522. {
  5523. RegCloseKey( RegKey );
  5524. }
  5525. }
  5526. DWORD
  5527. FinalInitAfterRouterInitComplete(
  5528. DWORD dwUpgrade,
  5529. PINISPOOLER pIniSpooler
  5530. )
  5531. /*++
  5532. Routine Description:
  5533. This thread does LocalSpl initialization that has to happen after
  5534. the router has completely initialized.
  5535. There are 2 jobs:-
  5536. Upgrading Printer Driver Data
  5537. Sharing Printers
  5538. Ensures that printers are shared. This case occurs when the spooler
  5539. service not running on startup (and the server is), and then the
  5540. user starts the spooler.
  5541. We also get the benefit of closing down any invalid printer handles
  5542. (in the server).
  5543. Arguments:
  5544. dwUpgrade != 0 upgrade printer driver data.
  5545. Return Value:
  5546. DWORD - ignored
  5547. --*/
  5548. {
  5549. DWORD dwPort;
  5550. PINIPORT pIniPort;
  5551. PINIMONITOR pIniLangMonitor;
  5552. PINIPRINTER pIniPrinter;
  5553. PINIPRINTER pIniPrinterNext;
  5554. // Do Not share all the printers during an Upgrade.
  5555. if ( dwUpgrade ) {
  5556. return 0;
  5557. }
  5558. WaitForSpoolerInitialization();
  5559. // Try pending driver upgrades on spooler startup
  5560. PendingDriverUpgrades(NULL);
  5561. EnterSplSem();
  5562. // Delete printers in pending deletion state with no jobs
  5563. CleanupDeletedPrinters(pIniSpooler);
  5564. //
  5565. // Re-share all shared printers.
  5566. //
  5567. for( pIniPrinter = pIniSpooler->pIniPrinter;
  5568. pIniPrinter;
  5569. pIniPrinter = pIniPrinterNext ) {
  5570. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
  5571. //
  5572. // Up the ref count to prevent deletion
  5573. //
  5574. INCPRINTERREF( pIniPrinter );
  5575. //
  5576. // Unshare it first. We are doing it both to close all handles in the
  5577. // server ( for the case when the printer is shared ) or to just unshare
  5578. // the printer if the policy says so ( we cleared the attribute above )
  5579. //
  5580. ShareThisPrinter( pIniPrinter,
  5581. pIniPrinter->pShareName,
  5582. FALSE );
  5583. //
  5584. // We are checking if the printer is still shared ( the attribute could have been
  5585. // cleared as a result of the remote connctions policy being off or , if that's
  5586. // not the case, as a result of leaving the Spooler semaphore in ShareThisPrinter)
  5587. //
  5588. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
  5589. BOOL bReturn;
  5590. //
  5591. // Now share it again.
  5592. //
  5593. bReturn = ShareThisPrinter( pIniPrinter,
  5594. pIniPrinter->pShareName,
  5595. TRUE );
  5596. if( !bReturn ){
  5597. DWORD rc = GetLastError();
  5598. if( rc != NERR_ServerNotStarted &&
  5599. rc != NERR_DuplicateShare ){
  5600. WCHAR szError[256];
  5601. DBGMSG( DBG_WARNING,
  5602. ( "NetShareAdd failed %lx\n", rc));
  5603. StringCchPrintf(szError, COUNTOF(szError), L"+ %d", rc);
  5604. SplLogEvent( pIniSpooler,
  5605. LOG_ERROR,
  5606. MSG_SHARE_FAILED,
  5607. TRUE,
  5608. szError,
  5609. pIniPrinter->pName,
  5610. pIniPrinter->pShareName,
  5611. NULL );
  5612. }
  5613. }
  5614. }
  5615. DECPRINTERREF( pIniPrinter );
  5616. pIniPrinterNext = pIniPrinter->pNext;
  5617. } else {
  5618. //
  5619. // The unshared case.
  5620. //
  5621. pIniPrinterNext = pIniPrinter->pNext;
  5622. }
  5623. INCPRINTERREF(pIniPrinter);
  5624. if (pIniPrinterNext)
  5625. INCPRINTERREF(pIniPrinterNext);
  5626. for ( dwPort = 0 ; dwPort < pIniPrinter->cPorts ; ++dwPort ) {
  5627. pIniPort = pIniPrinter->ppIniPorts[dwPort];
  5628. //
  5629. // Bidi monitor can inform spooler of errors. First
  5630. // printer will keep the port at the beginning
  5631. //
  5632. if ( pIniPort->ppIniPrinter[0] != pIniPrinter )
  5633. continue;
  5634. if ( !pIniPort->hMonitorHandle && dwUpgradeFlag == 0 ) {
  5635. LPTSTR pszPrinter;
  5636. TCHAR szFullPrinter[ MAX_UNC_PRINTER_NAME ];
  5637. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  5638. pszPrinter = szFullPrinter;
  5639. StringCchPrintf(szFullPrinter,
  5640. COUNTOF(szFullPrinter),
  5641. L"%ws\\%ws",
  5642. pIniSpooler->pMachineName,
  5643. pIniPrinter->pName);
  5644. } else {
  5645. pszPrinter = pIniPrinter->pName;
  5646. }
  5647. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_ENABLE_BIDI )
  5648. pIniLangMonitor = pIniPrinter->pIniDriver->pIniLangMonitor;
  5649. else
  5650. pIniLangMonitor = NULL;
  5651. OpenMonitorPort(pIniPort,
  5652. pIniLangMonitor,
  5653. pszPrinter);
  5654. ReleaseMonitorPort(pIniPort);
  5655. }
  5656. }
  5657. if (pIniPrinterNext)
  5658. DECPRINTERREF(pIniPrinterNext);
  5659. DECPRINTERREF(pIniPrinter);
  5660. }
  5661. LeaveSplSem();
  5662. return 0;
  5663. }
  5664. DWORD
  5665. FinalInitAfterRouterInitCompleteThread(
  5666. DWORD dwUpgrade
  5667. )
  5668. /*++
  5669. Routine Description:
  5670. Async thread called when initializing provider.
  5671. Arguments:
  5672. Return Value:
  5673. --*/
  5674. {
  5675. return FinalInitAfterRouterInitComplete( dwUpgrade, pLocalIniSpooler );
  5676. }
  5677. // DEBUG PURPOSE ONLY - - returns TRUE if pMem is an IniSpooler, FALSE otherwise
  5678. BOOL
  5679. NotIniSpooler(
  5680. BYTE *pMem
  5681. )
  5682. {
  5683. PINISPOOLER pIniSpooler;
  5684. for (pIniSpooler = pLocalIniSpooler ; pIniSpooler ; pIniSpooler = pIniSpooler->pIniNextSpooler)
  5685. if (pIniSpooler == (PINISPOOLER) pMem)
  5686. return FALSE;
  5687. return TRUE;
  5688. }
  5689. BOOL
  5690. ValidateProductSuite(
  5691. PWSTR pszSuiteName
  5692. )
  5693. {
  5694. BOOL bRet = FALSE;
  5695. LONG Rslt;
  5696. HKEY hKey = NULL;
  5697. DWORD Type = 0;
  5698. DWORD Size = 0;
  5699. PWSTR pszProductSuite = NULL;
  5700. PWSTR psz;
  5701. Rslt = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  5702. ipszRegistryProductOptions,
  5703. 0,
  5704. KEY_READ,
  5705. &hKey);
  5706. if (Rslt != ERROR_SUCCESS)
  5707. goto exit;
  5708. Rslt = RegQueryValueEx(
  5709. hKey,
  5710. L"ProductSuite",
  5711. NULL,
  5712. &Type,
  5713. NULL,
  5714. &Size
  5715. );
  5716. if (!Size || Rslt != ERROR_SUCCESS)
  5717. goto exit;
  5718. pszProductSuite = AllocSplMem(Size);
  5719. if (!pszProductSuite) {
  5720. goto exit;
  5721. }
  5722. Rslt = RegQueryValueEx(
  5723. hKey,
  5724. L"ProductSuite",
  5725. NULL,
  5726. &Type,
  5727. (LPBYTE) pszProductSuite,
  5728. &Size
  5729. );
  5730. if (Rslt != ERROR_SUCCESS || Type != REG_MULTI_SZ)
  5731. goto exit;
  5732. for(psz = pszProductSuite ; *psz && wcscmp(psz, pszSuiteName) ; psz += wcslen(psz) + 1)
  5733. ;
  5734. if (*psz)
  5735. bRet = TRUE;
  5736. exit:
  5737. FreeSplMem(pszProductSuite);
  5738. if (hKey)
  5739. RegCloseKey(hKey);
  5740. return bRet;
  5741. }
  5742. /*++
  5743. Routine Name:
  5744. ClusterAddOrUpdateDriverFromClusterDisk
  5745. Routine Description:
  5746. Takes in a driver key and a cluster type pIniSpooler. It will add
  5747. a driver from the cluster disk to the cluster spooler. If the driver
  5748. already exists in the list of drivers, then it will attempt to upgrade
  5749. it.
  5750. Arguments:
  5751. hKeyVersion - key to Ex. "Environments\Windows NT x86\Drivers\Version-3"
  5752. pszDriverName - name a a driver
  5753. pszEnvName - environemnt of the driver
  5754. pszenvDir - directory for the driver files on the disk (Ex. w32x86)
  5755. pIniSpooler - cluster type pIniSpooler
  5756. Return Value:
  5757. Win32 error code
  5758. --*/
  5759. DWORD
  5760. ClusterAddOrUpdateDriverFromClusterDisk(
  5761. IN HKEY hKeyVersion,
  5762. IN LPCWSTR pszDriverName,
  5763. IN LPCWSTR pszEnvName,
  5764. IN LPCWSTR pszEnvDir,
  5765. IN PINISPOOLER pIniSpooler
  5766. )
  5767. {
  5768. LPWSTR pszzPathDepFiles = NULL;
  5769. DRIVER_INFO_6 Drv = {0};
  5770. HKEY hDrvKey = NULL;
  5771. WCHAR szVerPath[10] = {0};
  5772. DWORD dwError = ERROR_SUCCESS;
  5773. WCHAR szData[MAX_PATH];
  5774. WCHAR szPathConfigFile[MAX_PATH];
  5775. WCHAR szPathDataFile[MAX_PATH];
  5776. WCHAR szPathDriverFile[MAX_PATH];
  5777. WCHAR szPathHelpFile[MAX_PATH];
  5778. DWORD cbData;
  5779. DWORD cLen;
  5780. //
  5781. // Open the driver's key
  5782. //
  5783. if ((dwError = SplRegOpenKey(hKeyVersion,
  5784. pszDriverName,
  5785. KEY_READ,
  5786. &hDrvKey,
  5787. pIniSpooler)) == ERROR_SUCCESS &&
  5788. (dwError = (Drv.pName = AllocSplStr(pszDriverName)) ? ERROR_SUCCESS : GetLastError()) == ERROR_SUCCESS &&
  5789. RegGetString(hDrvKey, szConfigurationKey, &Drv.pConfigFile, &cLen, &dwError, TRUE, pIniSpooler) &&
  5790. RegGetString(hDrvKey, szDataFileKey, &Drv.pDataFile, &cLen, &dwError, TRUE, pIniSpooler) &&
  5791. RegGetString(hDrvKey, szDriverFile, &Drv.pDriverPath, &cLen, &dwError, TRUE, pIniSpooler) &&
  5792. (dwError = Drv.pConfigFile &&
  5793. Drv.pDataFile &&
  5794. Drv.pDriverPath ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER) == ERROR_SUCCESS &&
  5795. RegGetString(hDrvKey, szHelpFile, &Drv.pHelpFile, &cLen, &dwError, FALSE, pIniSpooler) &&
  5796. RegGetString(hDrvKey, szMonitor, &Drv.pMonitorName, &cLen, &dwError, FALSE, pIniSpooler) &&
  5797. RegGetString(hDrvKey, szDatatype, &Drv.pDefaultDataType, &cLen, &dwError, FALSE, pIniSpooler) &&
  5798. RegGetMultiSzString(hDrvKey, szDependentFiles, &Drv.pDependentFiles, &cLen, &dwError, FALSE, pIniSpooler) &&
  5799. RegGetMultiSzString(hDrvKey, szPreviousNames, &Drv.pszzPreviousNames,&cLen, &dwError, FALSE, pIniSpooler) &&
  5800. RegGetString(hDrvKey, szMfgName, &Drv.pszMfgName, &cLen, &dwError, FALSE, pIniSpooler) &&
  5801. RegGetString(hDrvKey, szOEMUrl, &Drv.pszOEMUrl, &cLen, &dwError, FALSE, pIniSpooler) &&
  5802. RegGetString(hDrvKey, szHardwareID, &Drv.pszHardwareID, &cLen, &dwError, TRUE, pIniSpooler) &&
  5803. RegGetString(hDrvKey, szProvider, &Drv.pszProvider, &cLen, &dwError, TRUE, pIniSpooler) &&
  5804. (dwError = ClusterFindLanguageMonitor(Drv.pMonitorName, pszEnvName, pIniSpooler)) == ERROR_SUCCESS)
  5805. {
  5806. cbData = sizeof(Drv.ftDriverDate);
  5807. SplRegQueryValue(hDrvKey,
  5808. szDriverDate,
  5809. NULL,
  5810. (LPBYTE)&Drv.ftDriverDate,
  5811. &cbData,
  5812. pIniSpooler);
  5813. cbData = sizeof(Drv.dwlDriverVersion);
  5814. SplRegQueryValue(hDrvKey,
  5815. szLongVersion,
  5816. NULL,
  5817. (LPBYTE)&Drv.dwlDriverVersion,
  5818. &cbData,
  5819. pIniSpooler);
  5820. cbData = sizeof(Drv.cVersion);
  5821. SplRegQueryValue(hDrvKey,
  5822. szDriverVersion,
  5823. NULL,
  5824. (LPBYTE)&Drv.cVersion,
  5825. &cbData,
  5826. pIniSpooler);
  5827. //
  5828. // We need the matching version <-> directory on disk
  5829. // Ex. Version-3 <-> 3
  5830. //
  5831. StringCchPrintf(szVerPath, COUNTOF(szVerPath), L"%u", Drv.cVersion);
  5832. //
  5833. // Get fully qualified driver file paths. We will do an add printer driver
  5834. // without using the scratch directory. So the files have to be fully
  5835. // qualified
  5836. //
  5837. if ((dwError = StrNCatBuff(szPathDriverFile,
  5838. COUNTOF(szPathDriverFile),
  5839. pIniSpooler->pszClusResDriveLetter, L"\\",
  5840. szClusterDriverRoot, L"\\",
  5841. pszEnvDir, L"\\",
  5842. szVerPath, L"\\",
  5843. Drv.pDriverPath,
  5844. NULL)) == ERROR_SUCCESS &&
  5845. (dwError = StrNCatBuff(szPathDataFile,
  5846. COUNTOF(szPathDataFile),
  5847. pIniSpooler->pszClusResDriveLetter, L"\\",
  5848. szClusterDriverRoot, L"\\",
  5849. pszEnvDir, L"\\",
  5850. szVerPath, L"\\",
  5851. Drv.pDataFile,
  5852. NULL)) == ERROR_SUCCESS &&
  5853. (dwError = StrNCatBuff(szPathConfigFile,
  5854. COUNTOF(szPathConfigFile),
  5855. pIniSpooler->pszClusResDriveLetter, L"\\",
  5856. szClusterDriverRoot, L"\\",
  5857. pszEnvDir, L"\\",
  5858. szVerPath, L"\\",
  5859. Drv.pConfigFile,
  5860. NULL)) == ERROR_SUCCESS &&
  5861. (dwError = StrNCatBuff(szPathHelpFile,
  5862. COUNTOF(szPathHelpFile),
  5863. pIniSpooler->pszClusResDriveLetter, L"\\",
  5864. szClusterDriverRoot, L"\\",
  5865. pszEnvDir, L"\\",
  5866. szVerPath, L"\\",
  5867. Drv.pHelpFile,
  5868. NULL)) == ERROR_SUCCESS &&
  5869. (dwError = StrNCatBuff(szData,
  5870. COUNTOF(szData),
  5871. pIniSpooler->pszClusResDriveLetter, L"\\",
  5872. szClusterDriverRoot, L"\\",
  5873. pszEnvDir, L"\\",
  5874. szVerPath, L"\\",
  5875. NULL)) == ERROR_SUCCESS &&
  5876. (dwError = StrCatPrefixMsz(szData,
  5877. Drv.pDependentFiles,
  5878. &pszzPathDepFiles)) == ERROR_SUCCESS)
  5879. {
  5880. LPWSTR pszTempDriver = Drv.pDriverPath;
  5881. LPWSTR pszTempData = Drv.pDataFile;
  5882. LPWSTR pszTempConfig = Drv.pConfigFile;
  5883. LPWSTR pszTempHelp = Drv.pHelpFile;
  5884. LPWSTR pszTempDep = Drv.pDependentFiles;
  5885. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpDrv szPathDriverFile = "TSTR"\n", szPathDriverFile));
  5886. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpDrv szPathDataFile = "TSTR"\n", szPathDataFile));
  5887. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpDrv szPathConfigFile = "TSTR"\n", szPathConfigFile));
  5888. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpDrv szPathHelpFile = "TSTR"\n", szPathHelpFile));
  5889. Drv.pDriverPath = szPathDriverFile;
  5890. Drv.pEnvironment = (LPWSTR)pszEnvName;
  5891. Drv.pDataFile = szPathDataFile;
  5892. Drv.pConfigFile = szPathConfigFile;
  5893. Drv.pHelpFile = szPathHelpFile;
  5894. Drv.pDependentFiles = pszzPathDepFiles;
  5895. if (!SplAddPrinterDriverEx(NULL,
  5896. 6,
  5897. (LPBYTE)&Drv,
  5898. APD_COPY_NEW_FILES | APD_DONT_COPY_FILES_TO_CLUSTER,
  5899. pIniSpooler,
  5900. FALSE,
  5901. DO_NOT_IMPERSONATE_USER))
  5902. {
  5903. dwError = GetLastError();
  5904. }
  5905. //
  5906. // Restore pointers
  5907. //
  5908. Drv.pDriverPath = pszTempDriver;
  5909. Drv.pConfigFile = pszTempConfig;
  5910. Drv.pDataFile = pszTempData;
  5911. Drv.pHelpFile = pszTempHelp;
  5912. Drv.pDependentFiles = pszTempDep;
  5913. }
  5914. }
  5915. FreeSplStr(Drv.pName);
  5916. FreeSplStr(Drv.pDriverPath);
  5917. FreeSplStr(Drv.pConfigFile);
  5918. FreeSplStr(Drv.pDataFile);
  5919. FreeSplStr(Drv.pHelpFile);
  5920. FreeSplStr(Drv.pMonitorName);
  5921. FreeSplStr(Drv.pDefaultDataType);
  5922. FreeSplStr(Drv.pDependentFiles);
  5923. FreeSplStr(Drv.pszzPreviousNames);
  5924. FreeSplStr(Drv.pszMfgName);
  5925. FreeSplStr(Drv.pszOEMUrl);
  5926. FreeSplStr(Drv.pszProvider);
  5927. FreeSplStr(Drv.pszHardwareID);
  5928. FreeSplStr(pszzPathDepFiles);
  5929. if (hDrvKey)
  5930. {
  5931. SplRegCloseKey(hDrvKey, pIniSpooler);
  5932. }
  5933. DBGMSG(DBG_CLUSTER, ("ClusterAddOrUpdateDriverFromClusterDisk returns Win32 error %u\n", dwError));
  5934. return dwError;
  5935. }
  5936. /*++
  5937. Routine Name:
  5938. SplCreateSpoolerWorkerThread
  5939. Routine Description:
  5940. This routine will be launched in a separate thread to perform time consuming
  5941. initialization as part of SplCreateSpooler when the spooler is a cluster spooler.
  5942. Tasks that it will do include copying down ICM profiles from the cluster disk.
  5943. The caller needs to AddRef the pIniSpooler so that it doesn't become invalid
  5944. (deleted) while we are using it.
  5945. This function closes the hClusSplReady event handle.
  5946. Arguments:
  5947. PINISPOOLER pIniSpooler
  5948. Return Value:
  5949. None
  5950. --*/
  5951. VOID
  5952. SplCreateSpoolerWorkerThread(
  5953. IN PVOID pv
  5954. )
  5955. {
  5956. PINISPOOLER pIniSpooler;
  5957. WCHAR szDir[MAX_PATH];
  5958. pIniSpooler = (PINISPOOLER)pv;
  5959. if (pIniSpooler &&
  5960. pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER &&
  5961. pIniSpooler->hClusSplReady)
  5962. {
  5963. HANDLE hSplReady = pIniSpooler->hClusSplReady;
  5964. //
  5965. // Waiting for the creating function (SplCreateSpooler) to terminate
  5966. //
  5967. WaitForSingleObject(pIniSpooler->hClusSplReady, INFINITE);
  5968. EnterSplSem();
  5969. pIniSpooler->hClusSplReady = NULL;
  5970. LeaveSplSem();
  5971. //
  5972. // We use hSplReady so we do not hold the critical section while doing CloseHandle
  5973. //
  5974. CloseHandle(hSplReady);
  5975. CopyICMFromClusterDiskToLocalDisk(pIniSpooler);
  5976. //
  5977. // If the node was upgraded, we need to upgrade the print drivers
  5978. // We cannot load ntprint and printui. So we create a process and
  5979. // call an entry point in ntprint. That one will enumerate all the
  5980. // cluster drivers and will try to upgrade them based on the new cab.
  5981. //
  5982. if (pIniSpooler->dwClusNodeUpgraded)
  5983. {
  5984. DWORD dwError;
  5985. DWORD dwCode = 0;
  5986. LPWSTR pszCommand = NULL;
  5987. LPWSTR pszExe = NULL;
  5988. //
  5989. // We need to pass as argument the name of the cluster spooler
  5990. //
  5991. if ((dwError = StrCatSystemPath(L"rundll32.exe",
  5992. kSystemDir,
  5993. &pszExe)) == ERROR_SUCCESS &&
  5994. (dwError = StrCatAlloc(&pszCommand,
  5995. L"rundll32.exe ntprint.dll,PSetupUpgradeClusterDrivers ",
  5996. pIniSpooler->pMachineName,
  5997. NULL)) == ERROR_SUCCESS &&
  5998. (dwError = RunProcess(pszExe, pszCommand, INFINITE, &dwCode)) == ERROR_SUCCESS)
  5999. {
  6000. //
  6001. // dwCode is the return code of the function PSetupUpgradeClusterDrivers in ntprint,
  6002. // executed inside the rundll32 process
  6003. //
  6004. if (dwCode == ERROR_SUCCESS)
  6005. {
  6006. //
  6007. // We upgraded all the printer drivers, now we delete the key from the registry
  6008. // so we don't go though upgrading printer drivers again next time when the
  6009. // cluster group comes online on this node
  6010. //
  6011. ClusterSplDeleteUpgradeKey(pIniSpooler->pszClusResID);
  6012. }
  6013. else
  6014. {
  6015. DBGMSG(DBG_WARN, ("Error upgrading cluster drivers! dwCode %u\n", dwCode));
  6016. }
  6017. }
  6018. FreeSplMem(pszCommand);
  6019. FreeSplMem(pszExe);
  6020. DBGMSG(DBG_CLUSTER, ("SplCreateSpoolerWorkerThread dwError %u dwCode %u\n", dwError, dwCode));
  6021. }
  6022. //
  6023. // Set resource private property ClusterDriverDirectry. This will be used by the
  6024. // ResDll to perform clean up when the spooler is deleted
  6025. //
  6026. if (StrNCatBuff(szDir,
  6027. COUNTOF(szDir),
  6028. pIniSpooler->pszClusResDriveLetter,
  6029. L"\\",
  6030. szClusterDriverRoot,
  6031. NULL) == ERROR_SUCCESS)
  6032. {
  6033. SplRegSetValue(pIniSpooler->hckRoot,
  6034. SPLREG_CLUSTER_DRIVER_DIRECTORY,
  6035. REG_SZ,
  6036. (LPBYTE)szDir,
  6037. (wcslen(szDir) + 1) * sizeof(WCHAR),
  6038. pIniSpooler);
  6039. }
  6040. EnterSplSem();
  6041. DECSPOOLERREF(pIniSpooler);
  6042. LeaveSplSem();
  6043. DBGMSG(DBG_CLUSTER, ("SplCreateSpoolerWorkerThread terminates pIniSpooler->cRef %u\n", pIniSpooler->cRef));
  6044. }
  6045. }
  6046. /*++
  6047. Routine Name:
  6048. LogFatalPortError
  6049. Routine Description:
  6050. This routine logs a message when a printer cannot be brought up because its
  6051. ports are missing.
  6052. Arguments:
  6053. pszName - The name of the printer.
  6054. Return Value:
  6055. None.
  6056. --*/
  6057. VOID
  6058. LogFatalPortError(
  6059. IN PINISPOOLER pIniSpooler,
  6060. IN PCWSTR pszName
  6061. )
  6062. {
  6063. DWORD LastError = ERROR_SUCCESS;
  6064. WCHAR szError[40] = {0};
  6065. LastError = GetLastError();
  6066. StringCchPrintf(szError, COUNTOF(szError), L"%u (0x%x)", LastError, LastError);
  6067. SplLogEvent(pIniSpooler,
  6068. LOG_ERROR,
  6069. MSG_PORT_INITIALIZATION_ERROR,
  6070. FALSE,
  6071. (PWSTR)pszName,
  6072. szError,
  6073. NULL);
  6074. }