Source code of Windows XP (NT5)
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.

2776 lines
73 KiB

  1. /*++
  2. Copyright (c) 1990 - 1995 Microsoft Corporation
  3. Module Name:
  4. prndata.c
  5. Abstract:
  6. This module provides all the public exported APIs relating to Printer
  7. and Job management for the Local Print Providor
  8. Author:
  9. Dave Snipp (DaveSn) 15-Mar-1991
  10. Revision History:
  11. mattfe Apr 5 95 - we keep the driver data key open
  12. and then just do the read / write operations here.
  13. Steve Wilson (SWilson) Jan 11 96 - Added Server handle functionality to Get & setprinterdata
  14. and pretty much changed everything in the process.
  15. Steve Wilson (SWilson) May 31 96 - Added SplEnumPrinterData and SplDeletePrinterData
  16. Steve Wilson (SWilson) Dec 96 - Added SetPrinterDataEx, GetPrinterDataEx, EnumPrinterDataEx,
  17. EnumPrinterKey, DeletePrinterDataEx, and DeleteKey
  18. --*/
  19. #include <precomp.h>
  20. #pragma hdrstop
  21. #include "clusspl.h"
  22. #include "filepool.hxx"
  23. #include <lmcons.h>
  24. #include <lmwksta.h>
  25. #include <lmerr.h>
  26. #include <lmapibuf.h>
  27. #define SECURITY_WIN32
  28. #include <security.h>
  29. #define OPEN_PORT_TIMEOUT_VALUE 3000 // 3 seconds
  30. #define DELETE_PRINTER_DATA 0
  31. #define SET_PRINTER_DATA 1
  32. #define DELETE_PRINTER_KEY 2
  33. extern DWORD dwMajorVersion;
  34. extern DWORD dwMinorVersion;
  35. extern BOOL gbRemoteFax;
  36. extern HANDLE ghDsUpdateThread;
  37. extern DWORD gdwDsUpdateThreadId;
  38. DWORD
  39. SetPrinterDataPrinter(
  40. HANDLE hPrinter,
  41. HKEY hParentKey,
  42. HKEY hKey,
  43. LPWSTR pValueName,
  44. DWORD Type,
  45. LPBYTE pData,
  46. DWORD cbData,
  47. DWORD bSet
  48. );
  49. typedef enum {
  50. REG_PRINT,
  51. REG_PRINTERS,
  52. REG_PROVIDERS
  53. } REG_PRINT_KEY;
  54. DWORD
  55. GetServerKeyHandle(
  56. PINISPOOLER pIniSpooler,
  57. REG_PRINT_KEY eKey,
  58. HKEY *hPrintKey,
  59. PINISPOOLER* ppIniSpoolerOut
  60. );
  61. DWORD
  62. CloseServerKeyHandle(
  63. REG_PRINT_KEY eKey,
  64. HKEY hPrintKey,
  65. PINISPOOLER pIniSpooler
  66. );
  67. DWORD
  68. NonRegDsPresent(
  69. PINISPOOLER pIniSpooler,
  70. LPDWORD pType,
  71. LPBYTE pData,
  72. DWORD nSize,
  73. LPDWORD pcbNeeded
  74. );
  75. DWORD
  76. NonRegDsPresentForUser(
  77. PINISPOOLER pIniSpooler,
  78. LPDWORD pType,
  79. LPBYTE pData,
  80. DWORD nSize,
  81. LPDWORD pcbNeeded
  82. );
  83. DWORD
  84. NonRegGetDNSMachineName(
  85. PINISPOOLER pIniSpooler,
  86. LPDWORD pType,
  87. LPBYTE pData,
  88. DWORD nSize,
  89. LPDWORD pcbNeeded
  90. );
  91. DWORD
  92. PrinterNonRegGetDefaultSpoolDirectory(
  93. PSPOOL pSpool,
  94. LPDWORD pType,
  95. LPBYTE pData,
  96. DWORD nSize,
  97. LPDWORD pcbNeeded
  98. );
  99. DWORD
  100. PrinterNonRegGetChangeId(
  101. PSPOOL pSpool,
  102. LPDWORD pType,
  103. LPBYTE pData,
  104. DWORD nSize,
  105. LPDWORD pcbNeeded
  106. );
  107. DWORD
  108. RegSetDefaultSpoolDirectory(
  109. LPWSTR pValueName,
  110. DWORD dwType,
  111. LPBYTE pData,
  112. DWORD cbData,
  113. HKEY hKey,
  114. PINISPOOLER pIniSpooler
  115. );
  116. DWORD
  117. RegSetPortThreadPriority(
  118. LPWSTR pValueName,
  119. DWORD dwType,
  120. LPBYTE pData,
  121. DWORD cbData,
  122. HKEY hKey,
  123. PINISPOOLER pIniSpooler
  124. );
  125. DWORD
  126. RegSetSchedulerThreadPriority(
  127. LPWSTR pValueName,
  128. DWORD dwType,
  129. LPBYTE pData,
  130. DWORD cbData,
  131. HKEY hKey,
  132. PINISPOOLER pIniSpooler
  133. );
  134. DWORD
  135. RegSetNoRemoteDriver(
  136. LPWSTR pValueName,
  137. DWORD dwType,
  138. LPBYTE pData,
  139. DWORD cbData,
  140. HKEY hKey,
  141. PINISPOOLER pIniSpooler
  142. );
  143. DWORD
  144. RegSetNetPopupToComputer(
  145. LPWSTR pValueName,
  146. DWORD dwType,
  147. LPBYTE pData,
  148. DWORD cbData,
  149. HKEY hKey,
  150. PINISPOOLER pIniSpooler
  151. );
  152. DWORD
  153. RegSetRestartJobOnPoolError(
  154. LPWSTR pValueName,
  155. DWORD dwType,
  156. LPBYTE pData,
  157. DWORD cbData,
  158. HKEY hKey,
  159. PINISPOOLER pIniSpooler
  160. );
  161. DWORD
  162. RegSetRestartJobOnPoolEnabled(
  163. LPWSTR pValueName,
  164. DWORD dwType,
  165. LPBYTE pData,
  166. DWORD cbData,
  167. HKEY hKey,
  168. PINISPOOLER pIniSpooler
  169. );
  170. DWORD
  171. RegSetBeepEnabled(
  172. LPWSTR pValueName,
  173. DWORD dwType,
  174. LPBYTE pData,
  175. DWORD cbData,
  176. HKEY hKey,
  177. PINISPOOLER pIniSpooler
  178. );
  179. DWORD
  180. RegSetEventLog(
  181. LPWSTR pValueName,
  182. DWORD dwType,
  183. LPBYTE pData,
  184. DWORD cbData,
  185. HKEY hKey,
  186. PINISPOOLER pIniSpooler
  187. );
  188. DWORD
  189. RegSetNetPopup(
  190. LPWSTR pValueName,
  191. DWORD dwType,
  192. LPBYTE pData,
  193. DWORD cbData,
  194. HKEY hKey,
  195. PINISPOOLER pIniSpooler
  196. );
  197. DWORD
  198. RegSetRetryPopup(
  199. LPWSTR pValueName,
  200. DWORD dwType,
  201. LPBYTE pData,
  202. DWORD cbData,
  203. HKEY hKey,
  204. PINISPOOLER pIniSpooler
  205. );
  206. DWORD dwDefaultServerThreadPriority = DEFAULT_SERVER_THREAD_PRIORITY;
  207. DWORD dwDefaultSchedulerThreadPriority = DEFAULT_SCHEDULER_THREAD_PRIORITY;
  208. OSVERSIONINFO OsVersionInfo;
  209. OSVERSIONINFOEX OsVersionInfoEx;
  210. typedef struct {
  211. LPWSTR pValue;
  212. BOOL (*pSet) ( LPWSTR pValueName,
  213. DWORD dwType,
  214. LPBYTE pData,
  215. DWORD cbData,
  216. HKEY *hKey,
  217. PINISPOOLER pIniSpooler
  218. );
  219. REG_PRINT_KEY eKey;
  220. } SERVER_DATA, *PSERVER_DATA;
  221. typedef struct {
  222. LPWSTR pValue;
  223. LPBYTE pData;
  224. DWORD dwType;
  225. DWORD dwSize;
  226. } NON_REGISTRY_DATA, *PNON_REGISTRY_DATA;
  227. typedef struct {
  228. PWSTR pValue;
  229. DWORD (*pGet)( PINISPOOLER pIniSpooler,
  230. LPDWORD pType,
  231. LPBYTE pData,
  232. DWORD nSize,
  233. LPDWORD pcbNeeded
  234. );
  235. } NON_REGISTRY_FCN, *PNON_REGISTRY_FCN;
  236. typedef struct {
  237. PWSTR pValue;
  238. DWORD (*pGet)( PSPOOL pSpool,
  239. LPDWORD pType,
  240. LPBYTE pData,
  241. DWORD nSize,
  242. LPDWORD pcbNeeded
  243. );
  244. } PRINTER_NON_REGISTRY_FCN, *PPRINTER_NON_REGISTRY_FCN;
  245. SERVER_DATA gpServerRegistry[] = {{SPLREG_DEFAULT_SPOOL_DIRECTORY, RegSetDefaultSpoolDirectory, REG_PRINTERS},
  246. {SPLREG_PORT_THREAD_PRIORITY, RegSetPortThreadPriority, REG_PRINT},
  247. {SPLREG_SCHEDULER_THREAD_PRIORITY, RegSetSchedulerThreadPriority, REG_PRINT},
  248. {SPLREG_BEEP_ENABLED, RegSetBeepEnabled, REG_PRINT},
  249. {SPLREG_NET_POPUP, RegSetNetPopup, REG_PROVIDERS},
  250. {SPLREG_RETRY_POPUP, RegSetRetryPopup, REG_PROVIDERS},
  251. {SPLREG_EVENT_LOG, RegSetEventLog, REG_PROVIDERS},
  252. {SPLREG_NO_REMOTE_PRINTER_DRIVERS, RegSetNoRemoteDriver, REG_PRINT},
  253. {SPLREG_NET_POPUP_TO_COMPUTER, RegSetNetPopupToComputer, REG_PROVIDERS},
  254. {SPLREG_RESTART_JOB_ON_POOL_ERROR, RegSetRestartJobOnPoolError, REG_PROVIDERS},
  255. {SPLREG_RESTART_JOB_ON_POOL_ENABLED, RegSetRestartJobOnPoolEnabled, REG_PROVIDERS},
  256. {0,0,0}};
  257. NON_REGISTRY_DATA gpNonRegistryData[] = {{SPLREG_PORT_THREAD_PRIORITY_DEFAULT, (LPBYTE)&dwDefaultServerThreadPriority, REG_DWORD, sizeof(DWORD)},
  258. {SPLREG_SCHEDULER_THREAD_PRIORITY_DEFAULT, (LPBYTE)&dwDefaultSchedulerThreadPriority, REG_DWORD, sizeof(DWORD)},
  259. {SPLREG_ARCHITECTURE, (LPBYTE)&LOCAL_ENVIRONMENT, REG_SZ, 0},
  260. {SPLREG_MAJOR_VERSION, (LPBYTE)&dwMajorVersion, REG_DWORD, sizeof(DWORD)},
  261. {SPLREG_MINOR_VERSION, (LPBYTE)&dwMinorVersion, REG_DWORD, sizeof(DWORD)},
  262. {SPLREG_W3SVCINSTALLED, (LPBYTE)&fW3SvcInstalled, REG_DWORD, sizeof(DWORD)},
  263. {SPLREG_OS_VERSION, (LPBYTE)&OsVersionInfo, REG_BINARY, sizeof(OsVersionInfo)},
  264. {SPLREG_OS_VERSIONEX, (LPBYTE)&OsVersionInfoEx, REG_BINARY, sizeof(OsVersionInfoEx)},
  265. {SPLREG_REMOTE_FAX, (LPBYTE)&gbRemoteFax, REG_BINARY, sizeof(gbRemoteFax)},
  266. {0,0,0,0}};
  267. NON_REGISTRY_FCN gpNonRegistryFcn[] = { {SPLREG_DS_PRESENT, NonRegDsPresent},
  268. {SPLREG_DS_PRESENT_FOR_USER, NonRegDsPresentForUser},
  269. {SPLREG_DNS_MACHINE_NAME, NonRegGetDNSMachineName},
  270. {0,0}};
  271. PRINTER_NON_REGISTRY_FCN gpPrinterNonRegistryFcn[] =
  272. {
  273. { SPLREG_DEFAULT_SPOOL_DIRECTORY, PrinterNonRegGetDefaultSpoolDirectory },
  274. { SPLREG_CHANGE_ID, PrinterNonRegGetChangeId },
  275. { 0, 0 }
  276. };
  277. extern WCHAR *szPrinterData;
  278. BOOL
  279. AvailableBidiPort(
  280. PINIPORT pIniPort,
  281. PINIMONITOR pIniLangMonitor
  282. )
  283. {
  284. //
  285. // File ports and ports with no monitor are useless
  286. //
  287. if ( (pIniPort->Status & PP_FILE) || !(pIniPort->Status & PP_MONITOR) )
  288. return FALSE;
  289. //
  290. // If no LM then PM should support pfnGetPrinterDataFromPort
  291. //
  292. if ( !pIniLangMonitor &&
  293. !pIniPort->pIniMonitor->Monitor2.pfnGetPrinterDataFromPort )
  294. return FALSE;
  295. //
  296. // A port with no jobs or same monitor is printing then it is ok
  297. //
  298. return !pIniPort->pIniJob ||
  299. pIniLangMonitor == pIniPort->pIniLangMonitor;
  300. }
  301. DWORD
  302. GetPrinterDataFromPort(
  303. PINIPRINTER pIniPrinter,
  304. LPWSTR pszValueName,
  305. LPBYTE pData,
  306. DWORD cbBuf,
  307. LPDWORD pcbNeeded
  308. )
  309. /*++
  310. Routine Description:
  311. Tries to use GetPrinterDataFromPort monitor function to satisfy a
  312. GetPrinterData call
  313. Arguments:
  314. pIniPrinter - Points to an INIPRINTER
  315. Return Value:
  316. Win32 error code
  317. --*/
  318. {
  319. DWORD rc = ERROR_INVALID_PARAMETER;
  320. DWORD i, dwFirstPortWithNoJobs, dwFirstPortHeld;
  321. PINIMONITOR pIniLangMonitor = NULL;
  322. PINIPORT pIniPort;
  323. SplInSem();
  324. //
  325. // Is the printer bidi enabled with the LM supporting
  326. // pfnGetPrinterDataFromPort? (Note: even PM can support this function)
  327. //
  328. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_ENABLE_BIDI ) {
  329. pIniLangMonitor = pIniPrinter->pIniDriver->pIniLangMonitor;
  330. // SPLASSERT(pIniLangMonitor);
  331. if ( pIniLangMonitor &&
  332. !pIniLangMonitor->Monitor2.pfnGetPrinterDataFromPort )
  333. pIniLangMonitor = NULL;
  334. }
  335. //
  336. // Initialize to max
  337. //
  338. dwFirstPortWithNoJobs = dwFirstPortHeld = pIniPrinter->cPorts;
  339. for ( i = 0 ; i < pIniPrinter->cPorts ; ++i ) {
  340. pIniPort = pIniPrinter->ppIniPorts[i];
  341. //
  342. // Skip ports that can't be used
  343. //
  344. if ( !AvailableBidiPort(pIniPort, pIniLangMonitor) )
  345. continue;
  346. //
  347. // Port does not need closing?
  348. //
  349. if ( pIniLangMonitor == pIniPort->pIniLangMonitor ) {
  350. //
  351. // If no jobs also then great let's use it
  352. //
  353. if ( !pIniPort->pIniJob )
  354. goto PortFound;
  355. if ( dwFirstPortHeld == pIniPrinter->cPorts ) {
  356. dwFirstPortHeld = i;
  357. }
  358. } else if ( !pIniPort->pIniJob &&
  359. dwFirstPortWithNoJobs == pIniPrinter->cPorts ) {
  360. dwFirstPortWithNoJobs = i;
  361. }
  362. }
  363. //
  364. // If all ports need closing as well as have jobs let's quit
  365. //
  366. if ( dwFirstPortWithNoJobs == pIniPrinter->cPorts &&
  367. dwFirstPortHeld == pIniPrinter->cPorts ) {
  368. return rc; //Didn't leave CS and did not unset event
  369. }
  370. //
  371. // We will prefer a port with no jobs (even thought it requires closing)
  372. //
  373. if ( dwFirstPortWithNoJobs < pIniPrinter->cPorts )
  374. pIniPort = pIniPrinter->ppIniPorts[dwFirstPortWithNoJobs];
  375. else
  376. pIniPort = pIniPrinter->ppIniPorts[dwFirstPortHeld];
  377. PortFound:
  378. SPLASSERT(AvailableBidiPort(pIniPort, pIniLangMonitor));
  379. INCPORTREF(pIniPort);
  380. LeaveSplSem();
  381. SplOutSem();
  382. //
  383. // By unsetting the event for the duration of the GetPrinterDataFromPort
  384. // we make sure even if a job requiring different monitor got assigned
  385. // to the port it can't open/close the port.
  386. //
  387. // Since GetPrinterDataFromPort is supposed to come back fast it is ok
  388. //
  389. if ( WAIT_OBJECT_0 != WaitForSingleObject(pIniPort->hWaitToOpenOrClose,
  390. OPEN_PORT_TIMEOUT_VALUE) ) {
  391. DBGMSG(DBG_WARNING,
  392. ("GetPrinterDataFromPort: WaitForSingleObject timed-out\n"));
  393. goto CleanupFromOutsideSplSem; //Left CS did not unset the event
  394. }
  395. //
  396. // Port needs to be opened?
  397. //
  398. if ( pIniPort->pIniLangMonitor != pIniLangMonitor ||
  399. !pIniPort->hPort ) {
  400. LPTSTR pszPrinter;
  401. TCHAR szFullPrinter[ MAX_UNC_PRINTER_NAME ];
  402. //
  403. // A job got assigned after we left the CS and before the event
  404. // was reset?
  405. //
  406. if ( pIniPort->pIniJob ) {
  407. SetEvent(pIniPort->hWaitToOpenOrClose);
  408. goto CleanupFromOutsideSplSem; //Outside CS did set event
  409. }
  410. if( pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  411. pszPrinter = szFullPrinter;
  412. wsprintf( szFullPrinter,
  413. L"%ws\\%ws",
  414. pIniPrinter->pIniSpooler->pMachineName,
  415. pIniPrinter->pName );
  416. } else {
  417. pszPrinter = pIniPrinter->pName;
  418. }
  419. EnterSplSem();
  420. if ( !OpenMonitorPort(pIniPort,
  421. &pIniLangMonitor,
  422. pszPrinter,
  423. FALSE) ) {
  424. SetEvent(pIniPort->hWaitToOpenOrClose);
  425. goto Cleanup; //Inside CS but already set the event
  426. }
  427. LeaveSplSem();
  428. }
  429. SplOutSem();
  430. if ( !pIniLangMonitor )
  431. pIniLangMonitor = pIniPort->pIniMonitor;
  432. if ( (*pIniLangMonitor->Monitor2.pfnGetPrinterDataFromPort)(
  433. pIniPort->hPort,
  434. 0,
  435. pszValueName,
  436. NULL,
  437. 0,
  438. (LPWSTR)pData,
  439. cbBuf,
  440. pcbNeeded) ) {
  441. rc = ERROR_SUCCESS;
  442. } else {
  443. //
  444. // If monitor fails the call but did not do a SetLastError()
  445. // we do not want to corrupt the registry
  446. //
  447. if ( (rc = GetLastError()) == ERROR_SUCCESS ) {
  448. ASSERT(rc != ERROR_SUCCESS);
  449. rc = ERROR_INVALID_PARAMETER;
  450. }
  451. }
  452. //
  453. // At this point we do not care if someone tries to open/close the port
  454. // we can set the event before entering the splsem
  455. //
  456. SetEvent(pIniPort->hWaitToOpenOrClose);
  457. CleanupFromOutsideSplSem:
  458. EnterSplSem();
  459. Cleanup:
  460. SplInSem();
  461. DECPORTREF(pIniPort);
  462. return rc;
  463. }
  464. DWORD
  465. SplGetPrintProcCaps(
  466. PSPOOL pSpool,
  467. LPWSTR pDatatype,
  468. LPBYTE pData,
  469. DWORD nSize,
  470. LPDWORD pcbNeeded
  471. )
  472. /*++
  473. Function Description: SplGetPrintProcCaps calls the GetPrintProcCaps function of the
  474. Print processor that supports the given datatype.
  475. Parameters: pSpool -- handle to the printer
  476. pDatatype -- string containing the datatype
  477. pData -- pointer to buffer
  478. nSize -- size of the buffer
  479. pcbNeeded -- pointer to the variable to store the required size of
  480. buffer.
  481. Return Value: Error Code
  482. --*/
  483. {
  484. PINIPRINTPROC pIniPrintProc;
  485. PINIPRINTER pIniPrinter;
  486. DWORD dwAttributes, dwIndex, dwReturn;
  487. // Find the print processor that supports this datatype
  488. pIniPrintProc = pSpool->pIniPrintProc ? pSpool->pIniPrintProc
  489. : pSpool->pIniPrinter->pIniPrintProc;
  490. pIniPrintProc = FindDatatype( pIniPrintProc, pDatatype);
  491. if (!pIniPrintProc)
  492. {
  493. return ERROR_INVALID_DATATYPE;
  494. }
  495. // Get the features supported by that print processor
  496. if (!pIniPrintProc->GetPrintProcCaps)
  497. {
  498. return ERROR_NOT_SUPPORTED;
  499. }
  500. else
  501. {
  502. pIniPrinter = pSpool->pIniPrinter;
  503. dwAttributes = pIniPrinter->Attributes;
  504. // Check for FILE: port which forces RAW spooling
  505. for (dwIndex = 0;
  506. dwIndex < pIniPrinter->cPorts;
  507. ++dwIndex)
  508. {
  509. if (!lstrcmpi(pIniPrinter->ppIniPorts[dwIndex]->pName,
  510. L"FILE:"))
  511. {
  512. // Found a FILE: port
  513. dwAttributes |= PRINTER_ATTRIBUTE_RAW_ONLY;
  514. break;
  515. }
  516. }
  517. // Disable EMF simulated features for version < 3 drivers
  518. if (pIniPrinter->pIniDriver &&
  519. (pIniPrinter->pIniDriver->cVersion < 3))
  520. {
  521. dwAttributes |= PRINTER_ATTRIBUTE_RAW_ONLY;
  522. }
  523. LeaveSplSem();
  524. dwReturn = (*(pIniPrintProc->GetPrintProcCaps))(pDatatype,
  525. dwAttributes,
  526. pData,
  527. nSize,
  528. pcbNeeded);
  529. EnterSplSem();
  530. return dwReturn;
  531. }
  532. }
  533. DWORD
  534. SplGetNonRegData(
  535. PINISPOOLER pIniSpooler,
  536. LPDWORD pType,
  537. LPBYTE pData,
  538. DWORD nSize,
  539. LPDWORD pcbNeeded,
  540. PNON_REGISTRY_DATA pNonRegData
  541. )
  542. {
  543. if ( pNonRegData->dwType == REG_SZ && pNonRegData->dwSize == 0 )
  544. *pcbNeeded = wcslen((LPWSTR) pNonRegData->pData) * sizeof(WCHAR) + sizeof(WCHAR);
  545. else
  546. *pcbNeeded = pNonRegData->dwSize;
  547. if ( *pcbNeeded > nSize )
  548. return ERROR_MORE_DATA;
  549. CopyMemory(pData, (LPBYTE)pNonRegData->pData, *pcbNeeded);
  550. *pType = pNonRegData->dwType;
  551. return ERROR_SUCCESS;
  552. }
  553. DWORD
  554. SplGetPrinterData(
  555. HANDLE hPrinter,
  556. LPWSTR pValueName,
  557. LPDWORD pType,
  558. LPBYTE pData,
  559. DWORD nSize,
  560. LPDWORD pcbNeeded
  561. )
  562. {
  563. PSPOOL pSpool=(PSPOOL)hPrinter;
  564. DWORD rc = ERROR_INVALID_HANDLE;
  565. DWORD dwResult;
  566. PSERVER_DATA pRegistry; // points to table of Print Server registry entries
  567. PNON_REGISTRY_DATA pNonReg;
  568. PNON_REGISTRY_FCN pNonRegFcn;
  569. HKEY hPrintKey;
  570. PINIPRINTER pIniPrinter;
  571. HKEY hKey = NULL;
  572. DWORD dwType;
  573. PINISPOOLER pIniSpoolerOut;
  574. HANDLE hToken = NULL;
  575. WCHAR szPrintProcKey[] = L"PrintProcCaps_";
  576. LPWSTR pDatatype;
  577. if (!ValidateSpoolHandle(pSpool, 0)) {
  578. return rc;
  579. }
  580. if (!pValueName || !pcbNeeded) {
  581. rc = ERROR_INVALID_PARAMETER;
  582. return rc;
  583. }
  584. if (pType)
  585. dwType = *pType; // pType may be NULL
  586. // Server Handle
  587. if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
  588. // Check Registry Table
  589. for (pRegistry = gpServerRegistry ; pRegistry->pValue ; ++pRegistry) {
  590. if (!_wcsicmp(pRegistry->pValue, pValueName)) {
  591. //
  592. // Retrieve the handle for the Get.
  593. if ((rc = GetServerKeyHandle(pSpool->pIniSpooler,
  594. pRegistry->eKey,
  595. &hPrintKey,
  596. &pIniSpoolerOut)) == ERROR_SUCCESS) {
  597. *pcbNeeded = nSize;
  598. rc = SplRegQueryValue(hPrintKey, pValueName, pType, pData, pcbNeeded, pIniSpoolerOut);
  599. CloseServerKeyHandle( pRegistry->eKey,
  600. hPrintKey,
  601. pIniSpoolerOut );
  602. }
  603. break;
  604. }
  605. }
  606. if (!pRegistry->pValue) { // May be a non-registry entry
  607. for (pNonReg = gpNonRegistryData ; pNonReg->pValue ; ++pNonReg) {
  608. if (!_wcsicmp(pNonReg->pValue, pValueName)) {
  609. rc = SplGetNonRegData(pSpool->pIniSpooler,
  610. &dwType,
  611. pData,
  612. nSize,
  613. pcbNeeded,
  614. pNonReg);
  615. if (pType)
  616. *pType = dwType;
  617. goto FinishNonReg;
  618. }
  619. }
  620. for (pNonRegFcn = gpNonRegistryFcn ; pNonRegFcn->pValue ; ++pNonRegFcn) {
  621. if (!_wcsicmp(pNonRegFcn->pValue, pValueName)) {
  622. rc = (*pNonRegFcn->pGet)(pSpool->pIniSpooler, &dwType, pData, nSize, pcbNeeded);
  623. if (pType)
  624. *pType = dwType;
  625. goto FinishNonReg;
  626. }
  627. }
  628. FinishNonReg:
  629. if (!pNonReg->pValue && !pNonRegFcn->pValue) {
  630. rc = ERROR_INVALID_PARAMETER;
  631. }
  632. }
  633. // Printer handle
  634. } else {
  635. PPRINTER_NON_REGISTRY_FCN pPrinterNonRegFcn;
  636. EnterSplSem();
  637. pIniPrinter = pSpool->pIniPrinter;
  638. SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
  639. //
  640. // If the pValueName is "PrintProcCaps_[datatype]" call the print processor which
  641. // supports that datatype and return the options that it supports.
  642. //
  643. if (pValueName == wcsstr(pValueName, szPrintProcKey)) {
  644. pDatatype = (LPWSTR) (pValueName+(wcslen(szPrintProcKey)));
  645. if (!pDatatype) {
  646. LeaveSplSem();
  647. return ERROR_INVALID_DATATYPE;
  648. } else {
  649. rc = SplGetPrintProcCaps(pSpool,
  650. pDatatype,
  651. pData,
  652. nSize,
  653. pcbNeeded);
  654. LeaveSplSem();
  655. return rc;
  656. }
  657. }
  658. //
  659. // Check for PrinterNonReg calls.
  660. //
  661. for (pPrinterNonRegFcn = gpPrinterNonRegistryFcn ;
  662. pPrinterNonRegFcn->pValue ;
  663. ++pPrinterNonRegFcn) {
  664. if (!_wcsicmp(pPrinterNonRegFcn->pValue, pValueName)) {
  665. rc = (*pPrinterNonRegFcn->pGet)( pSpool,
  666. &dwType,
  667. pData,
  668. nSize,
  669. pcbNeeded );
  670. if( pType ){
  671. *pType = dwType;
  672. }
  673. LeaveSplSem();
  674. return rc;
  675. }
  676. }
  677. if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
  678. LeaveSplSem();
  679. rc = ERROR_INVALID_PRINTER_STATE;
  680. } else {
  681. //
  682. // During upgrade do not try to talk to the port since we
  683. // will not be on the net
  684. //
  685. if ( dwUpgradeFlag == 0 &&
  686. AccessGranted(SPOOLER_OBJECT_PRINTER,
  687. PRINTER_ACCESS_ADMINISTER,
  688. pSpool ) ) {
  689. rc = GetPrinterDataFromPort(pIniPrinter,
  690. pValueName,
  691. pData,
  692. nSize,
  693. pcbNeeded);
  694. }
  695. hToken = RevertToPrinterSelf();
  696. dwResult = OpenPrinterKey(pIniPrinter,
  697. KEY_READ | KEY_WRITE,
  698. &hKey,
  699. szPrinterData,
  700. FALSE);
  701. if (hToken)
  702. ImpersonatePrinterClient(hToken);
  703. if (dwResult != ERROR_SUCCESS) {
  704. LeaveSplSem();
  705. return dwResult;
  706. }
  707. if ( rc == ERROR_SUCCESS ) {
  708. *pType = REG_BINARY;
  709. (VOID)SetPrinterDataPrinter(hPrinter,
  710. NULL,
  711. hKey,
  712. pValueName,
  713. *pType,
  714. pData,
  715. *pcbNeeded,
  716. SET_PRINTER_DATA);
  717. } else if ( rc != ERROR_INSUFFICIENT_BUFFER ) {
  718. *pcbNeeded = nSize;
  719. rc = SplRegQueryValue( hKey,
  720. pValueName,
  721. pType,
  722. pData,
  723. pcbNeeded,
  724. pIniPrinter->pIniSpooler );
  725. }
  726. LeaveSplSem();
  727. }
  728. }
  729. if (hKey)
  730. SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
  731. SplOutSem();
  732. return rc;
  733. }
  734. DWORD
  735. SplGetPrinterDataEx(
  736. HANDLE hPrinter,
  737. LPCWSTR pKeyName,
  738. LPCWSTR pValueName,
  739. LPDWORD pType,
  740. LPBYTE pData,
  741. DWORD nSize,
  742. LPDWORD pcbNeeded
  743. )
  744. {
  745. PSPOOL pSpool=(PSPOOL)hPrinter;
  746. DWORD rc = ERROR_INVALID_HANDLE;
  747. PSERVER_DATA pRegistry; // points to table of Print Server registry entries
  748. PINIPRINTER pIniPrinter;
  749. HKEY hKey = NULL;
  750. HANDLE hToken = NULL;
  751. if (!ValidateSpoolHandle(pSpool, 0)) {
  752. goto Cleanup;
  753. }
  754. if (!pValueName || !pcbNeeded) {
  755. rc = ERROR_INVALID_PARAMETER;
  756. goto Cleanup;
  757. }
  758. if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
  759. rc = SplGetPrinterData( hPrinter,
  760. (LPWSTR) pValueName,
  761. pType,
  762. pData,
  763. nSize,
  764. pcbNeeded);
  765. } else {
  766. if (!pKeyName || !*pKeyName) {
  767. rc = ERROR_INVALID_PARAMETER;
  768. goto Cleanup;
  769. }
  770. EnterSplSem();
  771. pIniPrinter = pSpool->pIniPrinter;
  772. INCPRINTERREF(pIniPrinter);
  773. SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
  774. if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
  775. LeaveSplSem();
  776. rc = ERROR_INVALID_PRINTER_STATE;
  777. } else if (!_wcsicmp(pKeyName, szPrinterData)) {
  778. LeaveSplSem();
  779. rc = SplGetPrinterData( hPrinter,
  780. (LPWSTR) pValueName,
  781. pType,
  782. pData,
  783. nSize,
  784. pcbNeeded);
  785. } else {
  786. hToken = RevertToPrinterSelf();
  787. rc = OpenPrinterKey(pIniPrinter, KEY_READ, &hKey, pKeyName, TRUE);
  788. LeaveSplSem();
  789. if (rc == ERROR_SUCCESS) {
  790. *pcbNeeded = nSize;
  791. rc = SplRegQueryValue(hKey,
  792. pValueName,
  793. pType,
  794. pData,
  795. pcbNeeded,
  796. pIniPrinter->pIniSpooler);
  797. }
  798. }
  799. EnterSplSem();
  800. if (hKey)
  801. SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
  802. DECPRINTERREF(pIniPrinter);
  803. LeaveSplSem();
  804. }
  805. Cleanup:
  806. SplOutSem();
  807. if (hToken)
  808. ImpersonatePrinterClient(hToken);
  809. return rc;
  810. }
  811. DWORD
  812. SplEnumPrinterData(
  813. HANDLE hPrinter,
  814. DWORD dwIndex, // index of value to query
  815. LPWSTR pValueName, // address of buffer for value string
  816. DWORD cbValueName, // size of buffer for value string
  817. LPDWORD pcbValueName, // address for size of value buffer
  818. LPDWORD pType, // address of buffer for type code
  819. LPBYTE pData, // address of buffer for value data
  820. DWORD cbData, // size of buffer for value data
  821. LPDWORD pcbData // address for size of data buffer
  822. )
  823. {
  824. PSPOOL pSpool=(PSPOOL)hPrinter;
  825. DWORD rc = ERROR_INVALID_HANDLE;
  826. HKEY hKey = NULL;
  827. PINIPRINTER pIniPrinter;
  828. HANDLE hToken = NULL;
  829. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
  830. return rc;
  831. }
  832. if (!pValueName || !pcbValueName) {
  833. rc = ERROR_INVALID_PARAMETER;
  834. return rc;
  835. }
  836. EnterSplSem();
  837. pIniPrinter = pSpool->pIniPrinter;
  838. SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
  839. if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
  840. LeaveSplSem();
  841. rc = ERROR_INVALID_PRINTER_STATE;
  842. } else {
  843. hToken = RevertToPrinterSelf();
  844. rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_READ, &hKey, szPrinterData, TRUE);
  845. if (hToken)
  846. ImpersonatePrinterClient(hToken);
  847. LeaveSplSem();
  848. if (rc == ERROR_SUCCESS) {
  849. if (!cbValueName && !cbData) { // Both sizes are NULL, so user wants to get buffer sizes
  850. rc = SplRegQueryInfoKey( hKey,
  851. NULL,
  852. NULL,
  853. NULL,
  854. pcbValueName,
  855. pcbData,
  856. NULL,
  857. NULL,
  858. pIniPrinter->pIniSpooler );
  859. } else {
  860. *pcbValueName = cbValueName/sizeof(WCHAR);
  861. *pcbData = cbData;
  862. rc = SplRegEnumValue( hKey,
  863. dwIndex,
  864. pValueName,
  865. pcbValueName,
  866. pType,
  867. pData,
  868. pcbData,
  869. pIniPrinter->pIniSpooler );
  870. *pcbValueName = (*pcbValueName + 1)*sizeof(WCHAR);
  871. }
  872. SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
  873. }
  874. }
  875. return rc;
  876. }
  877. DWORD
  878. SplEnumPrinterDataEx(
  879. HANDLE hPrinter,
  880. LPCWSTR pKeyName, // key name
  881. LPBYTE pEnumValueStart,
  882. DWORD cbEnumValues,
  883. LPDWORD pcbEnumValues,
  884. LPDWORD pnEnumValues // number of values returned
  885. )
  886. {
  887. PSPOOL pSpool=(PSPOOL)hPrinter;
  888. BOOL bRet = FALSE;
  889. DWORD rc = ERROR_SUCCESS;
  890. PINIPRINTER pIniPrinter;
  891. HKEY hKey = NULL;
  892. DWORD i;
  893. LPWSTR pNextValueName, pValueName = NULL;
  894. LPBYTE pData = NULL;
  895. PPRINTER_ENUM_VALUES pEnumValue;
  896. DWORD cchValueName, cbData, cchValueNameTemp, cbDataTemp;
  897. DWORD dwType, cbSourceDir=0, cbTargetDir=0;
  898. HANDLE hToken = NULL;
  899. LPWSTR pszSourceDir = NULL, pszTargetDir = NULL;
  900. EnterSplSem();
  901. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
  902. LeaveSplSem();
  903. return ERROR_INVALID_HANDLE;
  904. }
  905. if (!pKeyName || !*pKeyName) {
  906. LeaveSplSem();
  907. return ERROR_INVALID_PARAMETER;
  908. }
  909. *pcbEnumValues = 0;
  910. *pnEnumValues = 0;
  911. pIniPrinter = pSpool->pIniPrinter;
  912. SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
  913. if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
  914. LeaveSplSem();
  915. rc = ERROR_INVALID_PRINTER_STATE;
  916. goto Cleanup;
  917. }
  918. // open specified key
  919. hToken = RevertToPrinterSelf();
  920. rc = OpenPrinterKey(pIniPrinter, KEY_READ, &hKey, pKeyName, TRUE);
  921. LeaveSplSem();
  922. if (rc != ERROR_SUCCESS) {
  923. goto Cleanup;
  924. }
  925. do {
  926. // Get the max size
  927. rc = SplRegQueryInfoKey( hKey,
  928. NULL,
  929. NULL,
  930. pnEnumValues,
  931. &cchValueName,
  932. &cbData,
  933. NULL,
  934. NULL,
  935. pIniPrinter->pIniSpooler );
  936. if (rc != ERROR_SUCCESS)
  937. goto Cleanup;
  938. cchValueName = (cchValueName + 1);
  939. cbData = (cbData + 1) & ~1;
  940. // Allocate temporary buffers to determine true required size
  941. if (!(pValueName = AllocSplMem(cchValueName * sizeof (WCHAR)))) {
  942. rc = GetLastError();
  943. goto Cleanup;
  944. }
  945. if (!(pData = AllocSplMem(cbData))) {
  946. rc = GetLastError();
  947. goto Cleanup;
  948. }
  949. // Run through Values and accumulate sizes
  950. for (i = 0 ; rc == ERROR_SUCCESS && i < *pnEnumValues ; ++i) {
  951. cchValueNameTemp = cchValueName;
  952. cbDataTemp = cbData;
  953. rc = SplRegEnumValue( hKey,
  954. i,
  955. pValueName,
  956. &cchValueNameTemp,
  957. &dwType,
  958. pData,
  959. &cbDataTemp,
  960. pIniPrinter->pIniSpooler);
  961. *pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
  962. (cchValueNameTemp + 1)*sizeof(WCHAR);
  963. *pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, dwType) +
  964. cbDataTemp;
  965. }
  966. //
  967. // If the key is a sub key of "CopyFiles" we need to generate
  968. // the paths for the source/target directories if the call is remote
  969. //
  970. if ( (pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_DATA) &&
  971. !wcsncmp(pKeyName, L"CopyFiles\\", wcslen(L"CopyFiles\\")) ) {
  972. if ( !GenerateDirectoryNamesForCopyFilesKey(pSpool,
  973. hKey,
  974. &pszSourceDir,
  975. &pszTargetDir,
  976. cchValueName*sizeof (WCHAR)) ) {
  977. rc = GetLastError();
  978. goto Cleanup;
  979. } else {
  980. SPLASSERT(pszSourceDir && pszTargetDir);
  981. if ( pszSourceDir ) {
  982. cbSourceDir = (wcslen(pszSourceDir) + 1)*sizeof(WCHAR);
  983. *pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
  984. sizeof(L"SourceDir") + sizeof(WCHAR);
  985. *pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
  986. cbSourceDir;
  987. (*pnEnumValues)++;
  988. }
  989. if ( pszTargetDir ) {
  990. cbTargetDir = (wcslen(pszTargetDir) + 1)*sizeof(WCHAR);
  991. *pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
  992. sizeof(L"TargetDir") + sizeof(WCHAR);
  993. *pcbEnumValues = (DWORD) AlignToRegType(*pcbEnumValues, REG_SZ) +
  994. cbTargetDir;
  995. (*pnEnumValues)++;
  996. }
  997. }
  998. }
  999. *pcbEnumValues += sizeof(PRINTER_ENUM_VALUES)**pnEnumValues;
  1000. if (rc == ERROR_SUCCESS) {
  1001. if (*pcbEnumValues > cbEnumValues) {
  1002. rc = ERROR_MORE_DATA;
  1003. break;
  1004. } else {
  1005. // Adjust pointers & Get data
  1006. pEnumValue = (PPRINTER_ENUM_VALUES) pEnumValueStart;
  1007. pNextValueName = (LPWSTR) (pEnumValueStart + *pnEnumValues*sizeof(PRINTER_ENUM_VALUES));
  1008. pNextValueName = (LPWSTR) AlignToRegType((ULONG_PTR)pNextValueName, REG_SZ);
  1009. for(i = 0 ; rc == ERROR_SUCCESS && i < *pnEnumValues ; ++i, ++pEnumValue) {
  1010. // bytes left in the allocated buffer
  1011. DWORD cbRemaining = (DWORD)(pEnumValueStart + cbEnumValues - (LPBYTE)pNextValueName);
  1012. pEnumValue->pValueName = pNextValueName;
  1013. // use minimum of cbRemaining and max size
  1014. pEnumValue->cbValueName = (cbRemaining < cchValueName*sizeof (WCHAR))
  1015. ? cbRemaining : cchValueName*sizeof (WCHAR);
  1016. pEnumValue->cbData = cbData;
  1017. if ( i == *pnEnumValues - 2 && cbSourceDir ) {
  1018. pEnumValue->dwType = REG_SZ;
  1019. pEnumValue->cbData = cbSourceDir;
  1020. pEnumValue->cbValueName = sizeof(L"SourceDir") + sizeof(WCHAR);
  1021. pEnumValue->pData = (LPBYTE) pEnumValue->pValueName +
  1022. pEnumValue->cbValueName;
  1023. pEnumValue->pData = (LPBYTE) AlignToRegType((ULONG_PTR)pEnumValue->pData,
  1024. pEnumValue->dwType);
  1025. wcscpy(pEnumValue->pValueName, L"SourceDir");
  1026. wcscpy((LPWSTR)pEnumValue->pData, pszSourceDir);
  1027. } else if ( i == *pnEnumValues - 1 && cbTargetDir ) {
  1028. pEnumValue->dwType = REG_SZ;
  1029. pEnumValue->cbData = cbTargetDir;
  1030. pEnumValue->cbValueName = sizeof(L"TargetDir") +
  1031. sizeof(WCHAR);
  1032. pEnumValue->pData = (LPBYTE) pEnumValue->pValueName +
  1033. pEnumValue->cbValueName;
  1034. pEnumValue->pData = (LPBYTE) AlignToRegType((ULONG_PTR )pEnumValue->pData,
  1035. pEnumValue->dwType);
  1036. wcscpy(pEnumValue->pValueName, L"TargetDir");
  1037. wcscpy((LPWSTR)pEnumValue->pData, pszTargetDir);
  1038. } else {
  1039. DWORD cchValueName = pEnumValue->cbValueName / sizeof (WCHAR);
  1040. // adjust to count of characters
  1041. rc = SplRegEnumValue(hKey,
  1042. i,
  1043. pEnumValue->pValueName,
  1044. &cchValueName,
  1045. &pEnumValue->dwType,
  1046. pData,
  1047. &pEnumValue->cbData,
  1048. pIniPrinter->pIniSpooler);
  1049. pEnumValue->cbValueName = (cchValueName + 1)*sizeof(WCHAR);
  1050. pEnumValue->pData = (LPBYTE) pEnumValue->pValueName + pEnumValue->cbValueName;
  1051. pEnumValue->pData = (LPBYTE) AlignToRegType((ULONG_PTR)pEnumValue->pData,
  1052. pEnumValue->dwType);
  1053. CopyMemory(pEnumValue->pData, pData, pEnumValue->cbData);
  1054. }
  1055. if (i + 1 < *pnEnumValues) {
  1056. pNextValueName = (LPWSTR) AlignToRegType((ULONG_PTR)(pEnumValue->pData +
  1057. pEnumValue->cbData), REG_SZ);
  1058. }
  1059. if (pEnumValue->cbData == 0) {
  1060. pEnumValue->pData = NULL;
  1061. }
  1062. }
  1063. if (rc == ERROR_NO_MORE_ITEMS)
  1064. rc = ERROR_SUCCESS;
  1065. }
  1066. }
  1067. FreeSplMem(pValueName);
  1068. FreeSplMem(pData);
  1069. pValueName = (LPWSTR) pData = NULL;
  1070. } while(rc == ERROR_MORE_DATA);
  1071. if ( rc == ERROR_SUCCESS )
  1072. bRet = TRUE;
  1073. Cleanup:
  1074. SplOutSem();
  1075. FreeSplStr(pszTargetDir);
  1076. FreeSplStr(pszSourceDir);
  1077. FreeSplMem(pValueName);
  1078. FreeSplMem(pData);
  1079. // Close handle
  1080. if (hKey)
  1081. SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
  1082. if (hToken)
  1083. ImpersonatePrinterClient(hToken);
  1084. if ( !bRet && rc == ERROR_SUCCESS ) {
  1085. // SPLASSERT(dwLastError == ERROR_SUCCESS); -- after ICM is fixed
  1086. rc = ERROR_INVALID_PARAMETER;
  1087. }
  1088. return rc;
  1089. }
  1090. DWORD
  1091. SplEnumPrinterKey(
  1092. HANDLE hPrinter,
  1093. LPCWSTR pKeyName, // key name
  1094. LPWSTR pSubKey, // address of buffer for value string
  1095. DWORD cbSubKey, // size of buffer for value string
  1096. LPDWORD pcbSubKey // address for size of value buffer
  1097. )
  1098. {
  1099. HKEY hKey = NULL;
  1100. PSPOOL pSpool=(PSPOOL)hPrinter;
  1101. DWORD rc = ERROR_SUCCESS;
  1102. PINIPRINTER pIniPrinter;
  1103. PINISPOOLER pIniSpooler;
  1104. LPWSTR pRootKeyName;
  1105. DWORD cbSubKeyMax;
  1106. DWORD cwSubKeyMax;
  1107. DWORD cwSubKey, cwSubKeyTotal, cbSubKeyTotal, cwSubKeyOutput;
  1108. DWORD dwIndex;
  1109. DWORD nSubKeys;
  1110. LPWSTR pKeys = NULL;
  1111. HANDLE hToken = NULL;
  1112. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
  1113. return ERROR_INVALID_HANDLE;
  1114. }
  1115. if (!pKeyName || !pcbSubKey) {
  1116. return ERROR_INVALID_PARAMETER;
  1117. }
  1118. EnterSplSem();
  1119. pIniPrinter = pSpool->pIniPrinter;
  1120. SPLASSERT(pIniPrinter && pIniPrinter->signature == IP_SIGNATURE);
  1121. if (pIniPrinter->Status & PRINTER_PENDING_CREATION) {
  1122. LeaveSplSem();
  1123. rc = ERROR_INVALID_PRINTER_STATE;
  1124. goto Cleanup;
  1125. }
  1126. // open specified key
  1127. hToken = RevertToPrinterSelf();
  1128. rc = OpenPrinterKey(pIniPrinter, KEY_READ, &hKey, pKeyName, TRUE);
  1129. LeaveSplSem();
  1130. if (rc != ERROR_SUCCESS)
  1131. goto Cleanup;
  1132. do {
  1133. // Get the max size
  1134. rc = SplRegQueryInfoKey( hKey, // Key
  1135. &nSubKeys, // lpcSubKeys
  1136. &cwSubKeyMax, // lpcbMaxSubKeyLen
  1137. NULL,
  1138. NULL,
  1139. NULL,
  1140. NULL,
  1141. NULL,
  1142. pIniPrinter->pIniSpooler );
  1143. if (rc != ERROR_SUCCESS)
  1144. goto Cleanup;
  1145. ++cwSubKeyMax; // Add terminating NULL
  1146. cbSubKeyMax = (cwSubKeyMax + 1)*sizeof(WCHAR);
  1147. if (!(pKeys = AllocSplMem(cbSubKeyMax))) {
  1148. rc = GetLastError();
  1149. goto Cleanup;
  1150. }
  1151. // Enumerate keys to get exact size
  1152. for(dwIndex = cwSubKeyTotal = 0 ; dwIndex < nSubKeys && rc == ERROR_SUCCESS ; ++dwIndex) {
  1153. cwSubKey = cwSubKeyMax;
  1154. rc = SplRegEnumKey( hKey,
  1155. dwIndex,
  1156. pKeys,
  1157. &cwSubKey,
  1158. NULL,
  1159. pIniPrinter->pIniSpooler );
  1160. cwSubKeyTotal += cwSubKey + 1;
  1161. }
  1162. //
  1163. // cwSubKeyTotal is being reset in the initialization list of the foor loop. Thus
  1164. // its value is not accurate if we do not enter the loop at all (when nSubKeys is 0)
  1165. //
  1166. *pcbSubKey = nSubKeys ? cwSubKeyTotal*sizeof(WCHAR) + sizeof(WCHAR) : 2*sizeof(WCHAR);
  1167. if (rc == ERROR_SUCCESS) {
  1168. if(*pcbSubKey > cbSubKey) {
  1169. rc = ERROR_MORE_DATA;
  1170. break;
  1171. } else {
  1172. //
  1173. // cwSubKeyOutput is the size of the output buffer in wchar
  1174. //
  1175. cwSubKeyOutput = cbSubKey/sizeof(WCHAR);
  1176. for(dwIndex = cwSubKeyTotal = 0 ; dwIndex < nSubKeys && rc == ERROR_SUCCESS ; ++dwIndex) {
  1177. //
  1178. // Calculate the remaining output buffer size in characters.
  1179. // If we're out of room, exit with ERROR_MORE_DATA.
  1180. // This is needed since it is possible the registry has changed.
  1181. //
  1182. if (cwSubKeyOutput < cwSubKeyTotal + 1) {
  1183. rc = ERROR_MORE_DATA;
  1184. break;
  1185. }
  1186. cwSubKey = cwSubKeyOutput - cwSubKeyTotal;
  1187. rc = SplRegEnumKey( hKey,
  1188. dwIndex,
  1189. pSubKey + cwSubKeyTotal,
  1190. &cwSubKey,
  1191. NULL,
  1192. pIniPrinter->pIniSpooler );
  1193. cwSubKeyTotal += cwSubKey + 1;
  1194. }
  1195. //
  1196. // cwSubKeyTotal is being reset in the initialization list of the foor loop. Thus
  1197. // its value is not accurate if we do not enter the loop at all (when nSubKeys is 0)
  1198. // If we don't enter the for loop, then we don't need to update *pcbSubKey
  1199. //
  1200. if (nSubKeys && (dwIndex == nSubKeys || rc == ERROR_NO_MORE_ITEMS)) {
  1201. //
  1202. // Get the most recent data size just in case something changed
  1203. //
  1204. *pcbSubKey = cwSubKeyTotal*sizeof(WCHAR) + sizeof(WCHAR);
  1205. rc = ERROR_SUCCESS;
  1206. }
  1207. }
  1208. }
  1209. FreeSplMem(pKeys);
  1210. pKeys = NULL;
  1211. } while(rc == ERROR_MORE_DATA);
  1212. Cleanup:
  1213. // Close handles
  1214. if (hKey)
  1215. SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
  1216. FreeSplMem(pKeys);
  1217. if (hToken)
  1218. ImpersonatePrinterClient(hToken);
  1219. return rc;
  1220. }
  1221. DWORD
  1222. SplDeletePrinterData(
  1223. HANDLE hPrinter,
  1224. LPWSTR pValueName
  1225. )
  1226. {
  1227. PSPOOL pSpool = (PSPOOL)hPrinter;
  1228. DWORD rc = ERROR_INVALID_HANDLE;
  1229. HKEY hKey = NULL;
  1230. HANDLE hToken = NULL;
  1231. EnterSplSem();
  1232. if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
  1233. hToken = RevertToPrinterSelf();
  1234. rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_WRITE, &hKey, szPrinterData, FALSE);
  1235. if (hToken)
  1236. ImpersonatePrinterClient(hToken);
  1237. if (rc == ERROR_SUCCESS) {
  1238. rc = SetPrinterDataPrinter( hPrinter,
  1239. NULL,
  1240. hKey,
  1241. pValueName,
  1242. 0, NULL, 0, DELETE_PRINTER_DATA);
  1243. SplRegCloseKey(hKey, pSpool->pIniPrinter->pIniSpooler);
  1244. }
  1245. }
  1246. LeaveSplSem();
  1247. return rc;
  1248. }
  1249. DWORD
  1250. SplDeletePrinterDataEx(
  1251. HANDLE hPrinter,
  1252. LPCWSTR pKeyName,
  1253. LPCWSTR pValueName
  1254. )
  1255. {
  1256. PSPOOL pSpool = (PSPOOL)hPrinter;
  1257. DWORD rc = ERROR_INVALID_HANDLE;
  1258. HANDLE hToken = NULL;
  1259. HKEY hKey = NULL;
  1260. if (!pKeyName || !*pKeyName) {
  1261. return ERROR_INVALID_PARAMETER;
  1262. }
  1263. EnterSplSem();
  1264. if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
  1265. hToken = RevertToPrinterSelf();
  1266. rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_WRITE, &hKey, pKeyName, TRUE);
  1267. if (hToken)
  1268. ImpersonatePrinterClient(hToken);
  1269. if (rc == ERROR_SUCCESS)
  1270. rc = SetPrinterDataPrinter(hPrinter,
  1271. NULL,
  1272. hKey,
  1273. (LPWSTR) pValueName,
  1274. 0, NULL, 0, DELETE_PRINTER_DATA);
  1275. }
  1276. LeaveSplSem();
  1277. if (hKey)
  1278. SplRegCloseKey(hKey, pSpool->pIniSpooler);
  1279. return rc;
  1280. }
  1281. DWORD
  1282. SplDeletePrinterKey(
  1283. HANDLE hPrinter,
  1284. LPCWSTR pKeyName
  1285. )
  1286. {
  1287. PSPOOL pSpool = (PSPOOL)hPrinter;
  1288. DWORD rc = ERROR_INVALID_HANDLE;
  1289. HANDLE hToken = NULL;
  1290. HKEY hKey = NULL, hPrinterKey = NULL;
  1291. if (!pKeyName)
  1292. return ERROR_INVALID_PARAMETER;
  1293. EnterSplSem();
  1294. if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
  1295. hToken = RevertToPrinterSelf();
  1296. rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_WRITE | KEY_READ, &hKey, pKeyName, TRUE);
  1297. if (rc == ERROR_SUCCESS)
  1298. rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_WRITE | KEY_READ, &hPrinterKey, NULL, TRUE);
  1299. if (hToken)
  1300. ImpersonatePrinterClient(hToken);
  1301. if (rc == ERROR_SUCCESS) {
  1302. rc = SetPrinterDataPrinter(hPrinter,
  1303. hPrinterKey,
  1304. hKey,
  1305. (LPWSTR) pKeyName,
  1306. 0, NULL, 0, DELETE_PRINTER_KEY);
  1307. }
  1308. }
  1309. LeaveSplSem();
  1310. if (hPrinterKey)
  1311. SplRegCloseKey(hPrinterKey, pSpool->pIniSpooler);
  1312. return rc;
  1313. }
  1314. DWORD
  1315. SplSetPrinterData(
  1316. HANDLE hPrinter,
  1317. LPWSTR pValueName,
  1318. DWORD Type,
  1319. LPBYTE pData,
  1320. DWORD cbData
  1321. )
  1322. {
  1323. PSPOOL pSpool = (PSPOOL)hPrinter;
  1324. DWORD rc = ERROR_INVALID_HANDLE;
  1325. HANDLE hToken = NULL;
  1326. HKEY hKey = NULL;
  1327. EnterSplSem();
  1328. if (!ValidateSpoolHandle(pSpool, 0)) {
  1329. LeaveSplSem();
  1330. return rc;
  1331. }
  1332. if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
  1333. if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
  1334. SERVER_ACCESS_ADMINISTER,
  1335. NULL, NULL, pSpool->pIniSpooler)) {
  1336. rc = ERROR_ACCESS_DENIED;
  1337. } else {
  1338. rc = SetPrinterDataServer(pSpool->pIniSpooler, pValueName, Type, pData, cbData);
  1339. }
  1340. } else {
  1341. hToken = RevertToPrinterSelf();
  1342. rc = OpenPrinterKey(pSpool->pIniPrinter, KEY_READ | KEY_WRITE, &hKey, szPrinterData, FALSE);
  1343. if (hToken)
  1344. ImpersonatePrinterClient(hToken);
  1345. if (rc == ERROR_SUCCESS) {
  1346. rc = SetPrinterDataPrinter( hPrinter,
  1347. NULL,
  1348. hKey,
  1349. pValueName,
  1350. Type, pData, cbData, SET_PRINTER_DATA);
  1351. SplRegCloseKey(hKey, pSpool->pIniPrinter->pIniSpooler);
  1352. }
  1353. }
  1354. LeaveSplSem();
  1355. return rc;
  1356. }
  1357. DWORD
  1358. SplSetPrinterDataEx(
  1359. HANDLE hPrinter,
  1360. LPCWSTR pKeyName,
  1361. LPCWSTR pValueName,
  1362. DWORD Type,
  1363. LPBYTE pData,
  1364. DWORD cbData
  1365. )
  1366. {
  1367. PSPOOL pSpool = (PSPOOL)hPrinter;
  1368. DWORD rc = ERROR_INVALID_HANDLE;
  1369. HANDLE hToken = NULL;
  1370. PINIPRINTER pIniPrinter;
  1371. PINIJOB pIniJob;
  1372. HKEY hKey = NULL;
  1373. PINISPOOLER pIniSpooler;
  1374. LPWSTR pPrinterKeyName;
  1375. DWORD DsUpdate = 0;
  1376. if (!ValidateSpoolHandle(pSpool, 0)){
  1377. goto Done;
  1378. }
  1379. if (!pValueName) {
  1380. rc = ERROR_INVALID_PARAMETER;
  1381. goto Done;
  1382. }
  1383. if (pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) {
  1384. return SplSetPrinterData(hPrinter, (LPWSTR) pValueName, Type, pData, cbData);
  1385. }
  1386. if (!pKeyName || !*pKeyName) {
  1387. rc = ERROR_INVALID_PARAMETER;
  1388. goto Done;
  1389. }
  1390. if (!_wcsicmp(szPrinterData, pKeyName)) {
  1391. return SplSetPrinterData(hPrinter, (LPWSTR) pValueName, Type, pData, cbData);
  1392. }
  1393. EnterSplSem();
  1394. pIniPrinter = pSpool->pIniPrinter;
  1395. pIniSpooler = pIniPrinter->pIniSpooler;
  1396. DBGMSG( DBG_EXEC, ("SetPrinterDataEx: %ws %ws %ws %d cbSize=cbData\n",
  1397. pIniPrinter->pName,
  1398. pKeyName,
  1399. pValueName,
  1400. Type,
  1401. cbData ));
  1402. SPLASSERT(pIniPrinter &&
  1403. pIniPrinter->signature == IP_SIGNATURE);
  1404. if ( !AccessGranted( SPOOLER_OBJECT_PRINTER,
  1405. PRINTER_ACCESS_ADMINISTER,
  1406. pSpool ) ) {
  1407. rc = ERROR_ACCESS_DENIED;
  1408. goto DoneFromSplSem;
  1409. }
  1410. hToken = RevertToPrinterSelf();
  1411. // If this is a DS Key then parse out OID, if any, and write to Registry
  1412. // Also check that data type is correct
  1413. if (!wcscmp(pKeyName, SPLDS_SPOOLER_KEY)){
  1414. DsUpdate = DS_KEY_SPOOLER;
  1415. } else if (!wcscmp(pKeyName, SPLDS_DRIVER_KEY)){
  1416. DsUpdate = DS_KEY_DRIVER;
  1417. } else if (!wcscmp(pKeyName, SPLDS_USER_KEY)){
  1418. DsUpdate = DS_KEY_USER;
  1419. }
  1420. if (DsUpdate) {
  1421. if (Type != REG_SZ && Type != REG_MULTI_SZ && Type != REG_DWORD && !(Type == REG_BINARY && cbData == 1)) {
  1422. rc = ERROR_INVALID_PARAMETER;
  1423. goto DoneFromSplSem;
  1424. }
  1425. }
  1426. // Open or Create the key
  1427. // Create the hPrinterKey if it doesn't exist
  1428. rc = OpenPrinterKey(pIniPrinter,
  1429. KEY_READ | KEY_WRITE,
  1430. &hKey,
  1431. pKeyName,
  1432. FALSE);
  1433. if (rc != ERROR_SUCCESS)
  1434. goto DoneFromSplSem;
  1435. // Set the value
  1436. rc = SplRegSetValue(hKey,
  1437. pValueName,
  1438. Type,
  1439. pData,
  1440. cbData,
  1441. pIniPrinter->pIniSpooler );
  1442. if (rc != ERROR_SUCCESS)
  1443. goto DoneFromSplSem;
  1444. //
  1445. // Set Data succeeded. If the color profiles assocaiated with the
  1446. // print queue were updated we send a notification. TS listens for it
  1447. // and saves print queues settings. Updating color profiles implies
  1448. // touching 4 regitry keys. We want to send the notify only after the
  1449. // last key is updated.
  1450. //
  1451. if (!_wcsicmp(pKeyName, L"CopyFiles\\ICM") &&
  1452. !_wcsicmp(pValueName, L"Module"))
  1453. {
  1454. UpdatePrinterIni(pIniPrinter, CHANGEID_ONLY);
  1455. SetPrinterChange(pIniPrinter,
  1456. NULL,
  1457. NULL,
  1458. PRINTER_CHANGE_SET_PRINTER_DRIVER,
  1459. pSpool->pIniSpooler );
  1460. }
  1461. if (hToken) {
  1462. ImpersonatePrinterClient(hToken);
  1463. hToken = NULL;
  1464. }
  1465. if (ghDsUpdateThread && gdwDsUpdateThreadId == GetCurrentThreadId()) {
  1466. // We are in the background thread
  1467. pIniPrinter->DsKeyUpdate |= DsUpdate;
  1468. } else {
  1469. pIniPrinter->DsKeyUpdateForeground |= DsUpdate;
  1470. }
  1471. UpdatePrinterIni(pIniPrinter, UPDATE_DS_ONLY);
  1472. DoneFromSplSem:
  1473. if (hToken) {
  1474. ImpersonatePrinterClient(hToken);
  1475. }
  1476. LeaveSplSem();
  1477. if ( rc == ERROR_SUCCESS &&
  1478. !wcsncmp(pKeyName, L"CopyFiles\\", wcslen(L"CopyFiles\\")) ) {
  1479. (VOID)SplCopyFileEvent(pSpool,
  1480. (LPWSTR)pKeyName,
  1481. COPYFILE_EVENT_SET_PRINTER_DATAEX);
  1482. }
  1483. Done:
  1484. DBGMSG( DBG_EXEC, ("SetPrinterDataEx: return %d\n", rc));
  1485. if (hKey) {
  1486. SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
  1487. }
  1488. return rc;
  1489. }
  1490. // SetPrinterDataServer - also called during initialization
  1491. DWORD
  1492. SetPrinterDataServer(
  1493. PINISPOOLER pIniSpooler,
  1494. LPWSTR pValueName,
  1495. DWORD Type,
  1496. LPBYTE pData,
  1497. DWORD cbData
  1498. )
  1499. {
  1500. LPWSTR pKeyName;
  1501. DWORD rc;
  1502. HANDLE hToken = NULL;
  1503. PINIPRINTER pIniPrinter;
  1504. PINIJOB pIniJob;
  1505. PSERVER_DATA pRegistry; // points to table of Print Server registry entries
  1506. HKEY hKey;
  1507. PINISPOOLER pIniSpoolerOut;
  1508. // Server Handle
  1509. if (!pValueName) {
  1510. rc = ERROR_INVALID_PARAMETER;
  1511. } else {
  1512. for (pRegistry = gpServerRegistry ; pRegistry->pValue ; ++pRegistry) {
  1513. if (!_wcsicmp(pRegistry->pValue, pValueName)) {
  1514. if ((rc = GetServerKeyHandle( pIniSpooler,
  1515. pRegistry->eKey,
  1516. &hKey,
  1517. &pIniSpoolerOut)) == ERROR_SUCCESS) {
  1518. hToken = RevertToPrinterSelf();
  1519. if (pRegistry->pSet) {
  1520. rc = (*pRegistry->pSet)(pValueName, Type, pData, cbData, hKey, pIniSpoolerOut);
  1521. }
  1522. else {
  1523. rc = ERROR_INVALID_PARAMETER;
  1524. }
  1525. CloseServerKeyHandle( pRegistry->eKey,
  1526. hKey,
  1527. pIniSpoolerOut );
  1528. if (hToken)
  1529. ImpersonatePrinterClient(hToken);
  1530. }
  1531. break;
  1532. }
  1533. }
  1534. if (!pRegistry->pValue) {
  1535. rc = ERROR_INVALID_PARAMETER;
  1536. }
  1537. }
  1538. return rc;
  1539. }
  1540. DWORD
  1541. SetPrinterDataPrinter(
  1542. HANDLE hPrinter,
  1543. HKEY hParentKey,
  1544. HKEY hKey,
  1545. LPWSTR pValueName,
  1546. DWORD Type,
  1547. LPBYTE pData,
  1548. DWORD cbData,
  1549. DWORD dwSet // SET_PRINTER_DATA, DELETE_PRINTER_DATA, or DELETE_PRINTER_KEY
  1550. )
  1551. {
  1552. PSPOOL pSpool = (PSPOOL)hPrinter;
  1553. LPWSTR pKeyName;
  1554. DWORD rc = ERROR_INVALID_HANDLE;
  1555. HANDLE hToken = NULL;
  1556. PINIPRINTER pIniPrinter;
  1557. PINIJOB pIniJob;
  1558. SplInSem();
  1559. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )){
  1560. goto Done;
  1561. }
  1562. pIniPrinter = pSpool->pIniPrinter;
  1563. SPLASSERT(pIniPrinter &&
  1564. pIniPrinter->signature == IP_SIGNATURE && hKey);
  1565. if ( !AccessGranted( SPOOLER_OBJECT_PRINTER,
  1566. PRINTER_ACCESS_ADMINISTER,
  1567. pSpool ) ) {
  1568. rc = ERROR_ACCESS_DENIED;
  1569. goto Done;
  1570. }
  1571. hToken = RevertToPrinterSelf();
  1572. if (dwSet == SET_PRINTER_DATA) {
  1573. rc = SplRegSetValue(hKey,
  1574. pValueName,
  1575. Type,
  1576. pData,
  1577. cbData,
  1578. pIniPrinter->pIniSpooler );
  1579. } else if (dwSet == DELETE_PRINTER_DATA) {
  1580. rc = SplRegDeleteValue(hKey, pValueName, pIniPrinter->pIniSpooler );
  1581. } else if (dwSet == DELETE_PRINTER_KEY) {
  1582. rc = SplDeleteThisKey(hParentKey,
  1583. hKey,
  1584. pValueName,
  1585. FALSE,
  1586. pIniPrinter->pIniSpooler);
  1587. }
  1588. if (hToken)
  1589. ImpersonatePrinterClient(hToken);
  1590. if ( rc == ERROR_SUCCESS ) {
  1591. UpdatePrinterIni(pIniPrinter, CHANGEID_ONLY);
  1592. SetPrinterChange(pIniPrinter,
  1593. NULL,
  1594. NULL,
  1595. PRINTER_CHANGE_SET_PRINTER_DRIVER,
  1596. pSpool->pIniSpooler );
  1597. }
  1598. //
  1599. // Now if there are any Jobs waiting for these changes because of
  1600. // DevQueryPrint fix them as well
  1601. //
  1602. pIniJob = pIniPrinter->pIniFirstJob;
  1603. while (pIniJob) {
  1604. if (pIniJob->Status & JOB_BLOCKED_DEVQ) {
  1605. pIniJob->Status &= ~JOB_BLOCKED_DEVQ;
  1606. FreeSplStr(pIniJob->pStatus);
  1607. pIniJob->pStatus = NULL;
  1608. SetPrinterChange(pIniJob->pIniPrinter,
  1609. pIniJob,
  1610. NVJobStatusAndString,
  1611. PRINTER_CHANGE_SET_JOB,
  1612. pIniJob->pIniPrinter->pIniSpooler );
  1613. }
  1614. pIniJob = pIniJob->pIniNextJob;
  1615. }
  1616. CHECK_SCHEDULER();
  1617. Done:
  1618. return rc;
  1619. }
  1620. DWORD
  1621. GetServerKeyHandle(
  1622. PINISPOOLER pIniSpooler,
  1623. REG_PRINT_KEY eKey,
  1624. HKEY *phKey,
  1625. PINISPOOLER* ppIniSpoolerOut
  1626. )
  1627. {
  1628. DWORD rc = ERROR_SUCCESS;
  1629. HANDLE hToken;
  1630. *ppIniSpoolerOut = NULL;
  1631. hToken = RevertToPrinterSelf();
  1632. switch (eKey) {
  1633. case REG_PRINT:
  1634. *phKey = pIniSpooler->hckRoot;
  1635. *ppIniSpoolerOut = pIniSpooler;
  1636. break;
  1637. case REG_PRINTERS:
  1638. *phKey = pIniSpooler->hckPrinters;
  1639. *ppIniSpoolerOut = pIniSpooler;
  1640. break;
  1641. case REG_PROVIDERS:
  1642. rc = SplRegCreateKey( pIniSpooler->hckRoot,
  1643. pIniSpooler->pszRegistryProviders,
  1644. 0,
  1645. KEY_ALL_ACCESS,
  1646. NULL,
  1647. phKey,
  1648. NULL,
  1649. pIniSpooler);
  1650. *ppIniSpoolerOut = pIniSpooler;
  1651. break;
  1652. default:
  1653. rc = ERROR_INVALID_PARAMETER;
  1654. break;
  1655. }
  1656. ImpersonatePrinterClient(hToken);
  1657. return rc;
  1658. }
  1659. DWORD
  1660. CloseServerKeyHandle(
  1661. REG_PRINT_KEY eKey,
  1662. HKEY hKey,
  1663. PINISPOOLER pIniSpooler
  1664. )
  1665. {
  1666. DWORD rc = ERROR_SUCCESS;
  1667. HANDLE hToken = NULL;
  1668. hToken = RevertToPrinterSelf();
  1669. switch (eKey) {
  1670. case REG_PRINT:
  1671. break;
  1672. case REG_PRINTERS:
  1673. break;
  1674. case REG_PROVIDERS:
  1675. SplRegCloseKey( hKey, pIniSpooler );
  1676. break;
  1677. default:
  1678. rc = ERROR_INVALID_PARAMETER;
  1679. break;
  1680. }
  1681. if (hToken)
  1682. ImpersonatePrinterClient(hToken);
  1683. return rc;
  1684. }
  1685. DWORD
  1686. RegSetDefaultSpoolDirectory(
  1687. LPWSTR pValueName,
  1688. DWORD dwType,
  1689. LPBYTE pData,
  1690. DWORD cbData,
  1691. HKEY hKey,
  1692. PINISPOOLER pIniSpooler
  1693. )
  1694. {
  1695. DWORD rc = ERROR_SUCCESS;
  1696. LPWSTR pszNewSpoolDir = NULL;
  1697. SECURITY_ATTRIBUTES SecurityAttributes;
  1698. if ( pIniSpooler == NULL )
  1699. {
  1700. //
  1701. // This check is probably not needed.
  1702. // Old code was checking for NULL so instead of just removing it I
  1703. // changed it to an assert and fail gracefully w/o crash
  1704. //
  1705. rc = ERROR_INVALID_PARAMETER;
  1706. SPLASSERT(pIniSpooler != NULL);
  1707. }
  1708. else if (!pData || wcslen((LPWSTR)pData) > MAX_PATH - 12)
  1709. {
  1710. rc = ERROR_INVALID_PARAMETER;
  1711. }
  1712. else if ( !(pszNewSpoolDir = AllocSplStr((LPWSTR) pData)) )
  1713. {
  1714. rc = ERROR_OUTOFMEMORY;
  1715. }
  1716. if ( rc == ERROR_SUCCESS )
  1717. {
  1718. //
  1719. // Create the directory with the proper security, or fail trying
  1720. //
  1721. SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  1722. SecurityAttributes.lpSecurityDescriptor = CreateEverybodySecurityDescriptor();
  1723. SecurityAttributes.bInheritHandle = FALSE;
  1724. if ( !CreateDirectory(pszNewSpoolDir, &SecurityAttributes) )
  1725. {
  1726. rc = GetLastError();
  1727. //
  1728. // If the directory already exists it is not a failure
  1729. //
  1730. if ( rc == ERROR_ALREADY_EXISTS )
  1731. {
  1732. rc = ERROR_SUCCESS;
  1733. }
  1734. else if ( rc == ERROR_SUCCESS )
  1735. {
  1736. //
  1737. // Don't rely on last error being set
  1738. //
  1739. rc = ERROR_OUTOFMEMORY;
  1740. }
  1741. }
  1742. LocalFree(SecurityAttributes.lpSecurityDescriptor);
  1743. }
  1744. if ( rc == ERROR_SUCCESS )
  1745. {
  1746. EnterSplSem();
  1747. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1748. if ( rc == ERROR_SUCCESS ) {
  1749. FreeSplStr(pIniSpooler->pDefaultSpoolDir);
  1750. pIniSpooler->pDefaultSpoolDir = pszNewSpoolDir;
  1751. pszNewSpoolDir = NULL;
  1752. if ( pIniSpooler->hFilePool != INVALID_HANDLE_VALUE )
  1753. {
  1754. (VOID) ChangeFilePoolBasePath(pIniSpooler->hFilePool,
  1755. pIniSpooler->pDefaultSpoolDir);
  1756. }
  1757. }
  1758. LeaveSplSem();
  1759. }
  1760. FreeSplStr(pszNewSpoolDir);
  1761. return rc;
  1762. }
  1763. DWORD
  1764. RegSetPortThreadPriority(
  1765. LPWSTR pValueName,
  1766. DWORD dwType,
  1767. LPBYTE pData,
  1768. DWORD cbData,
  1769. HKEY hKey,
  1770. PINISPOOLER pIniSpooler
  1771. )
  1772. {
  1773. BOOL rc;
  1774. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1775. if ((rc == ERROR_SUCCESS) &&
  1776. (cbData >= sizeof(DWORD))) {
  1777. dwPortThreadPriority = *(LPDWORD)pData;
  1778. }
  1779. return rc;
  1780. }
  1781. DWORD
  1782. RegSetSchedulerThreadPriority(
  1783. LPWSTR pValueName,
  1784. DWORD dwType,
  1785. LPBYTE pData,
  1786. DWORD cbData,
  1787. HKEY hKey,
  1788. PINISPOOLER pIniSpooler
  1789. )
  1790. {
  1791. BOOL rc;
  1792. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1793. if ((rc == ERROR_SUCCESS) &&
  1794. (cbData >= sizeof(DWORD))) {
  1795. dwSchedulerThreadPriority = *(LPDWORD)pData;
  1796. }
  1797. return rc;
  1798. }
  1799. DWORD
  1800. RegSetBeepEnabled(
  1801. LPWSTR pValueName,
  1802. DWORD dwType,
  1803. LPBYTE pData,
  1804. DWORD cbData,
  1805. HKEY hKey,
  1806. PINISPOOLER pIniSpooler
  1807. )
  1808. {
  1809. BOOL rc;
  1810. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1811. if ((rc == ERROR_SUCCESS) &&
  1812. (cbData >= sizeof(DWORD)) &&
  1813. pIniSpooler) {
  1814. pIniSpooler->dwBeepEnabled = *(LPDWORD)pData;
  1815. // Make it 1 or 0
  1816. pIniSpooler->dwBeepEnabled = !!pIniSpooler->dwBeepEnabled;
  1817. }
  1818. return rc;
  1819. }
  1820. DWORD
  1821. RegSetRetryPopup(
  1822. LPWSTR pValueName,
  1823. DWORD dwType,
  1824. LPBYTE pData,
  1825. DWORD cbData,
  1826. HKEY hKey,
  1827. PINISPOOLER pIniSpooler
  1828. )
  1829. {
  1830. BOOL rc;
  1831. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1832. if ((rc == ERROR_SUCCESS) &&
  1833. (cbData >= sizeof(DWORD)) &&
  1834. pIniSpooler) {
  1835. pIniSpooler->bEnableRetryPopups = *(LPDWORD) pData;
  1836. // Make it 1 or 0
  1837. pIniSpooler->bEnableRetryPopups = !!pIniSpooler->bEnableRetryPopups;
  1838. }
  1839. return rc;
  1840. }
  1841. DWORD
  1842. RegSetNetPopup(
  1843. LPWSTR pValueName,
  1844. DWORD dwType,
  1845. LPBYTE pData,
  1846. DWORD cbData,
  1847. HKEY hKey,
  1848. PINISPOOLER pIniSpooler
  1849. )
  1850. {
  1851. BOOL rc;
  1852. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1853. if ((rc == ERROR_SUCCESS) &&
  1854. (cbData >= sizeof(DWORD)) &&
  1855. pIniSpooler) {
  1856. pIniSpooler->bEnableNetPopups = *(LPDWORD) pData;
  1857. // Make it 1 or 0
  1858. pIniSpooler->bEnableNetPopups = !!pIniSpooler->bEnableNetPopups;
  1859. }
  1860. return rc;
  1861. }
  1862. DWORD
  1863. RegSetEventLog(
  1864. LPWSTR pValueName,
  1865. DWORD dwType,
  1866. LPBYTE pData,
  1867. DWORD cbData,
  1868. HKEY hKey,
  1869. PINISPOOLER pIniSpooler
  1870. )
  1871. {
  1872. BOOL rc;
  1873. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1874. if ((rc == ERROR_SUCCESS) &&
  1875. (cbData >= sizeof(DWORD)) &&
  1876. pIniSpooler) {
  1877. pIniSpooler->dwEventLogging = *(LPDWORD) pData;
  1878. }
  1879. return rc;
  1880. }
  1881. DWORD
  1882. RegSetNetPopupToComputer(
  1883. LPWSTR pValueName,
  1884. DWORD dwType,
  1885. LPBYTE pData,
  1886. DWORD cbData,
  1887. HKEY hKey,
  1888. PINISPOOLER pIniSpooler
  1889. )
  1890. {
  1891. BOOL rc;
  1892. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1893. if ((rc == ERROR_SUCCESS) &&
  1894. (cbData >= sizeof(DWORD)) &&
  1895. pIniSpooler) {
  1896. pIniSpooler->bEnableNetPopupToComputer = *(LPDWORD) pData;
  1897. // Make it 1 or 0
  1898. pIniSpooler->bEnableNetPopupToComputer = !!pIniSpooler->bEnableNetPopupToComputer;
  1899. }
  1900. return rc;
  1901. }
  1902. DWORD
  1903. RegSetRestartJobOnPoolError(
  1904. LPWSTR pValueName,
  1905. DWORD dwType,
  1906. LPBYTE pData,
  1907. DWORD cbData,
  1908. HKEY hKey,
  1909. PINISPOOLER pIniSpooler
  1910. )
  1911. {
  1912. BOOL rc;
  1913. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1914. if ((rc == ERROR_SUCCESS) &&
  1915. (cbData >= sizeof(DWORD)) &&
  1916. pIniSpooler) {
  1917. pIniSpooler->dwRestartJobOnPoolTimeout = *(LPDWORD) pData;
  1918. }
  1919. return rc;
  1920. }
  1921. DWORD
  1922. RegSetRestartJobOnPoolEnabled(
  1923. LPWSTR pValueName,
  1924. DWORD dwType,
  1925. LPBYTE pData,
  1926. DWORD cbData,
  1927. HKEY hKey,
  1928. PINISPOOLER pIniSpooler
  1929. )
  1930. {
  1931. BOOL rc;
  1932. rc = SplRegSetValue(hKey, pValueName, dwType, pData, cbData, pIniSpooler);
  1933. if ((rc == ERROR_SUCCESS) &&
  1934. (cbData >= sizeof(DWORD)) &&
  1935. pIniSpooler) {
  1936. pIniSpooler->bRestartJobOnPoolEnabled = *(LPDWORD) pData;
  1937. // Make it 1 or 0
  1938. pIniSpooler->bRestartJobOnPoolEnabled = !!pIniSpooler->bRestartJobOnPoolEnabled;
  1939. }
  1940. return rc;
  1941. }
  1942. DWORD
  1943. RegSetNoRemoteDriver(
  1944. LPWSTR pValueName,
  1945. DWORD dwType,
  1946. LPBYTE pData,
  1947. DWORD cbData,
  1948. HKEY hKey,
  1949. PINISPOOLER pIniSpooler
  1950. )
  1951. {
  1952. return ERROR_NOT_SUPPORTED;
  1953. }
  1954. DWORD
  1955. PrinterNonRegGetDefaultSpoolDirectory(
  1956. PSPOOL pSpool,
  1957. LPDWORD pType,
  1958. LPBYTE pData,
  1959. DWORD nSize,
  1960. LPDWORD pcbNeeded
  1961. )
  1962. {
  1963. WCHAR szDefaultSpoolDirectory[MAX_PATH];
  1964. DWORD cch;
  1965. cch = GetPrinterDirectory( pSpool->pIniPrinter,
  1966. FALSE,
  1967. szDefaultSpoolDirectory,
  1968. COUNTOF(szDefaultSpoolDirectory),
  1969. pSpool->pIniSpooler );
  1970. if(!cch) {
  1971. return GetLastError();
  1972. }
  1973. *pcbNeeded = ( cch + 1 ) * sizeof( szDefaultSpoolDirectory[0] );
  1974. *pType = REG_SZ;
  1975. if( nSize < *pcbNeeded ){
  1976. return ERROR_MORE_DATA;
  1977. }
  1978. wcscpy( (LPWSTR)pData, szDefaultSpoolDirectory );
  1979. return ERROR_SUCCESS;
  1980. }
  1981. DWORD
  1982. PrinterNonRegGetChangeId(
  1983. PSPOOL pSpool,
  1984. LPDWORD pType,
  1985. LPBYTE pData,
  1986. DWORD nSize,
  1987. LPDWORD pcbNeeded
  1988. )
  1989. {
  1990. LPDWORD pdwChangeID = (LPDWORD)pData;
  1991. DWORD dwRetval = ERROR_INVALID_PARAMETER;
  1992. //
  1993. // We need a valid handle, piniPrinter
  1994. //
  1995. if (pSpool && pSpool->pIniPrinter)
  1996. {
  1997. if (pcbNeeded)
  1998. {
  1999. *pcbNeeded = sizeof(pSpool->pIniPrinter->cChangeID);
  2000. }
  2001. //
  2002. // The type is optional.
  2003. //
  2004. if (pType)
  2005. {
  2006. *pType = REG_DWORD;
  2007. }
  2008. //
  2009. // Is the provided buffer large enough.
  2010. //
  2011. if (nSize < sizeof(pSpool->pIniPrinter->cChangeID))
  2012. {
  2013. dwRetval = ERROR_MORE_DATA;
  2014. }
  2015. else
  2016. {
  2017. //
  2018. // Is the provided buffer valid.
  2019. //
  2020. if (pdwChangeID)
  2021. {
  2022. //
  2023. // Get the printer change id. We really would like
  2024. // more granularity on this. Just knowing if something
  2025. // changed about this printer is very general.
  2026. //
  2027. *pdwChangeID = pSpool->pIniPrinter->cChangeID;
  2028. dwRetval = ERROR_SUCCESS;
  2029. }
  2030. }
  2031. }
  2032. return dwRetval;
  2033. }
  2034. DWORD
  2035. NonRegGetDNSMachineName(
  2036. PINISPOOLER pIniSpooler,
  2037. LPDWORD pType,
  2038. LPBYTE pData,
  2039. DWORD nSize,
  2040. LPDWORD pcbNeeded
  2041. )
  2042. {
  2043. DWORD cChars;
  2044. if(!pIniSpooler || !pIniSpooler->pszFullMachineName) {
  2045. return ERROR_INVALID_PARAMETER;
  2046. }
  2047. cChars = wcslen(pIniSpooler->pszFullMachineName);
  2048. *pcbNeeded = ( cChars + 1 ) * sizeof( WCHAR );
  2049. *pType = REG_SZ;
  2050. if( nSize < *pcbNeeded ){
  2051. return ERROR_MORE_DATA;
  2052. }
  2053. wcscpy( (LPWSTR)pData, _wcslwr(pIniSpooler->pszFullMachineName) );
  2054. return ERROR_SUCCESS;
  2055. }
  2056. DWORD
  2057. NonRegDsPresent(
  2058. PINISPOOLER pIniSpooler,
  2059. LPDWORD pType,
  2060. LPBYTE pData,
  2061. DWORD nSize,
  2062. LPDWORD pcbNeeded
  2063. )
  2064. {
  2065. HANDLE hToken = NULL;
  2066. *pcbNeeded = sizeof(DWORD);
  2067. *pType = REG_DWORD;
  2068. if (nSize < sizeof(DWORD))
  2069. return ERROR_MORE_DATA;
  2070. hToken = RevertToPrinterSelf();
  2071. *(PDWORD) pData = IsDsPresent();
  2072. if (hToken)
  2073. ImpersonatePrinterClient(hToken);
  2074. return ERROR_SUCCESS;
  2075. }
  2076. BOOL
  2077. IsDsPresent(
  2078. )
  2079. {
  2080. DOMAIN_CONTROLLER_INFO *pDCI = NULL;
  2081. BOOL bDsPresent;
  2082. DWORD dwRet;
  2083. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  2084. // Get Domain name
  2085. dwRet = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *) &pDsRole);
  2086. bDsPresent = (dwRet == ERROR_SUCCESS &&
  2087. pDsRole->MachineRole != DsRole_RoleStandaloneServer &&
  2088. pDsRole->MachineRole != DsRole_RoleStandaloneWorkstation);
  2089. if (pDsRole) {
  2090. DsRoleFreeMemory((PVOID) pDsRole);
  2091. }
  2092. if (bDsPresent) {
  2093. if (DsGetDcName(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pDCI) == ERROR_SUCCESS)
  2094. bDsPresent = !!(pDCI->Flags & DS_DS_FLAG);
  2095. else
  2096. bDsPresent = FALSE;
  2097. if (pDCI)
  2098. NetApiBufferFree(pDCI);
  2099. }
  2100. return bDsPresent;
  2101. }
  2102. DWORD
  2103. NonRegDsPresentForUser(
  2104. PINISPOOLER pIniSpooler,
  2105. LPDWORD pType,
  2106. LPBYTE pData,
  2107. DWORD nSize,
  2108. LPDWORD pcbNeeded
  2109. )
  2110. {
  2111. WCHAR pUserName[MAX_PATH + 1];
  2112. PWSTR pszUserName = pUserName;
  2113. DWORD cchUserName = MAX_PATH + 1;
  2114. DWORD dwError = ERROR_SUCCESS;
  2115. PWSTR pszDomain;
  2116. DOMAIN_CONTROLLER_INFO *pDCI = NULL;
  2117. WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  2118. *pcbNeeded = sizeof(DWORD);
  2119. *pType = REG_DWORD;
  2120. if (nSize < sizeof(DWORD))
  2121. return ERROR_MORE_DATA;
  2122. // GetUserNameEx returns "Domain\User" in pszUserName (e.g.: NTDEV\swilson)
  2123. if (!GetUserNameEx(NameSamCompatible, pszUserName, &cchUserName)) {
  2124. if (cchUserName > MAX_PATH + 1) {
  2125. pszUserName = AllocSplMem(cchUserName);
  2126. if (!pszUserName || !GetUserNameEx(NameSamCompatible, pszUserName, &cchUserName)) {
  2127. dwError = GetLastError();
  2128. goto error;
  2129. }
  2130. } else {
  2131. dwError = GetLastError();
  2132. goto error;
  2133. }
  2134. }
  2135. // Chop off user name
  2136. pszDomain = wcschr(pszUserName, L'\\');
  2137. SPLASSERT(pszDomain);
  2138. if (pszDomain) { // pszDomain should never be NULL, but just in case...
  2139. *pszDomain = L'\0';
  2140. } else {
  2141. *(PDWORD) pData = 0;
  2142. goto error;
  2143. }
  2144. // If domain is same a machine name, then we're logged on locally
  2145. nSize = COUNTOF(szComputerName);
  2146. if (GetComputerName(szComputerName, &nSize) && !wcscmp(szComputerName, pszUserName)) {
  2147. *(PDWORD) pData = 0;
  2148. goto error;
  2149. }
  2150. pszDomain = pszUserName;
  2151. if (DsGetDcName(NULL, pszDomain, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pDCI) == ERROR_SUCCESS)
  2152. *(PDWORD) pData = !!(pDCI->Flags & DS_DS_FLAG);
  2153. error:
  2154. if (pDCI)
  2155. NetApiBufferFree(pDCI);
  2156. if (pszUserName != pUserName)
  2157. FreeSplMem(pszUserName);
  2158. return dwError;
  2159. }