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.

2253 lines
61 KiB

  1. /*++
  2. Copyright (c) 1990 - 1995 Microsoft Corporation
  3. Module Name:
  4. getprn.c
  5. Abstract:
  6. This module provides all the public exported APIs relating to Printer
  7. management for the Local Print Providor
  8. SplGetPrinter
  9. LocalEnumPrinters
  10. Author:
  11. Dave Snipp (DaveSn) 15-Mar-1991
  12. Steve Wilson (SWilson) - Dec 1996 Added GetPrinter Level 7
  13. Revision History:
  14. --*/
  15. #define NOMINMAX
  16. #include <precomp.h>
  17. #include <offsets.h>
  18. WCHAR *szNull = L"";
  19. WCHAR *szPrintProvidorName = L"Windows NT Local Print Providor";
  20. WCHAR *szPrintProvidorDescription=L"Windows NT Local Printers";
  21. WCHAR *szPrintProvidorComment=L"Locally connected Printers";
  22. WCHAR *gszDrvConvert = L",DrvConvert";
  23. #define Nulwcslen(psz) ((psz) ? wcslen(psz)*sizeof(WCHAR)+sizeof(WCHAR) : 0)
  24. #define PRINTER_STATUS_INTERNAL 0
  25. #define PRINTER_STATUS_EXTERNAL 1
  26. DWORD SettablePrinterStatusMappings[] = {
  27. // INTERNAL: EXTERNAL:
  28. PRINTER_OFFLINE, PRINTER_STATUS_OFFLINE,
  29. PRINTER_PAPEROUT, PRINTER_STATUS_PAPER_OUT,
  30. PRINTER_PAPER_JAM, PRINTER_STATUS_PAPER_JAM,
  31. PRINTER_MANUAL_FEED, PRINTER_STATUS_MANUAL_FEED,
  32. PRINTER_PAPER_PROBLEM, PRINTER_STATUS_PAPER_PROBLEM,
  33. PRINTER_IO_ACTIVE, PRINTER_STATUS_IO_ACTIVE,
  34. PRINTER_BUSY, PRINTER_STATUS_BUSY,
  35. PRINTER_PRINTING, PRINTER_STATUS_PRINTING,
  36. PRINTER_OUTPUT_BIN_FULL, PRINTER_STATUS_OUTPUT_BIN_FULL,
  37. PRINTER_NOT_AVAILABLE, PRINTER_STATUS_NOT_AVAILABLE,
  38. PRINTER_WAITING, PRINTER_STATUS_WAITING,
  39. PRINTER_PROCESSING, PRINTER_STATUS_PROCESSING,
  40. PRINTER_INITIALIZING, PRINTER_STATUS_INITIALIZING,
  41. PRINTER_WARMING_UP, PRINTER_STATUS_WARMING_UP,
  42. PRINTER_TONER_LOW, PRINTER_STATUS_TONER_LOW,
  43. PRINTER_NO_TONER, PRINTER_STATUS_NO_TONER,
  44. PRINTER_PAGE_PUNT, PRINTER_STATUS_PAGE_PUNT,
  45. PRINTER_USER_INTERVENTION, PRINTER_STATUS_USER_INTERVENTION,
  46. PRINTER_OUT_OF_MEMORY, PRINTER_STATUS_OUT_OF_MEMORY,
  47. PRINTER_DOOR_OPEN, PRINTER_STATUS_DOOR_OPEN,
  48. PRINTER_SERVER_UNKNOWN, PRINTER_STATUS_SERVER_UNKNOWN,
  49. PRINTER_POWER_SAVE, PRINTER_STATUS_POWER_SAVE,
  50. 0, 0
  51. };
  52. DWORD ReadablePrinterStatusMappings[] = {
  53. // INTERNAL: EXTERNAL:
  54. PRINTER_PAUSED, PRINTER_STATUS_PAUSED,
  55. PRINTER_PENDING_DELETION, PRINTER_STATUS_PENDING_DELETION,
  56. PRINTER_OFFLINE, PRINTER_STATUS_OFFLINE,
  57. PRINTER_PAPEROUT, PRINTER_STATUS_PAPER_OUT,
  58. PRINTER_PAPER_JAM, PRINTER_STATUS_PAPER_JAM,
  59. PRINTER_MANUAL_FEED, PRINTER_STATUS_MANUAL_FEED,
  60. PRINTER_PAPER_PROBLEM, PRINTER_STATUS_PAPER_PROBLEM,
  61. PRINTER_IO_ACTIVE, PRINTER_STATUS_IO_ACTIVE,
  62. PRINTER_BUSY, PRINTER_STATUS_BUSY,
  63. PRINTER_PRINTING, PRINTER_STATUS_PRINTING,
  64. PRINTER_OUTPUT_BIN_FULL, PRINTER_STATUS_OUTPUT_BIN_FULL,
  65. PRINTER_NOT_AVAILABLE, PRINTER_STATUS_NOT_AVAILABLE,
  66. PRINTER_WAITING, PRINTER_STATUS_WAITING,
  67. PRINTER_PROCESSING, PRINTER_STATUS_PROCESSING,
  68. PRINTER_INITIALIZING, PRINTER_STATUS_INITIALIZING,
  69. PRINTER_WARMING_UP, PRINTER_STATUS_WARMING_UP,
  70. PRINTER_TONER_LOW, PRINTER_STATUS_TONER_LOW,
  71. PRINTER_NO_TONER, PRINTER_STATUS_NO_TONER,
  72. PRINTER_PAGE_PUNT, PRINTER_STATUS_PAGE_PUNT,
  73. PRINTER_USER_INTERVENTION, PRINTER_STATUS_USER_INTERVENTION,
  74. PRINTER_OUT_OF_MEMORY, PRINTER_STATUS_OUT_OF_MEMORY,
  75. PRINTER_DOOR_OPEN, PRINTER_STATUS_DOOR_OPEN,
  76. PRINTER_SERVER_UNKNOWN, PRINTER_STATUS_SERVER_UNKNOWN,
  77. PRINTER_POWER_SAVE, PRINTER_STATUS_POWER_SAVE,
  78. 0, 0
  79. };
  80. DWORD
  81. MapPrinterStatus(
  82. DWORD Type,
  83. DWORD SourceStatus)
  84. {
  85. DWORD TargetStatus;
  86. PDWORD pMappings;
  87. INT MapFrom;
  88. INT MapTo;
  89. if (Type == MAP_READABLE) {
  90. MapFrom = PRINTER_STATUS_INTERNAL;
  91. MapTo = PRINTER_STATUS_EXTERNAL;
  92. pMappings = ReadablePrinterStatusMappings;
  93. } else {
  94. MapFrom = PRINTER_STATUS_EXTERNAL;
  95. MapTo = PRINTER_STATUS_INTERNAL;
  96. pMappings = SettablePrinterStatusMappings;
  97. }
  98. TargetStatus = 0;
  99. while(*pMappings) {
  100. if (SourceStatus & pMappings[MapFrom])
  101. TargetStatus |= pMappings[MapTo];
  102. pMappings += 2;
  103. }
  104. return TargetStatus;
  105. }
  106. DWORD
  107. GetIniNetPrintSize(
  108. PININETPRINT pIniNetPrint
  109. )
  110. {
  111. return sizeof(PRINTER_INFO_1) +
  112. wcslen(pIniNetPrint->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
  113. Nulwcslen(pIniNetPrint->pDescription) +
  114. Nulwcslen(pIniNetPrint->pComment);
  115. }
  116. DWORD
  117. GetPrinterSize(
  118. PINIPRINTER pIniPrinter,
  119. DWORD Level,
  120. DWORD Flags,
  121. LPWSTR lpRemote,
  122. LPDEVMODE pDevMode
  123. )
  124. {
  125. DWORD cb;
  126. DWORD cbNeeded;
  127. LPWSTR pszPorts;
  128. switch (Level) {
  129. case STRESSINFOLEVEL:
  130. cb = sizeof(PRINTER_INFO_STRESS) +
  131. wcslen(pIniPrinter->pName)*sizeof(WCHAR) + sizeof(WCHAR);
  132. if( lpRemote ){
  133. //
  134. // Allocate space for ServerName "\\foobar" and the prefix
  135. // for PrinterName "\\foobar\." The rest of PrinterName
  136. // is allocated above.
  137. //
  138. // ServerName + NULL + ServerName +'\'
  139. //
  140. cb += 2 * wcslen(lpRemote) * sizeof(WCHAR) +
  141. sizeof(WCHAR) + sizeof(WCHAR);
  142. }
  143. break;
  144. case 4:
  145. cb = sizeof(PRINTER_INFO_4) +
  146. wcslen(pIniPrinter->pName)*sizeof(WCHAR) + sizeof(WCHAR);
  147. if( lpRemote ){
  148. cb += 2 * wcslen(lpRemote) * sizeof(WCHAR) +
  149. sizeof(WCHAR) + sizeof(WCHAR);
  150. }
  151. break;
  152. case 1:
  153. //
  154. // Local:
  155. //
  156. // "pName,pDriver,pLocation"
  157. // "pName"
  158. // "pComment"
  159. //
  160. // Remote:
  161. //
  162. // "pMachine\pName,pDriver,<pLocation>"
  163. // "pMachine\pName"
  164. // "pComment"
  165. //
  166. //
  167. // Mandatory items, plus NULLs for _all_ strings.
  168. // 2 * PrinterName +
  169. // DriverName +
  170. // 2 commas, 3 NULL terminators.
  171. //
  172. cb = 2 * wcslen( pIniPrinter->pName ) +
  173. wcslen( pIniPrinter->pIniDriver->pName ) +
  174. 2 + 3;
  175. //
  176. // Add items that may be NULL.
  177. //
  178. if( pIniPrinter->pLocation ){
  179. cb += wcslen( pIniPrinter->pLocation );
  180. }
  181. if( pIniPrinter->pComment ){
  182. cb += wcslen( pIniPrinter->pComment );
  183. }
  184. //
  185. // Remote case adds prefix.
  186. // 2 * ( MachineName + BackSlash )
  187. //
  188. if( lpRemote ){
  189. cb += 2 * ( wcslen( lpRemote ) + 1 );
  190. }
  191. //
  192. // cb was a char count, convert to byte count.
  193. //
  194. cb *= sizeof( WCHAR );
  195. cb += sizeof( PRINTER_INFO_1 );
  196. break;
  197. case 2:
  198. cbNeeded = 0;
  199. GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
  200. cb = sizeof(PRINTER_INFO_2) +
  201. wcslen(pIniPrinter->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
  202. Nulwcslen(pIniPrinter->pShareName) +
  203. cbNeeded +
  204. wcslen(pIniPrinter->pIniDriver->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
  205. Nulwcslen(pIniPrinter->pComment) +
  206. Nulwcslen(pIniPrinter->pLocation) +
  207. Nulwcslen(pIniPrinter->pSepFile) +
  208. wcslen(pIniPrinter->pIniPrintProc->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
  209. Nulwcslen(pIniPrinter->pDatatype) +
  210. Nulwcslen(pIniPrinter->pParameters);
  211. if( lpRemote ){
  212. cb += 2 * wcslen(lpRemote) * sizeof(WCHAR) +
  213. sizeof(WCHAR) + sizeof(WCHAR);
  214. }
  215. if (pDevMode) {
  216. cb += pDevMode->dmSize + pDevMode->dmDriverExtra;
  217. cb = (cb + sizeof(ULONG_PTR)-1) & ~(sizeof(ULONG_PTR)-1);
  218. }
  219. if (pIniPrinter->pSecurityDescriptor) {
  220. cb += GetSecurityDescriptorLength(pIniPrinter->pSecurityDescriptor);
  221. cb = (cb + sizeof(ULONG_PTR)-1) & ~(sizeof(ULONG_PTR)-1);
  222. }
  223. break;
  224. case 3:
  225. cb = sizeof(PRINTER_INFO_3);
  226. cb += GetSecurityDescriptorLength(pIniPrinter->pSecurityDescriptor);
  227. cb = (cb + sizeof(ULONG_PTR)-1) & ~(sizeof(ULONG_PTR)-1);
  228. break;
  229. case 5:
  230. cbNeeded = 0;
  231. GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
  232. cb = sizeof(PRINTER_INFO_5) +
  233. wcslen(pIniPrinter->pName)*sizeof(WCHAR) + sizeof(WCHAR) +
  234. cbNeeded;
  235. //
  236. // Allocate space for just the PrinterName prefix:
  237. // "\\server\."
  238. //
  239. if( lpRemote ){
  240. cb += wcslen(lpRemote) * sizeof(WCHAR) +
  241. sizeof(WCHAR);
  242. }
  243. break;
  244. case 6:
  245. cb = sizeof(PRINTER_INFO_6);
  246. break;
  247. case 7:
  248. cb = sizeof(PRINTER_INFO_7);
  249. cb += pIniPrinter->pszObjectGUID ? (wcslen(pIniPrinter->pszObjectGUID) + 1)*sizeof(WCHAR) : 0;
  250. break;
  251. default:
  252. cb = 0;
  253. break;
  254. }
  255. return cb;
  256. }
  257. LPBYTE
  258. CopyIniNetPrintToPrinter(
  259. PININETPRINT pIniNetPrint,
  260. LPBYTE pPrinterInfo,
  261. LPBYTE pEnd
  262. )
  263. {
  264. LPWSTR SourceStrings[sizeof(PRINTER_INFO_1)/sizeof(LPWSTR)];
  265. LPWSTR *pSourceStrings=SourceStrings;
  266. PPRINTER_INFO_1 pPrinterInfo1 = (PPRINTER_INFO_1)pPrinterInfo;
  267. *pSourceStrings++=pIniNetPrint->pDescription;
  268. *pSourceStrings++=pIniNetPrint->pName;
  269. *pSourceStrings++=pIniNetPrint->pComment;
  270. pEnd = PackStrings(SourceStrings, pPrinterInfo, PrinterInfo1Strings, pEnd);
  271. pPrinterInfo1->Flags = PRINTER_ENUM_NAME;
  272. return pEnd;
  273. }
  274. /* CopyIniPrinterSecurityDescriptor
  275. *
  276. * Copies the security descriptor for the printer to the buffer provided
  277. * on a call to GetPrinter. The portions of the security descriptor which
  278. * will be copied are determined by the accesses granted when the printer
  279. * was opened. If it was opened with both READ_CONTROL and ACCESS_SYSTEM_SECURITY,
  280. * all of the security descriptor will be made available. Otherwise a
  281. * partial descriptor is built containing those portions to which the caller
  282. * has access.
  283. *
  284. * Parameters
  285. *
  286. * pIniPrinter - Spooler's private structure for this printer.
  287. *
  288. * Level - Should be 2 or 3. Any other will cause AV.
  289. *
  290. * pPrinterInfo - Pointer to the buffer to receive the PRINTER_INFO_*
  291. * structure. The pSecurityDescriptor field will be filled in with
  292. * a pointer to the security descriptor.
  293. *
  294. * pEnd - Current position in the buffer to receive the data.
  295. * This will be decremented to point to the next free bit of the
  296. * buffer and will be returned.
  297. *
  298. * GrantedAccess - An access mask used to determine how much of the
  299. * security descriptor the caller has access to.
  300. *
  301. * Returns
  302. *
  303. * Updated position in the buffer.
  304. *
  305. * NULL if an error occurred copying the security descriptor.
  306. * It is assumed that no other errors are possible.
  307. *
  308. */
  309. LPBYTE
  310. CopyIniPrinterSecurityDescriptor(
  311. PINIPRINTER pIniPrinter,
  312. DWORD Level,
  313. LPBYTE pPrinterInfo,
  314. LPBYTE pEnd,
  315. ACCESS_MASK GrantedAccess
  316. )
  317. {
  318. PSECURITY_DESCRIPTOR pPartialSecurityDescriptor = NULL;
  319. DWORD SecurityDescriptorLength = 0;
  320. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  321. PSECURITY_DESCRIPTOR *ppSecurityDescriptorCopy;
  322. BOOL ErrorOccurred = FALSE;
  323. if(!(AreAllAccessesGranted(GrantedAccess,
  324. READ_CONTROL | ACCESS_SYSTEM_SECURITY)))
  325. {
  326. /* Caller doesn't have full access, so we'll have to build
  327. * a partial descriptor:
  328. */
  329. if(!BuildPartialSecurityDescriptor(GrantedAccess,
  330. pIniPrinter->pSecurityDescriptor,
  331. &pPartialSecurityDescriptor,
  332. &SecurityDescriptorLength))
  333. {
  334. ErrorOccurred = TRUE;
  335. }
  336. else
  337. {
  338. if (pPartialSecurityDescriptor)
  339. {
  340. pSecurityDescriptor = pPartialSecurityDescriptor;
  341. }
  342. else
  343. {
  344. ErrorOccurred = TRUE;
  345. }
  346. }
  347. }
  348. else
  349. {
  350. pSecurityDescriptor = pIniPrinter->pSecurityDescriptor;
  351. SecurityDescriptorLength = GetSecurityDescriptorLength(pSecurityDescriptor);
  352. }
  353. if (!ErrorOccurred)
  354. {
  355. pEnd -= SecurityDescriptorLength;
  356. pEnd = (PBYTE) ALIGN_PTR_DOWN(pEnd);
  357. switch( Level )
  358. {
  359. case 2:
  360. ppSecurityDescriptorCopy =
  361. &((LPPRINTER_INFO_2)pPrinterInfo)->pSecurityDescriptor;
  362. break;
  363. case 3:
  364. ppSecurityDescriptorCopy =
  365. &((LPPRINTER_INFO_3)pPrinterInfo)->pSecurityDescriptor;
  366. break;
  367. default:
  368. ErrorOccurred = TRUE;
  369. /* This should never happen */
  370. DBGMSG( DBG_ERROR, ("Invalid level %d in CopyIniPrinterSecurityDescriptor\n", Level ));
  371. break;
  372. }
  373. if (!ErrorOccurred) {
  374. // Copy the descriptor into the buffer that will be returned:
  375. *ppSecurityDescriptorCopy = (PSECURITY_DESCRIPTOR)pEnd;
  376. memcpy(*ppSecurityDescriptorCopy, pSecurityDescriptor,
  377. SecurityDescriptorLength);
  378. }
  379. }
  380. if (pPartialSecurityDescriptor)
  381. {
  382. FreeSplMem(pPartialSecurityDescriptor);
  383. }
  384. if (ErrorOccurred)
  385. {
  386. pEnd = NULL;
  387. }
  388. return pEnd;
  389. }
  390. /* CopyIniPrinterToPrinter
  391. *
  392. * Copies the spooler's internal printer data to the caller's buffer,
  393. * depending on the level of information requested.
  394. *
  395. * Parameters
  396. *
  397. * pIniPrinter - A pointer to the spooler's internal data structure
  398. * for the printer concerned.
  399. *
  400. * Level - Level of information requested (1, 2 or 3). Any level
  401. * other than those supported will cause the routine to return
  402. * immediately.
  403. *
  404. * pPrinterInfo - Pointer to the buffer to receive the PRINTER_INFO_*
  405. * structure.
  406. *
  407. * pEnd - Current position in the buffer to receive the data.
  408. * This will be decremented to point to the next free bit of the
  409. * buffer and will be returned.
  410. *
  411. * pSecondPrinter - If the printer has a port which is being controlled
  412. * by a monitor, this parameter points to information retrieved
  413. * about a network printer. This allows us, e.g., to return
  414. * the number of jobs on the printer that the output of the
  415. * printer is currently being directed to.
  416. *
  417. * Remote - Indicates whether the caller is remote. If so we have to
  418. * include the machine name in the printer name returned.
  419. *
  420. * CopySecurityDescriptor - Indicates whether the security descriptor
  421. * should be copied. The security descriptor should not be copied
  422. * on EnumPrinters calls, because this API requires
  423. * SERVER_ACCESS_ENUMERATE access, and we'd have to do an access
  424. * check on every printer enumerated to determine how much of the
  425. * security descriptor could be copied. This would be costly,
  426. * and the caller would probably not need the information anyway.
  427. *
  428. * GrantedAccess - An access mask used to determine how much of the
  429. * security descriptor the caller has access to.
  430. *
  431. *
  432. * Returns
  433. *
  434. * A pointer to the point in the buffer reached after the requested
  435. * data has been copied.
  436. *
  437. * If there was an error, the return value is NULL.
  438. *
  439. *
  440. * Assumes
  441. *
  442. * The largest PRINTER_INFO_* structure is PRINTER_INFO_2.
  443. *
  444. */
  445. LPBYTE
  446. CopyIniPrinterToPrinter(
  447. PINIPRINTER pIniPrinter,
  448. DWORD Level,
  449. LPBYTE pPrinterInfo,
  450. LPBYTE pEnd,
  451. PPRINTER_INFO_2 pSecondPrinter2,
  452. LPWSTR lpRemote, // contains this machine name, or NULL
  453. BOOL CopySecurityDescriptor,
  454. ACCESS_MASK GrantedAccess,
  455. PDEVMODE pDevMode
  456. )
  457. {
  458. LPWSTR SourceStrings[sizeof(PRINTER_INFO_2)/sizeof(LPWSTR)];
  459. LPWSTR *pSourceStrings=SourceStrings;
  460. DWORD Attributes;
  461. //
  462. // Max string: "\\Computer\Printer,Driver,Location"
  463. //
  464. DWORD dwRet;
  465. PWSTR pszString = NULL;
  466. WCHAR string[ MAX_PRINTER_BROWSE_NAME ];
  467. DWORD dwLength;
  468. WCHAR printerString[ MAX_UNC_PRINTER_NAME ];
  469. LPWSTR pszPorts;
  470. PPRINTER_INFO_3 pPrinter3 = (PPRINTER_INFO_3)pPrinterInfo;
  471. PPRINTER_INFO_2 pPrinter2 = (PPRINTER_INFO_2)pPrinterInfo;
  472. PPRINTER_INFO_1 pPrinter1 = (PPRINTER_INFO_1)pPrinterInfo;
  473. PPRINTER_INFO_4 pPrinter4 = (PPRINTER_INFO_4)pPrinterInfo;
  474. PPRINTER_INFO_5 pPrinter5 = (PPRINTER_INFO_5)pPrinterInfo;
  475. PPRINTER_INFO_6 pPrinter6 = (PPRINTER_INFO_6)pPrinterInfo;
  476. PPRINTER_INFO_7 pPrinter7 = (PPRINTER_INFO_7)pPrinterInfo;
  477. PPRINTER_INFO_STRESS pPrinter0 = (PPRINTER_INFO_STRESS)pPrinterInfo;
  478. PSECURITY_DESCRIPTOR pPartialSecurityDescriptor = NULL;
  479. DWORD *pOffsets;
  480. SYSTEM_INFO si;
  481. DWORD cbNeeded;
  482. switch (Level) {
  483. case STRESSINFOLEVEL:
  484. pOffsets = PrinterInfoStressStrings;
  485. break;
  486. case 4:
  487. pOffsets = PrinterInfo4Strings;
  488. break;
  489. case 1:
  490. pOffsets = PrinterInfo1Strings;
  491. break;
  492. case 2:
  493. pOffsets = PrinterInfo2Strings;
  494. break;
  495. case 3:
  496. pOffsets = PrinterInfo3Strings;
  497. break;
  498. case 5:
  499. pOffsets = PrinterInfo5Strings;
  500. break;
  501. case 6:
  502. pOffsets = PrinterInfo6Strings;
  503. break;
  504. case 7:
  505. pOffsets = PrinterInfo7Strings;
  506. break;
  507. default:
  508. return pEnd;
  509. }
  510. //
  511. // If it's a cluster printer, it always appears remote.
  512. //
  513. Attributes = pIniPrinter->Attributes;
  514. Attributes |= ( pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ) ?
  515. PRINTER_ATTRIBUTE_NETWORK :
  516. PRINTER_ATTRIBUTE_LOCAL;
  517. switch (Level) {
  518. case STRESSINFOLEVEL:
  519. if (lpRemote) {
  520. wsprintf(string, L"%ws\\%ws", lpRemote, pIniPrinter->pName);
  521. *pSourceStrings++=string;
  522. *pSourceStrings++=lpRemote;
  523. } else {
  524. *pSourceStrings++=pIniPrinter->pName;
  525. *pSourceStrings++=NULL;
  526. }
  527. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter0, pOffsets, pEnd);
  528. pPrinter0->cJobs = pIniPrinter->cJobs;
  529. pPrinter0->cTotalJobs = pIniPrinter->cTotalJobs;
  530. pPrinter0->cTotalBytes = pIniPrinter->cTotalBytes.LowPart;
  531. pPrinter0->dwHighPartTotalBytes = pIniPrinter->cTotalBytes.HighPart;
  532. pPrinter0->stUpTime = pIniPrinter->stUpTime;
  533. pPrinter0->MaxcRef = pIniPrinter->MaxcRef;
  534. pPrinter0->cTotalPagesPrinted = pIniPrinter->cTotalPagesPrinted;
  535. pPrinter0->dwGetVersion = GetVersion();
  536. #if DBG
  537. pPrinter0->fFreeBuild = FALSE;
  538. #else
  539. pPrinter0->fFreeBuild = TRUE;
  540. #endif
  541. GetSystemInfo(&si);
  542. pPrinter0->dwProcessorType = si.dwProcessorType;
  543. pPrinter0->dwNumberOfProcessors = si.dwNumberOfProcessors;
  544. pPrinter0->cSpooling = pIniPrinter->cSpooling;
  545. pPrinter0->cMaxSpooling = pIniPrinter->cMaxSpooling;
  546. pPrinter0->cRef = pIniPrinter->cRef;
  547. pPrinter0->cErrorOutOfPaper = pIniPrinter->cErrorOutOfPaper;
  548. pPrinter0->cErrorNotReady = pIniPrinter->cErrorNotReady;
  549. pPrinter0->cJobError = pIniPrinter->cJobError;
  550. pPrinter0->cChangeID = pIniPrinter->cChangeID;
  551. pPrinter0->dwLastError = pIniPrinter->dwLastError;
  552. pPrinter0->Status = MapPrinterStatus(MAP_READABLE,
  553. pIniPrinter->Status) |
  554. pIniPrinter->PortStatus;
  555. pPrinter0->cEnumerateNetworkPrinters = pIniPrinter->pIniSpooler->cEnumerateNetworkPrinters;
  556. pPrinter0->cAddNetPrinters = pIniPrinter->pIniSpooler->cAddNetPrinters;
  557. pPrinter0->wProcessorArchitecture = si.wProcessorArchitecture;
  558. pPrinter0->wProcessorLevel = si.wProcessorLevel;
  559. pPrinter0->cRefIC = pIniPrinter->cRefIC;
  560. break;
  561. case 4:
  562. if (lpRemote) {
  563. wsprintf(string, L"%ws\\%ws", lpRemote, pIniPrinter->pName);
  564. *pSourceStrings++=string;
  565. *pSourceStrings++= lpRemote;
  566. } else {
  567. *pSourceStrings++=pIniPrinter->pName;
  568. *pSourceStrings++=NULL;
  569. }
  570. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter4, pOffsets, pEnd);
  571. //
  572. // Add additional info later
  573. //
  574. pPrinter4->Attributes = Attributes;
  575. break;
  576. case 1:
  577. if (lpRemote) {
  578. dwRet = StrCatAlloc(&pszString,
  579. lpRemote,
  580. L"\\",
  581. pIniPrinter->pName,
  582. L",",
  583. pIniPrinter->pIniDriver->pName,
  584. L",",
  585. pIniPrinter->pLocation ?
  586. pIniPrinter->pLocation :
  587. szNull,
  588. NULL);
  589. if (dwRet != ERROR_SUCCESS) {
  590. pEnd = NULL;
  591. break;
  592. }
  593. wsprintf(printerString, L"%ws\\%ws", lpRemote, pIniPrinter->pName);
  594. } else {
  595. dwRet = StrCatAlloc(&pszString,
  596. pIniPrinter->pName,
  597. L",",
  598. pIniPrinter->pIniDriver->pName,
  599. L",",
  600. pIniPrinter->pLocation ?
  601. pIniPrinter->pLocation :
  602. szNull,
  603. NULL);
  604. if (dwRet != ERROR_SUCCESS) {
  605. pEnd = NULL;
  606. break;
  607. }
  608. wcscpy(printerString, pIniPrinter->pName);
  609. }
  610. *pSourceStrings++=pszString;
  611. *pSourceStrings++=printerString;
  612. *pSourceStrings++=pIniPrinter->pComment;
  613. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter1, pOffsets, pEnd);
  614. FreeSplStr(pszString);
  615. pPrinter1->Flags = PRINTER_ENUM_ICON8;
  616. break;
  617. case 2:
  618. if (lpRemote) {
  619. *pSourceStrings++= lpRemote;
  620. wsprintf(string, L"%ws\\%ws", lpRemote, pIniPrinter->pName);
  621. *pSourceStrings++=string;
  622. } else {
  623. *pSourceStrings++=NULL;
  624. *pSourceStrings++=pIniPrinter->pName;
  625. }
  626. *pSourceStrings++=pIniPrinter->pShareName;
  627. cbNeeded = 0;
  628. GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
  629. if (pszPorts = AllocSplMem(cbNeeded)) {
  630. GetPrinterPorts(pIniPrinter, pszPorts, &cbNeeded);
  631. *pSourceStrings++=pszPorts;
  632. *pSourceStrings++=pIniPrinter->pIniDriver->pName;
  633. *pSourceStrings++=pIniPrinter->pComment;
  634. *pSourceStrings++=pIniPrinter->pLocation;
  635. *pSourceStrings++=pIniPrinter->pSepFile;
  636. *pSourceStrings++=pIniPrinter->pIniPrintProc->pName;
  637. *pSourceStrings++=pIniPrinter->pDatatype;
  638. *pSourceStrings++=pIniPrinter->pParameters;
  639. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter2, pOffsets, pEnd);
  640. FreeSplMem(pszPorts);
  641. }
  642. else {
  643. pEnd = NULL;
  644. break;
  645. }
  646. if (pDevMode) {
  647. pEnd -= pDevMode->dmSize + pDevMode->dmDriverExtra;
  648. pEnd = (PBYTE)ALIGN_PTR_DOWN(pEnd);
  649. pPrinter2->pDevMode=(LPDEVMODE)pEnd;
  650. memcpy(pPrinter2->pDevMode, pDevMode, pDevMode->dmSize + pDevMode->dmDriverExtra);
  651. //
  652. // In the remote case, append the name of the server
  653. // in the devmode.dmDeviceName. This allows dmDeviceName
  654. // to always match win.ini's [devices] section.
  655. //
  656. FixDevModeDeviceName(lpRemote ? string : pIniPrinter->pName,
  657. pPrinter2->pDevMode,
  658. pIniPrinter->cbDevMode);
  659. } else {
  660. pPrinter2->pDevMode=NULL;
  661. }
  662. pPrinter2->Attributes = Attributes;
  663. pPrinter2->Priority = pIniPrinter->Priority;
  664. pPrinter2->DefaultPriority = pIniPrinter->DefaultPriority;
  665. pPrinter2->StartTime = pIniPrinter->StartTime;
  666. pPrinter2->UntilTime = pIniPrinter->UntilTime;
  667. if (pSecondPrinter2) {
  668. pPrinter2->cJobs = pSecondPrinter2->cJobs;
  669. pPrinter2->Status = pSecondPrinter2->Status;
  670. if( pIniPrinter->Status & PRINTER_PENDING_DELETION ){
  671. pPrinter2->Status |= PRINTER_STATUS_PENDING_DELETION;
  672. }
  673. } else {
  674. pPrinter2->cJobs=pIniPrinter->cJobs;
  675. pPrinter2->Status = MapPrinterStatus(MAP_READABLE,
  676. pIniPrinter->Status) |
  677. pIniPrinter->PortStatus;
  678. }
  679. pPrinter2->AveragePPM=pIniPrinter->AveragePPM;
  680. if( CopySecurityDescriptor ) {
  681. pEnd = CopyIniPrinterSecurityDescriptor(pIniPrinter,
  682. Level,
  683. pPrinterInfo,
  684. pEnd,
  685. GrantedAccess);
  686. } else {
  687. pPrinter2->pSecurityDescriptor = NULL;
  688. }
  689. break;
  690. case 3:
  691. pEnd = CopyIniPrinterSecurityDescriptor(pIniPrinter,
  692. Level,
  693. pPrinterInfo,
  694. pEnd,
  695. GrantedAccess);
  696. break;
  697. case 5:
  698. if (lpRemote) {
  699. wsprintf(string, L"%ws\\%ws", lpRemote, pIniPrinter->pName);
  700. *pSourceStrings++=string;
  701. } else {
  702. *pSourceStrings++=pIniPrinter->pName;
  703. }
  704. cbNeeded = 0;
  705. GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
  706. if (pszPorts = AllocSplMem(cbNeeded)) {
  707. GetPrinterPorts(pIniPrinter, pszPorts, &cbNeeded);
  708. *pSourceStrings++ = pszPorts;
  709. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter5, pOffsets, pEnd);
  710. pPrinter5->Attributes = Attributes;
  711. pPrinter5->DeviceNotSelectedTimeout = pIniPrinter->dnsTimeout;
  712. pPrinter5->TransmissionRetryTimeout = pIniPrinter->txTimeout;
  713. FreeSplMem(pszPorts);
  714. }
  715. else
  716. pEnd = NULL;
  717. break;
  718. case 6:
  719. if (pSecondPrinter2) {
  720. pPrinter6->dwStatus = pSecondPrinter2->Status;
  721. if( pIniPrinter->Status & PRINTER_PENDING_DELETION ){
  722. pPrinter6->dwStatus |= PRINTER_STATUS_PENDING_DELETION;
  723. }
  724. } else {
  725. pPrinter6->dwStatus = MapPrinterStatus(MAP_READABLE,
  726. pIniPrinter->Status) |
  727. pIniPrinter->PortStatus;
  728. }
  729. break;
  730. case 7:
  731. *pSourceStrings++ = pIniPrinter->pszObjectGUID;
  732. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter7, pOffsets, pEnd);
  733. if ( pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CACHE) {
  734. //
  735. // For connections, we rely directly on dwAction. The caching code
  736. // is the only one that updates dwAction in RefreshPrinterInfo7.
  737. //
  738. pPrinter7->dwAction = pIniPrinter->dwAction;
  739. } else {
  740. if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
  741. pPrinter7->dwAction = DSPRINT_PUBLISH;
  742. if (!pIniPrinter->pszObjectGUID ||
  743. pIniPrinter->DsKeyUpdate ||
  744. pIniPrinter->DsKeyUpdateForeground) {
  745. pPrinter7->dwAction |= DSPRINT_PENDING;
  746. }
  747. } else {
  748. pPrinter7->dwAction = DSPRINT_UNPUBLISH;
  749. if (pIniPrinter->pszObjectGUID ||
  750. (pIniPrinter->DsKeyUpdate & DS_KEY_UNPUBLISH) ||
  751. (pIniPrinter->DsKeyUpdateForeground & DS_KEY_UNPUBLISH)) {
  752. pPrinter7->dwAction |= DSPRINT_PENDING;
  753. }
  754. }
  755. }
  756. break;
  757. default:
  758. return pEnd;
  759. }
  760. return pEnd;
  761. }
  762. BOOL
  763. SplGetPrinter(
  764. HANDLE hPrinter,
  765. DWORD Level,
  766. LPBYTE pPrinter,
  767. DWORD cbBuf,
  768. LPDWORD pcbNeeded
  769. )
  770. {
  771. PSPOOL pSpool = (PSPOOL)hPrinter;
  772. BOOL AccessIsGranted = FALSE; // Must intialize
  773. PPRINTER_INFO_2 pSecondPrinter=NULL;
  774. LPBYTE pEnd;
  775. LPWSTR lpRemote;
  776. BOOL bReturn = FALSE;
  777. PDEVMODE pDevMode = NULL;
  778. PINIPRINTER pIniPrinter;
  779. BOOL bNt3xClient;
  780. PWSTR pszCN = NULL, pszDN = NULL;
  781. DWORD dwRet;
  782. EnterSplSem();
  783. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
  784. goto Cleanup;
  785. }
  786. pIniPrinter = pSpool->pIniPrinter;
  787. bNt3xClient = (pSpool->TypeofHandle & PRINTER_HANDLE_3XCLIENT);
  788. //
  789. // If Nt3x client we will converted devmode. If driver can't convert we will not return devmode
  790. //
  791. if ( bNt3xClient && Level == 2 && pIniPrinter->pDevMode ) {
  792. //
  793. // Call driver to get a Nt3x DevMode (if fails no devmode is given)
  794. //
  795. if (wcsstr(pSpool->pName, gszDrvConvert))
  796. pDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
  797. pIniPrinter->pDevMode,
  798. NULL,
  799. pSpool->pName,
  800. NT3X_VERSION);
  801. else
  802. pDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
  803. pIniPrinter->pDevMode,
  804. NULL,
  805. NULL,
  806. NT3X_VERSION);
  807. }
  808. SplInSem();
  809. if (( pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_DATA ) ||
  810. ( pSpool->pIniSpooler != pLocalIniSpooler )) {
  811. lpRemote = pSpool->pFullMachineName;
  812. } else {
  813. lpRemote = NULL;
  814. }
  815. switch (Level) {
  816. case STRESSINFOLEVEL:
  817. case 1:
  818. case 2:
  819. case 4:
  820. case 5:
  821. case 6:
  822. case 7:
  823. if ( !AccessGranted(SPOOLER_OBJECT_PRINTER,
  824. PRINTER_ACCESS_USE,
  825. pSpool) ) {
  826. SetLastError(ERROR_ACCESS_DENIED);
  827. goto Cleanup;
  828. }
  829. break;
  830. case 3:
  831. if (!AreAnyAccessesGranted(pSpool->GrantedAccess,
  832. READ_CONTROL | ACCESS_SYSTEM_SECURITY)) {
  833. SetLastError(ERROR_ACCESS_DENIED);
  834. goto Cleanup;
  835. }
  836. break;
  837. default:
  838. break;
  839. }
  840. if (pSpool->pIniPort && !(pSpool->pIniPort->Status & PP_MONITOR)) {
  841. HANDLE hPort = pSpool->hPort;
  842. if (hPort == INVALID_PORT_HANDLE) {
  843. DBGMSG(DBG_WARNING, ("GetPrinter called with bad port handle. Setting error %d\n",
  844. pSpool->OpenPortError));
  845. //
  846. // If this value is 0, then when we return GetLastError,
  847. // the client will think we succeeded.
  848. //
  849. SPLASSERT(pSpool->OpenPortError);
  850. goto PartialSuccess;
  851. }
  852. LeaveSplSem();
  853. if ((Level == 2 || Level == 6)) {
  854. if (!RetrieveMasqPrinterInfo(pSpool, &pSecondPrinter)) {
  855. goto CleanupFromOutsideSplSem;
  856. }
  857. }
  858. EnterSplSem();
  859. /* Re-validate the handle, since it might possibly have been closed
  860. * while we were outside the semaphore:
  861. */
  862. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
  863. goto Cleanup;
  864. }
  865. }
  866. PartialSuccess:
  867. *pcbNeeded = GetPrinterSize(pIniPrinter, Level, 0, lpRemote,
  868. bNt3xClient ? pDevMode : pIniPrinter->pDevMode);
  869. if (*pcbNeeded > cbBuf) {
  870. DBGMSG(DBG_TRACE, ("SplGetPrinter Failure with ERROR_INSUFFICIENT_BUFFER cbBuf is %d and pcbNeeded is %d\n", cbBuf, *pcbNeeded));
  871. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  872. goto Cleanup;
  873. }
  874. pEnd = CopyIniPrinterToPrinter(pIniPrinter, Level, pPrinter,
  875. pPrinter+cbBuf, (PPRINTER_INFO_2) pSecondPrinter,
  876. lpRemote,
  877. TRUE, pSpool->GrantedAccess,
  878. bNt3xClient ? pDevMode : pIniPrinter->pDevMode);
  879. if ( pEnd != NULL)
  880. bReturn = TRUE;
  881. Cleanup:
  882. LeaveSplSem();
  883. CleanupFromOutsideSplSem:
  884. SplOutSem();
  885. FreeSplMem(pSecondPrinter);
  886. FreeSplMem(pDevMode);
  887. if ( bReturn == FALSE ) {
  888. SPLASSERT(GetLastError() != ERROR_SUCCESS);
  889. }
  890. return bReturn;
  891. }
  892. BOOL
  893. EnumerateNetworkPrinters(
  894. LPBYTE pPrinter,
  895. DWORD cbBuf,
  896. LPDWORD pcbNeeded,
  897. LPDWORD pcReturned,
  898. PINISPOOLER pIniSpooler
  899. )
  900. {
  901. PININETPRINT pIniNetPrint;
  902. DWORD cb;
  903. LPBYTE pEnd;
  904. BOOL bReturnValue = FALSE;
  905. EnterSplSem();
  906. //
  907. // All network printers reside in pLocalIniSpooler to avoid
  908. // duplicates.
  909. //
  910. RemoveOldNetPrinters( NULL, pLocalIniSpooler );
  911. //
  912. // If the Server has not been up long enough, then fail
  913. // so the client will ask another Server for the Browse List.
  914. //
  915. if ( bNetInfoReady == FALSE ) {
  916. SetLastError( ERROR_CAN_NOT_COMPLETE );
  917. goto Done;
  918. }
  919. cb = 0;
  920. pIniNetPrint = pIniSpooler->pIniNetPrint;
  921. while (pIniNetPrint) {
  922. cb += GetIniNetPrintSize( pIniNetPrint );
  923. pIniNetPrint = pIniNetPrint->pNext;
  924. }
  925. *pcbNeeded = cb;
  926. if (cb > cbBuf) {
  927. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  928. goto Done;
  929. }
  930. pIniNetPrint = pIniSpooler->pIniNetPrint;
  931. pEnd = pPrinter + cbBuf;
  932. while ( pIniNetPrint ) {
  933. pEnd = CopyIniNetPrintToPrinter( pIniNetPrint, pPrinter, pEnd );
  934. (*pcReturned)++;
  935. pPrinter += sizeof(PRINTER_INFO_1);
  936. pIniNetPrint = pIniNetPrint->pNext;
  937. }
  938. if ( *pcReturned == 0 ) {
  939. bNetInfoReady = FALSE;
  940. FirstAddNetPrinterTickCount = 0;
  941. SetLastError( ERROR_CAN_NOT_COMPLETE );
  942. DBGMSG( DBG_TRACE, ("EnumerateNetworkPrinters returning ERROR_CAN_NOT_COMPELTE becase there is no browse list\n"));
  943. } else {
  944. pIniSpooler->cEnumerateNetworkPrinters++; // Stats only
  945. bReturnValue = TRUE;
  946. DBGMSG( DBG_TRACE, (" EnumerateNetworkPrnters called %d times returning %d printers\n", pIniSpooler->cEnumerateNetworkPrinters, *pcReturned ));
  947. }
  948. Done:
  949. LeaveSplSem();
  950. SplOutSem();
  951. return bReturnValue;
  952. }
  953. /*++
  954. Routine Name
  955. UpdateSpoolersRef
  956. Routine Description:
  957. Does and AddRef or a DecRef on all pIniSpooler matching a certain criteria
  958. Arguments:
  959. SpoolerType - Type of pIniSpoolers which to addref/decref
  960. (Ex. SPL_TYPE_CLUSTER | SPL_TYPE_LOCAL)
  961. bAddRef - TRUE means AddRef, FALSE means DecRef
  962. Return Value:
  963. None
  964. --*/
  965. VOID
  966. UpdateSpoolersRef(
  967. IN DWORD SpoolerType,
  968. IN BOOL bAddRef
  969. )
  970. {
  971. PINISPOOLER pIniSpooler;
  972. EnterSplSem();
  973. //
  974. // AddRef or DecRef all local and cluster spoolers
  975. //
  976. for (pIniSpooler = pLocalIniSpooler; pIniSpooler; pIniSpooler = pIniSpooler->pIniNextSpooler)
  977. {
  978. if (pIniSpooler->SpoolerFlags & SpoolerType)
  979. {
  980. if (bAddRef)
  981. {
  982. INCSPOOLERREF(pIniSpooler);
  983. }
  984. else
  985. {
  986. DECSPOOLERREF(pIniSpooler);
  987. }
  988. }
  989. }
  990. LeaveSplSem();
  991. }
  992. /*++
  993. Routine Name
  994. SplEnumAllClusterPrinters
  995. Routine Description:
  996. Enumerates all printers in the local spooler and all cluster
  997. spoolers hosted by localspl at the time of the call.
  998. Arguments:
  999. InputFlags - combination of ENUM_PRINTER_xxx
  1000. pszInputName - name of the print provider
  1001. Level - level of the call
  1002. pPrinter - buffer to hold the PRINTER_INFO_xxx structures
  1003. cbInputBufSize - size of pPrinter buffer
  1004. pcbNeeded - bytes required to hold all the printer info structures
  1005. pcReturned - number of structures returned by this function
  1006. Return Value:
  1007. TRUE - cal succeeded
  1008. FALSE - an error occurred, the function sets the last error
  1009. --*/
  1010. BOOL
  1011. SplEnumAllClusterPrinters(
  1012. DWORD InputFlags,
  1013. LPWSTR pszInputName,
  1014. DWORD Level,
  1015. LPBYTE pPrinter,
  1016. DWORD cbInputBufSize,
  1017. LPDWORD pcbNeeded,
  1018. LPDWORD pcReturned
  1019. )
  1020. {
  1021. PINISPOOLER pIniSpooler;
  1022. DWORD cbBuf = cbInputBufSize;
  1023. DWORD cTotalReturned = 0;
  1024. DWORD cbTotalNeeded = 0;
  1025. DWORD dwError = ERROR_SUCCESS;
  1026. DWORD cbStruct;
  1027. switch (Level)
  1028. {
  1029. case STRESSINFOLEVEL:
  1030. cbStruct = sizeof(PRINTER_INFO_STRESS);
  1031. break;
  1032. case 1:
  1033. cbStruct = sizeof(PRINTER_INFO_1);
  1034. break;
  1035. case 2:
  1036. cbStruct = sizeof(PRINTER_INFO_2);
  1037. break;
  1038. case 4:
  1039. cbStruct = sizeof(PRINTER_INFO_4);
  1040. break;
  1041. case 5:
  1042. cbStruct = sizeof(PRINTER_INFO_5);
  1043. break;
  1044. default:
  1045. dwError = ERROR_INVALID_LEVEL;
  1046. }
  1047. if (dwError == ERROR_SUCCESS)
  1048. {
  1049. //
  1050. // AddRef all ini spoolers
  1051. //
  1052. UpdateSpoolersRef(SPL_TYPE_LOCAL | SPL_TYPE_CLUSTER, TRUE);
  1053. //
  1054. // Enumerate all the printers
  1055. //
  1056. for (pIniSpooler = pLocalIniSpooler; pIniSpooler; pIniSpooler = pIniSpooler->pIniNextSpooler)
  1057. {
  1058. if (pIniSpooler->SpoolerFlags & (SPL_TYPE_LOCAL | SPL_TYPE_CLUSTER))
  1059. {
  1060. DWORD cReturned;
  1061. DWORD cbNeeded;
  1062. DWORD Flags = InputFlags;
  1063. LPWSTR pszName = pszInputName;
  1064. //
  1065. // For clusters force the printer name to be fully qualified
  1066. //
  1067. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER)
  1068. {
  1069. Flags |= PRINTER_ENUM_NAME;
  1070. pszName = pIniSpooler->pMachineName;
  1071. }
  1072. if (SplEnumPrinters(Flags,
  1073. pszName,
  1074. Level,
  1075. pPrinter,
  1076. cbBuf,
  1077. &cbNeeded,
  1078. &cReturned,
  1079. pIniSpooler))
  1080. {
  1081. cTotalReturned += cReturned;
  1082. cbBuf -= cbNeeded;
  1083. pPrinter += cReturned * cbStruct;
  1084. }
  1085. else
  1086. {
  1087. dwError = GetLastError();
  1088. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  1089. {
  1090. cbBuf = 0;
  1091. }
  1092. else
  1093. {
  1094. //
  1095. // We cannot continue on an error different than insufficient buffer
  1096. //
  1097. break;
  1098. }
  1099. }
  1100. cbTotalNeeded += cbNeeded;
  1101. }
  1102. }
  1103. //
  1104. // DecRef all ini spoolers
  1105. //
  1106. UpdateSpoolersRef(SPL_TYPE_LOCAL | SPL_TYPE_CLUSTER, FALSE);
  1107. //
  1108. // Update out variables
  1109. //
  1110. if (dwError == ERROR_SUCCESS)
  1111. {
  1112. *pcbNeeded = cbTotalNeeded;
  1113. *pcReturned = cTotalReturned;
  1114. }
  1115. else if (dwError == ERROR_INSUFFICIENT_BUFFER)
  1116. {
  1117. *pcbNeeded = cbTotalNeeded;
  1118. }
  1119. else
  1120. {
  1121. SetLastError(dwError);
  1122. }
  1123. }
  1124. return dwError == ERROR_SUCCESS;
  1125. }
  1126. /*
  1127. EnumPrinters can be called with the following combinations:
  1128. Flags Name Meaning
  1129. PRINTER_ENUM_LOCAL NULL Enumerate all Printers on this machine
  1130. PRINTER_ENUM_NAME MachineName Enumerate all Printers on this machine
  1131. PRINTER_ENUM_NAME | MachineName Enumerate all shared Printers on this
  1132. PRINTER_ENUM_SHARED MachineName machine
  1133. PRINTER_ENUM_NETWORK MachineName Enumerate all added remote printers
  1134. PRINTER_ENUM_REMOTE ? Return error - let win32spl handle it
  1135. PRINTER_ENUM_NAME NULL Give back Print Providor name
  1136. PRINTER_ENUM_NAME "Windows NT Local Print Providor"
  1137. same as PRINTER_ENUM_LOCAL
  1138. It is not an error if no known flag is specified.
  1139. In this case we just return TRUE without any data
  1140. (This is so that other print providers may define
  1141. their own flags.)
  1142. */
  1143. BOOL
  1144. LocalEnumPrinters(
  1145. DWORD Flags,
  1146. LPWSTR pName,
  1147. DWORD Level,
  1148. LPBYTE pPrinter,
  1149. DWORD cbBuf,
  1150. LPDWORD pcbNeeded,
  1151. LPDWORD pcReturned
  1152. )
  1153. {
  1154. BOOL bReturn = ROUTER_UNKNOWN;
  1155. if (Flags & PRINTER_ENUM_CLUSTER)
  1156. {
  1157. bReturn = SplEnumAllClusterPrinters(Flags,
  1158. pName,
  1159. Level,
  1160. pPrinter,
  1161. cbBuf,
  1162. pcbNeeded,
  1163. pcReturned);
  1164. }
  1165. else
  1166. {
  1167. PINISPOOLER pIniSpooler;
  1168. //
  1169. // Mask cluster flag
  1170. //
  1171. Flags &= ~PRINTER_ENUM_CLUSTER;
  1172. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  1173. if (pIniSpooler)
  1174. {
  1175. bReturn = SplEnumPrinters(Flags,
  1176. pName,
  1177. Level,
  1178. pPrinter,
  1179. cbBuf,
  1180. pcbNeeded,
  1181. pcReturned,
  1182. pIniSpooler);
  1183. FindSpoolerByNameDecRef(pIniSpooler);
  1184. }
  1185. }
  1186. return bReturn;
  1187. }
  1188. BOOL
  1189. EnumThisPrinter(
  1190. DWORD Flags,
  1191. PINIPRINTER pIniPrinter,
  1192. PINISPOOLER pIniSpooler
  1193. )
  1194. {
  1195. //
  1196. // If they only want shared Printers
  1197. //
  1198. if ( (Flags & PRINTER_ENUM_SHARED) &&
  1199. !(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) )
  1200. return FALSE;
  1201. //
  1202. // Only allow them to see printers which are being deleted if they have jobs
  1203. // This allows remote admin to work well.
  1204. if ( (pIniPrinter->Status & PRINTER_PENDING_DELETION) &&
  1205. pIniPrinter->cJobs == 0 )
  1206. return FALSE;
  1207. //
  1208. // Don't count printers which are partially created
  1209. //
  1210. if ( pIniPrinter->Status & PRINTER_PENDING_CREATION )
  1211. return FALSE;
  1212. return TRUE;
  1213. }
  1214. BOOL
  1215. SplEnumPrinters(
  1216. DWORD Flags,
  1217. LPWSTR Name,
  1218. DWORD Level,
  1219. LPBYTE pPrinter,
  1220. DWORD cbBuf,
  1221. LPDWORD pcbNeeded,
  1222. LPDWORD pcReturned,
  1223. PINISPOOLER pIniSpooler
  1224. )
  1225. {
  1226. PINIPRINTER pIniPrinter;
  1227. PPRINTER_INFO_1 pPrinter1=(PPRINTER_INFO_1)pPrinter;
  1228. DWORD cb;
  1229. LPBYTE pEnd;
  1230. LPWSTR lpRemote;
  1231. *pcbNeeded = 0;
  1232. *pcReturned = 0;
  1233. if ( Flags & PRINTER_ENUM_NAME ) {
  1234. if ( Name && *Name ) {
  1235. if (lstrcmpi(Name, szPrintProvidorName) && !MyName( Name, pIniSpooler)) {
  1236. return FALSE;
  1237. }
  1238. // If it's PRINTER_ENUM_NAME of our name,
  1239. // do the same as PRINTER_ENUM_LOCAL:
  1240. Flags |= PRINTER_ENUM_LOCAL;
  1241. // Also if it is for us then ignore the REMOTE flag.
  1242. // Otherwise the call will get passed to Win32Spl which
  1243. // will end up calling us back forever.
  1244. Flags &= ~PRINTER_ENUM_REMOTE;
  1245. }
  1246. }
  1247. if ( Flags & PRINTER_ENUM_REMOTE ) {
  1248. SetLastError( ERROR_INVALID_NAME );
  1249. return FALSE;
  1250. }
  1251. lpRemote = NULL;
  1252. if ( Name && *Name ) {
  1253. if ( MyName( Name, pIniSpooler ) ) {
  1254. lpRemote = Name;
  1255. }
  1256. }
  1257. if ((Level == 1) && (Flags & PRINTER_ENUM_NETWORK)) {
  1258. SplOutSem();
  1259. return EnumerateNetworkPrinters( pPrinter, cbBuf, pcbNeeded, pcReturned, pIniSpooler );
  1260. }
  1261. EnterSplSem();
  1262. if ((Level == 1 ) && (Flags & PRINTER_ENUM_NAME) && !Name) {
  1263. LPWSTR SourceStrings[sizeof(PRINTER_INFO_1)/sizeof(LPWSTR)];
  1264. LPWSTR *pSourceStrings=SourceStrings;
  1265. cb = wcslen(szPrintProvidorName)*sizeof(WCHAR) + sizeof(WCHAR) +
  1266. wcslen(szPrintProvidorDescription)*sizeof(WCHAR) + sizeof(WCHAR) +
  1267. wcslen(szPrintProvidorComment)*sizeof(WCHAR) + sizeof(WCHAR) +
  1268. sizeof(PRINTER_INFO_1);
  1269. *pcbNeeded=cb;
  1270. if (cb > cbBuf) {
  1271. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1272. LeaveSplSem();
  1273. return FALSE;
  1274. }
  1275. *pcReturned = 1;
  1276. pPrinter1->Flags = PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON1;
  1277. *pSourceStrings++=szPrintProvidorDescription;
  1278. *pSourceStrings++=szPrintProvidorName;
  1279. *pSourceStrings++=szPrintProvidorComment;
  1280. PackStrings(SourceStrings, pPrinter, PrinterInfo1Strings,
  1281. pPrinter+cbBuf);
  1282. LeaveSplSem();
  1283. return TRUE;
  1284. }
  1285. cb=0;
  1286. if (Flags & (PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME)) {
  1287. //
  1288. // For remote user's who are not admins enumerate shared printers only
  1289. //
  1290. if ( !IsLocalCall() &&
  1291. !(Flags & PRINTER_ENUM_SHARED) &&
  1292. !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  1293. SERVER_ACCESS_ADMINISTER,
  1294. NULL,
  1295. NULL,
  1296. pIniSpooler) )
  1297. Flags |= PRINTER_ENUM_SHARED;
  1298. //
  1299. // Calculate the size required
  1300. //
  1301. for ( pIniPrinter = pIniSpooler->pIniPrinter;
  1302. pIniPrinter != NULL;
  1303. pIniPrinter = pIniPrinter->pNext ) {
  1304. #ifdef _HYDRA_
  1305. if ( EnumThisPrinter(Flags, pIniPrinter, pIniSpooler) && ShowThisPrinter( pIniPrinter ))
  1306. #else
  1307. if ( EnumThisPrinter(Flags, pIniPrinter, pIniSpooler) )
  1308. #endif
  1309. cb += GetPrinterSize(pIniPrinter, Level, Flags,
  1310. lpRemote, pIniPrinter->pDevMode);
  1311. }
  1312. }
  1313. *pcbNeeded=cb;
  1314. if (cb > cbBuf) {
  1315. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1316. LeaveSplSem();
  1317. return FALSE;
  1318. }
  1319. if (Flags & (PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME)) {
  1320. for ( pIniPrinter = pIniSpooler->pIniPrinter, pEnd = pPrinter + cbBuf;
  1321. pIniPrinter != NULL;
  1322. pIniPrinter = pIniPrinter->pNext ) {
  1323. if ( !EnumThisPrinter(Flags, pIniPrinter, pIniSpooler) )
  1324. continue;
  1325. #ifdef _HYDRA_
  1326. // Do not list printers without access
  1327. if( !ShowThisPrinter( pIniPrinter ) ) {
  1328. continue;
  1329. }
  1330. #endif
  1331. pEnd = CopyIniPrinterToPrinter( pIniPrinter, Level, pPrinter,
  1332. pEnd, NULL, lpRemote, FALSE, 0,
  1333. pIniPrinter->pDevMode );
  1334. if (!pEnd) {
  1335. LeaveSplSem();
  1336. return FALSE;
  1337. }
  1338. (*pcReturned)++;
  1339. switch (Level) {
  1340. case STRESSINFOLEVEL:
  1341. pPrinter+=sizeof(PRINTER_INFO_STRESS);
  1342. break;
  1343. case 1:
  1344. pPrinter+=sizeof(PRINTER_INFO_1);
  1345. break;
  1346. case 2:
  1347. pPrinter+=sizeof(PRINTER_INFO_2);
  1348. break;
  1349. case 4:
  1350. pPrinter+=sizeof(PRINTER_INFO_4);
  1351. break;
  1352. case 5:
  1353. pPrinter+=sizeof(PRINTER_INFO_5);
  1354. break;
  1355. }
  1356. }
  1357. }
  1358. LeaveSplSem();
  1359. return TRUE;
  1360. }
  1361. #ifdef _HYDRA_
  1362. /* ShowThisPrinter
  1363. *
  1364. * Returns whether this printer should be visible to the current
  1365. * user.
  1366. *
  1367. * We do not show printers that the caller does not
  1368. * have access to. This is for two reasons:
  1369. *
  1370. * 1: A multi-user system with 200 users each with their
  1371. * own client printers would cause a large confusing
  1372. * list of printers from within applications such as word.
  1373. * "Client" printers are owned by the user of that station,
  1374. * and by default only allow print access for that user.
  1375. * This provides a simple way of filtering printers to show
  1376. * to the user for a selection.
  1377. *
  1378. * 2: Programs such as Windows write get confused when
  1379. * they see a printer they can not open. This is a bad
  1380. * program, since normal NT can have a printer denied to a user, but we must
  1381. * make it work anyway.
  1382. *
  1383. *
  1384. * Must work out security modes!
  1385. *
  1386. * Parameters
  1387. *
  1388. * pIniPrinter - A pointer to the spooler's internal data structure
  1389. * for the printer concerned.
  1390. */
  1391. BOOL
  1392. ShowThisPrinter(
  1393. PINIPRINTER pIniPrinter
  1394. )
  1395. {
  1396. LPWSTR pObjectName;
  1397. HANDLE ClientToken;
  1398. BOOL AccessCheckOK;
  1399. BOOL OK;
  1400. BOOL AccessStatus = TRUE;
  1401. ACCESS_MASK MappedDesiredAccess;
  1402. DWORD GrantedAccess = 0;
  1403. PBOOL pGenerateOnClose;
  1404. BYTE PrivilegeSetBuffer[256];
  1405. DWORD PrivilegeSetBufferLength = 256;
  1406. PPRIVILEGE_SET pPrivilegeSet;
  1407. DWORD dwRetCode;
  1408. PTOKEN_PRIVILEGES pPreviousTokenPrivileges;
  1409. DWORD PreviousTokenPrivilegesLength;
  1410. // External references to global variables in security.c
  1411. extern GENERIC_MAPPING GenericMapping[];
  1412. extern WCHAR *szSpooler;
  1413. //
  1414. // If Hydra is not enabled, keep NT behavior unchanged
  1415. //
  1416. if( !(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer)) ) {
  1417. return( TRUE );
  1418. }
  1419. //
  1420. // Administrators see all printers. This allows an
  1421. // Admin to take ownership of a printer whose ACL is
  1422. // messed up.
  1423. //
  1424. if( ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  1425. SERVER_ACCESS_ADMINISTER,
  1426. NULL,
  1427. NULL,
  1428. pIniPrinter->pIniSpooler) ) {
  1429. return( TRUE );
  1430. }
  1431. MapGenericToSpecificAccess(
  1432. SPOOLER_OBJECT_PRINTER,
  1433. PRINTER_ACCESS_USE,
  1434. &MappedDesiredAccess
  1435. );
  1436. if (!(OK = GetTokenHandle(&ClientToken))) {
  1437. return(FALSE);
  1438. }
  1439. pPrivilegeSet = (PPRIVILEGE_SET)PrivilegeSetBuffer;
  1440. /* Call AccessCheck followed by ObjectOpenAuditAlarm rather than
  1441. * AccessCheckAndAuditAlarm, because we may need to enable
  1442. * SeSecurityPrivilege in order to check for ACCESS_SYSTEM_SECURITY
  1443. * privilege. We must ensure that the security access-checking
  1444. * API has the actual token whose security privilege we have enabled.
  1445. * AccessCheckAndAuditAlarm is no good for this, because it opens
  1446. * the client's token again, which may not have the privilege enabled.
  1447. */
  1448. AccessCheckOK = AccessCheck( pIniPrinter->pSecurityDescriptor,
  1449. ClientToken,
  1450. MappedDesiredAccess,
  1451. &GenericMapping[SPOOLER_OBJECT_PRINTER],
  1452. pPrivilegeSet,
  1453. &PrivilegeSetBufferLength,
  1454. &GrantedAccess,
  1455. &AccessStatus );
  1456. // Close the client token handle now
  1457. CloseHandle (ClientToken);
  1458. if (!AccessCheckOK) {
  1459. //
  1460. // We do not audit and set off alarms because the caller
  1461. // did not really try and open the printer.
  1462. // We the server tried to check access for display purposes, not
  1463. // for handle create.
  1464. //
  1465. if (GetLastError() == ERROR_NO_IMPERSONATION_TOKEN) {
  1466. DBGMSG( DBG_ERROR, ("ShowThisPrinter: No impersonation token. Printer will be enumerated\n"));
  1467. return( TRUE );
  1468. }else {
  1469. DBGMSG( DBG_TRACE, ("ShowThisPrinter: Printer %ws Not accessable by caller Access Check failuer %d\n",pIniPrinter->pName,GetLastError()));
  1470. return( FALSE );
  1471. }
  1472. }
  1473. else if( !AccessStatus ) {
  1474. DBGMSG( DBG_TRACE, ("ShowThisPrinter: Printer %ws Not accessable by caller AccessStatus failure %d\n",pIniPrinter->pName,GetLastError()));
  1475. return( FALSE );
  1476. }
  1477. return( TRUE );
  1478. }
  1479. #endif
  1480. /*++
  1481. Routine Name:
  1482. RetrieveMasqPrinterInfo
  1483. Description:
  1484. This retrieves Masq information for the printer, it is either cached state
  1485. or a direct call into the provider depending on Reg Settings.
  1486. Arguments:
  1487. pSpool - The spool handle that we use for synchronisation.
  1488. ppPrinterInfo - The returned printer info.
  1489. Returns:
  1490. A Boolean, if FALSE, last error is set.
  1491. --*/
  1492. BOOL
  1493. RetrieveMasqPrinterInfo(
  1494. IN PSPOOL pSpool,
  1495. OUT PRINTER_INFO_2 **ppPrinterInfo
  1496. )
  1497. {
  1498. BOOL bRet = TRUE;
  1499. PINIPRINTER pIniPrinter = NULL;
  1500. pIniPrinter = pSpool->pIniPrinter;
  1501. SplOutSem();
  1502. if (!(pSpool->pIniSpooler->dwSpoolerSettings & SPOOLER_CACHEMASQPRINTERS))
  1503. {
  1504. //
  1505. // Just synchronously return the data from the partial print provider.
  1506. //
  1507. bRet = BoolFromStatus(GetPrinterInfoFromRouter(pSpool->hPort, ppPrinterInfo));
  1508. }
  1509. else
  1510. {
  1511. //
  1512. // Kick off the thread that goes and reads the masq status.
  1513. //
  1514. BOOL bCreateThread = FALSE;
  1515. PRINTER_INFO_2 *pPrinterInfo2 = NULL;
  1516. EnterSplSem();
  1517. if (!pIniPrinter->MasqCache.bThreadRunning)
  1518. {
  1519. bCreateThread = TRUE;
  1520. pIniPrinter->MasqCache.bThreadRunning = TRUE;
  1521. INCPRINTERREF(pIniPrinter);
  1522. }
  1523. LeaveSplSem();
  1524. SplOutSem();
  1525. if (bCreateThread)
  1526. {
  1527. HANDLE hThread = NULL;
  1528. MasqUpdateThreadData *pThreadData = NULL;
  1529. DWORD dwThreadId = 0;
  1530. pThreadData = AllocSplMem(sizeof(*pThreadData));
  1531. bRet = pThreadData != NULL;
  1532. if (bRet)
  1533. {
  1534. bRet = GetSid(&pThreadData->hUserToken);
  1535. }
  1536. if (bRet)
  1537. {
  1538. pThreadData->pIniPrinter = pIniPrinter;
  1539. hThread = CreateThread(NULL, 0, AsyncPopulateMasqPrinterCache, (VOID *)pThreadData, 0, &dwThreadId);
  1540. bRet = hThread != NULL;
  1541. }
  1542. if (bRet)
  1543. {
  1544. pThreadData = NULL;
  1545. }
  1546. //
  1547. // If we couldn't create the thread, then drop the ref count on the
  1548. // pIniPrinter again and set thread running to false.
  1549. //
  1550. if (!bRet)
  1551. {
  1552. EnterSplSem();
  1553. pIniPrinter->MasqCache.bThreadRunning = FALSE;
  1554. DECPRINTERREF(pIniPrinter);
  1555. LeaveSplSem();
  1556. }
  1557. if (hThread)
  1558. {
  1559. CloseHandle(hThread);
  1560. }
  1561. if (pThreadData)
  1562. {
  1563. if (pThreadData->hUserToken)
  1564. {
  1565. CloseHandle(pThreadData->hUserToken);
  1566. }
  1567. FreeSplMem(pThreadData);
  1568. }
  1569. }
  1570. //
  1571. // Check to see the cached error return for the printer.
  1572. //
  1573. if (bRet)
  1574. {
  1575. EnterSplSem();
  1576. if (pIniPrinter->MasqCache.dwError != ERROR_SUCCESS)
  1577. {
  1578. SetLastError(pIniPrinter->MasqCache.dwError);
  1579. bRet = FALSE;
  1580. }
  1581. //
  1582. // Caller is only interested in the Status and cJobs members, all strings
  1583. // are set to NULL by the allocation.
  1584. //
  1585. if (bRet)
  1586. {
  1587. pPrinterInfo2 = AllocSplMem(sizeof(PRINTER_INFO_2));
  1588. bRet = pPrinterInfo2 != NULL;
  1589. }
  1590. if (bRet)
  1591. {
  1592. pPrinterInfo2->Status = pIniPrinter->MasqCache.Status;
  1593. pPrinterInfo2->cJobs = pIniPrinter->MasqCache.cJobs;
  1594. *ppPrinterInfo = pPrinterInfo2;
  1595. pPrinterInfo2 = NULL;
  1596. }
  1597. LeaveSplSem();
  1598. }
  1599. FreeSplMem(pPrinterInfo2);
  1600. }
  1601. return bRet;
  1602. }
  1603. /*++
  1604. Routine Name:
  1605. GetPrinterInfoFromRouter
  1606. Description:
  1607. This does a GetPrinter call against the router, it returns the error code
  1608. as a status.
  1609. Arguments:
  1610. hMasqPrinter - Handle to the masq printer.
  1611. ppPrinterInfo - Returned printer info.
  1612. Returns:
  1613. Status Code.
  1614. --*/
  1615. DWORD
  1616. GetPrinterInfoFromRouter(
  1617. IN HANDLE hMasqPrinter,
  1618. OUT PRINTER_INFO_2 **ppPrinterInfo
  1619. )
  1620. {
  1621. DWORD Status = ERROR_SUCCESS;
  1622. DWORD cb = 4096;
  1623. PRINTER_INFO_2 *pPrinterInfo2 = NULL;
  1624. DWORD cbNeeded;
  1625. SplOutSem();
  1626. pPrinterInfo2 = AllocSplMem(cb);
  1627. Status = pPrinterInfo2 != NULL ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
  1628. if (ERROR_SUCCESS == Status)
  1629. {
  1630. Status = GetPrinter(hMasqPrinter, 2, (BYTE *)pPrinterInfo2, cb, &cbNeeded) ? ERROR_SUCCESS : GetLastError();
  1631. }
  1632. if (ERROR_INSUFFICIENT_BUFFER == Status)
  1633. {
  1634. FreeSplMem(pPrinterInfo2);
  1635. pPrinterInfo2 = NULL;
  1636. cb = cbNeeded;
  1637. pPrinterInfo2 = AllocSplMem(cb);
  1638. Status = pPrinterInfo2 != NULL ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
  1639. if (ERROR_SUCCESS == Status)
  1640. {
  1641. Status = GetPrinter(hMasqPrinter, 2, (BYTE *)pPrinterInfo2, cb, &cbNeeded) ? ERROR_SUCCESS : GetLastError();
  1642. }
  1643. }
  1644. if (ERROR_SUCCESS == Status)
  1645. {
  1646. *ppPrinterInfo = pPrinterInfo2;
  1647. pPrinterInfo2 = NULL;
  1648. }
  1649. FreeSplMem(pPrinterInfo2);
  1650. return Status;
  1651. }
  1652. /*++
  1653. Routine Name:
  1654. AsyncPopulateMasqPrinterCache
  1655. Description:
  1656. This populates the Masq printer cache for a given pIniPrinter.
  1657. Arguments:
  1658. pvThreadData - Pointer to a MasqUpdateThreadData structure
  1659. Returns:
  1660. A DWORD status, ignored.
  1661. --*/
  1662. DWORD
  1663. AsyncPopulateMasqPrinterCache(
  1664. IN VOID *pvThreadData
  1665. )
  1666. {
  1667. DWORD Status = ERROR_SUCCESS;
  1668. PINIPRINTER pIniPrinter = NULL;
  1669. PINIPORT pIniPort = NULL;
  1670. PWSTR pszPrinterName = NULL;
  1671. HANDLE hMasqPrinter = NULL;
  1672. PRINTER_INFO_2 *pPrinterInfo2 = NULL;
  1673. MasqUpdateThreadData *pThreadData = NULL;
  1674. SplOutSem();
  1675. pThreadData = (MasqUpdateThreadData *)pvThreadData;
  1676. pIniPrinter = pThreadData->pIniPrinter;
  1677. Status = SetCurrentSid(pThreadData->hUserToken) ? ERROR_SUCCESS : GetLastError();
  1678. EnterSplSem();
  1679. //
  1680. // Find the port associated with the printer.
  1681. //
  1682. if (Status == ERROR_SUCCESS)
  1683. {
  1684. pIniPort = FindIniPortFromIniPrinter(pIniPrinter);
  1685. Status = pIniPort && !(pIniPort->Status & PP_MONITOR) ? ERROR_SUCCESS : ERROR_INVALID_FUNCTION;
  1686. }
  1687. if (Status == ERROR_SUCCESS)
  1688. {
  1689. INCPORTREF(pIniPort);
  1690. LeaveSplSem();
  1691. SplOutSem();
  1692. //
  1693. // This relies on the fact that a masq port cannot be renamed.
  1694. //
  1695. if (OpenPrinterPortW(pIniPort->pName, &hMasqPrinter, NULL))
  1696. {
  1697. //
  1698. // This will propogate any errors into the masq cache, which we
  1699. // don't have to do twice, so we ignore the return code.
  1700. //
  1701. Status = GetPrinterInfoFromRouter(hMasqPrinter, &pPrinterInfo2);
  1702. ClosePrinter(hMasqPrinter);
  1703. }
  1704. else
  1705. {
  1706. Status = GetLastError();
  1707. if (Status == ERROR_SUCCESS)
  1708. {
  1709. Status = ERROR_UNEXP_NET_ERR;
  1710. }
  1711. }
  1712. EnterSplSem();
  1713. if (ERROR_SUCCESS == Status)
  1714. {
  1715. pIniPrinter->MasqCache.cJobs = pPrinterInfo2->cJobs;
  1716. pIniPrinter->MasqCache.Status = pPrinterInfo2->Status;
  1717. }
  1718. else
  1719. {
  1720. pIniPrinter->MasqCache.cJobs = 0;
  1721. pIniPrinter->MasqCache.Status = 0;
  1722. }
  1723. //
  1724. // We always want to reset the status.
  1725. //
  1726. pIniPrinter->MasqCache.dwError = Status;
  1727. DECPORTREF(pIniPort);
  1728. }
  1729. SplInSem();
  1730. pIniPrinter->MasqCache.bThreadRunning = FALSE;
  1731. DECPRINTERREF(pIniPrinter);
  1732. DeletePrinterCheck(pIniPrinter);
  1733. LeaveSplSem();
  1734. if (pThreadData)
  1735. {
  1736. CloseHandle(pThreadData->hUserToken);
  1737. }
  1738. FreeSplMem(pThreadData);
  1739. FreeSplMem(pPrinterInfo2);
  1740. return Status;
  1741. }