Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2313 lines
65 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. //
  377. // This is OK because GetPrinterSize has validated that the buffer
  378. // is big enough.
  379. //
  380. memcpy(*ppSecurityDescriptorCopy, pSecurityDescriptor, SecurityDescriptorLength);
  381. }
  382. }
  383. if (pPartialSecurityDescriptor)
  384. {
  385. FreeSplMem(pPartialSecurityDescriptor);
  386. }
  387. if (ErrorOccurred)
  388. {
  389. pEnd = NULL;
  390. }
  391. return pEnd;
  392. }
  393. /* CopyIniPrinterToPrinter
  394. *
  395. * Copies the spooler's internal printer data to the caller's buffer,
  396. * depending on the level of information requested.
  397. *
  398. * Parameters
  399. *
  400. * pIniPrinter - A pointer to the spooler's internal data structure
  401. * for the printer concerned.
  402. *
  403. * Level - Level of information requested (1, 2 or 3). Any level
  404. * other than those supported will cause the routine to return
  405. * immediately.
  406. *
  407. * pPrinterInfo - Pointer to the buffer to receive the PRINTER_INFO_*
  408. * structure.
  409. *
  410. * pEnd - Current position in the buffer to receive the data.
  411. * This will be decremented to point to the next free bit of the
  412. * buffer and will be returned.
  413. *
  414. * pSecondPrinter - If the printer has a port which is being controlled
  415. * by a monitor, this parameter points to information retrieved
  416. * about a network printer. This allows us, e.g., to return
  417. * the number of jobs on the printer that the output of the
  418. * printer is currently being directed to.
  419. *
  420. * Remote - Indicates whether the caller is remote. If so we have to
  421. * include the machine name in the printer name returned.
  422. *
  423. * CopySecurityDescriptor - Indicates whether the security descriptor
  424. * should be copied. The security descriptor should not be copied
  425. * on EnumPrinters calls, because this API requires
  426. * SERVER_ACCESS_ENUMERATE access, and we'd have to do an access
  427. * check on every printer enumerated to determine how much of the
  428. * security descriptor could be copied. This would be costly,
  429. * and the caller would probably not need the information anyway.
  430. *
  431. * GrantedAccess - An access mask used to determine how much of the
  432. * security descriptor the caller has access to.
  433. *
  434. *
  435. * Returns
  436. *
  437. * A pointer to the point in the buffer reached after the requested
  438. * data has been copied.
  439. *
  440. * If there was an error, the return value is NULL.
  441. *
  442. *
  443. * Assumes
  444. *
  445. * The largest PRINTER_INFO_* structure is PRINTER_INFO_2.
  446. *
  447. */
  448. LPBYTE
  449. CopyIniPrinterToPrinter(
  450. PINIPRINTER pIniPrinter,
  451. DWORD Level,
  452. LPBYTE pPrinterInfo,
  453. LPBYTE pEnd,
  454. PPRINTER_INFO_2 pSecondPrinter2,
  455. LPWSTR lpRemote, // contains this machine name, or NULL
  456. BOOL CopySecurityDescriptor,
  457. ACCESS_MASK GrantedAccess,
  458. PDEVMODE pDevMode
  459. )
  460. {
  461. LPWSTR SourceStrings[sizeof(PRINTER_INFO_2)/sizeof(LPWSTR)];
  462. LPWSTR *pSourceStrings=SourceStrings;
  463. DWORD Attributes;
  464. //
  465. // Max string: "\\Computer\Printer,Driver,Location"
  466. //
  467. DWORD dwRet;
  468. PWSTR pszString = NULL;
  469. WCHAR string[MAX_PRINTER_BROWSE_NAME];
  470. DWORD dwLength;
  471. WCHAR printerString[ MAX_UNC_PRINTER_NAME ];
  472. LPWSTR pszPorts;
  473. PPRINTER_INFO_3 pPrinter3 = (PPRINTER_INFO_3)pPrinterInfo;
  474. PPRINTER_INFO_2 pPrinter2 = (PPRINTER_INFO_2)pPrinterInfo;
  475. PPRINTER_INFO_1 pPrinter1 = (PPRINTER_INFO_1)pPrinterInfo;
  476. PPRINTER_INFO_4 pPrinter4 = (PPRINTER_INFO_4)pPrinterInfo;
  477. PPRINTER_INFO_5 pPrinter5 = (PPRINTER_INFO_5)pPrinterInfo;
  478. PPRINTER_INFO_6 pPrinter6 = (PPRINTER_INFO_6)pPrinterInfo;
  479. PPRINTER_INFO_7 pPrinter7 = (PPRINTER_INFO_7)pPrinterInfo;
  480. PPRINTER_INFO_STRESS pPrinter0 = (PPRINTER_INFO_STRESS)pPrinterInfo;
  481. PSECURITY_DESCRIPTOR pPartialSecurityDescriptor = NULL;
  482. DWORD *pOffsets;
  483. SYSTEM_INFO si;
  484. DWORD cbNeeded;
  485. switch (Level) {
  486. case STRESSINFOLEVEL:
  487. pOffsets = PrinterInfoStressStrings;
  488. break;
  489. case 4:
  490. pOffsets = PrinterInfo4Strings;
  491. break;
  492. case 1:
  493. pOffsets = PrinterInfo1Strings;
  494. break;
  495. case 2:
  496. pOffsets = PrinterInfo2Strings;
  497. break;
  498. case 3:
  499. pOffsets = PrinterInfo3Strings;
  500. break;
  501. case 5:
  502. pOffsets = PrinterInfo5Strings;
  503. break;
  504. case 6:
  505. pOffsets = PrinterInfo6Strings;
  506. break;
  507. case 7:
  508. pOffsets = PrinterInfo7Strings;
  509. break;
  510. default:
  511. return pEnd;
  512. }
  513. //
  514. // If it's a cluster printer, it always appears remote.
  515. //
  516. Attributes = pIniPrinter->Attributes;
  517. Attributes |= ( pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ) ?
  518. PRINTER_ATTRIBUTE_NETWORK :
  519. PRINTER_ATTRIBUTE_LOCAL;
  520. switch (Level) {
  521. case STRESSINFOLEVEL:
  522. if (lpRemote) {
  523. if (!BoolFromHResult(StringCchPrintf(string, COUNTOF(string), L"%ws\\%ws", lpRemote, pIniPrinter->pName))) {
  524. pEnd = NULL;
  525. break;
  526. }
  527. *pSourceStrings++=string;
  528. *pSourceStrings++=lpRemote;
  529. } else {
  530. *pSourceStrings++=pIniPrinter->pName;
  531. *pSourceStrings++=NULL;
  532. }
  533. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter0, pOffsets, pEnd);
  534. pPrinter0->cJobs = pIniPrinter->cJobs;
  535. pPrinter0->cTotalJobs = pIniPrinter->cTotalJobs;
  536. pPrinter0->cTotalBytes = pIniPrinter->cTotalBytes.LowPart;
  537. pPrinter0->dwHighPartTotalBytes = pIniPrinter->cTotalBytes.HighPart;
  538. pPrinter0->stUpTime = pIniPrinter->stUpTime;
  539. pPrinter0->MaxcRef = pIniPrinter->MaxcRef;
  540. pPrinter0->cTotalPagesPrinted = pIniPrinter->cTotalPagesPrinted;
  541. pPrinter0->dwGetVersion = GetVersion();
  542. #if DBG
  543. pPrinter0->fFreeBuild = FALSE;
  544. #else
  545. pPrinter0->fFreeBuild = TRUE;
  546. #endif
  547. GetSystemInfo(&si);
  548. pPrinter0->dwProcessorType = si.dwProcessorType;
  549. pPrinter0->dwNumberOfProcessors = si.dwNumberOfProcessors;
  550. pPrinter0->cSpooling = pIniPrinter->cSpooling;
  551. pPrinter0->cMaxSpooling = pIniPrinter->cMaxSpooling;
  552. pPrinter0->cRef = pIniPrinter->cRef;
  553. pPrinter0->cErrorOutOfPaper = pIniPrinter->cErrorOutOfPaper;
  554. pPrinter0->cErrorNotReady = pIniPrinter->cErrorNotReady;
  555. pPrinter0->cJobError = pIniPrinter->cJobError;
  556. pPrinter0->cChangeID = pIniPrinter->cChangeID;
  557. pPrinter0->dwLastError = pIniPrinter->dwLastError;
  558. pPrinter0->Status = MapPrinterStatus(MAP_READABLE,
  559. pIniPrinter->Status) |
  560. pIniPrinter->PortStatus;
  561. pPrinter0->cEnumerateNetworkPrinters = pIniPrinter->pIniSpooler->cEnumerateNetworkPrinters;
  562. pPrinter0->cAddNetPrinters = pIniPrinter->pIniSpooler->cAddNetPrinters;
  563. pPrinter0->wProcessorArchitecture = si.wProcessorArchitecture;
  564. pPrinter0->wProcessorLevel = si.wProcessorLevel;
  565. pPrinter0->cRefIC = pIniPrinter->cRefIC;
  566. break;
  567. case 4:
  568. if (lpRemote) {
  569. if (!BoolFromHResult(StringCchPrintf(string, COUNTOF(string), L"%ws\\%ws", lpRemote, pIniPrinter->pName))) {
  570. pEnd = NULL;
  571. break;
  572. }
  573. *pSourceStrings++=string;
  574. *pSourceStrings++= lpRemote;
  575. } else {
  576. *pSourceStrings++=pIniPrinter->pName;
  577. *pSourceStrings++=NULL;
  578. }
  579. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter4, pOffsets, pEnd);
  580. //
  581. // Add additional info later
  582. //
  583. pPrinter4->Attributes = Attributes;
  584. break;
  585. case 1:
  586. if (lpRemote) {
  587. dwRet = StrCatAlloc(&pszString,
  588. lpRemote,
  589. L"\\",
  590. pIniPrinter->pName,
  591. L",",
  592. pIniPrinter->pIniDriver->pName,
  593. L",",
  594. pIniPrinter->pLocation ?
  595. pIniPrinter->pLocation :
  596. szNull,
  597. NULL);
  598. if (dwRet != ERROR_SUCCESS) {
  599. pEnd = NULL;
  600. break;
  601. }
  602. if (!BoolFromHResult(StringCchPrintf(printerString, COUNTOF(printerString), L"%ws\\%ws", lpRemote, pIniPrinter->pName))) {
  603. pEnd = NULL;
  604. break;
  605. }
  606. } else {
  607. dwRet = StrCatAlloc(&pszString,
  608. pIniPrinter->pName,
  609. L",",
  610. pIniPrinter->pIniDriver->pName,
  611. L",",
  612. pIniPrinter->pLocation ?
  613. pIniPrinter->pLocation :
  614. szNull,
  615. NULL);
  616. if (dwRet != ERROR_SUCCESS) {
  617. pEnd = NULL;
  618. break;
  619. }
  620. if (!BoolFromHResult(StringCchCopy(printerString, COUNTOF(printerString), pIniPrinter->pName))) {
  621. pEnd = NULL;
  622. break;
  623. }
  624. }
  625. *pSourceStrings++=pszString;
  626. *pSourceStrings++=printerString;
  627. *pSourceStrings++=pIniPrinter->pComment;
  628. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter1, pOffsets, pEnd);
  629. FreeSplStr(pszString);
  630. pPrinter1->Flags = PRINTER_ENUM_ICON8;
  631. break;
  632. case 2:
  633. if (lpRemote) {
  634. *pSourceStrings++= lpRemote;
  635. if (!BoolFromHResult(StringCchPrintf(string, COUNTOF(string), L"%ws\\%ws", lpRemote, pIniPrinter->pName))){
  636. pEnd = NULL;
  637. break;
  638. }
  639. *pSourceStrings++=string;
  640. } else {
  641. *pSourceStrings++=NULL;
  642. *pSourceStrings++=pIniPrinter->pName;
  643. }
  644. *pSourceStrings++=pIniPrinter->pShareName;
  645. cbNeeded = 0;
  646. GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
  647. if (pszPorts = AllocSplMem(cbNeeded)) {
  648. GetPrinterPorts(pIniPrinter, pszPorts, &cbNeeded);
  649. *pSourceStrings++=pszPorts;
  650. *pSourceStrings++=pIniPrinter->pIniDriver->pName;
  651. *pSourceStrings++=pIniPrinter->pComment;
  652. *pSourceStrings++=pIniPrinter->pLocation;
  653. *pSourceStrings++=pIniPrinter->pSepFile;
  654. *pSourceStrings++=pIniPrinter->pIniPrintProc->pName;
  655. *pSourceStrings++=pIniPrinter->pDatatype;
  656. *pSourceStrings++=pIniPrinter->pParameters;
  657. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter2, pOffsets, pEnd);
  658. FreeSplMem(pszPorts);
  659. }
  660. else {
  661. pEnd = NULL;
  662. break;
  663. }
  664. if (pDevMode) {
  665. pEnd -= pDevMode->dmSize + pDevMode->dmDriverExtra;
  666. pEnd = (PBYTE)ALIGN_PTR_DOWN(pEnd);
  667. pPrinter2->pDevMode=(LPDEVMODE)pEnd;
  668. //
  669. // This is OK because GetPrinterSize has validated the buffer is big enough.
  670. //
  671. memcpy(pPrinter2->pDevMode, pDevMode, pDevMode->dmSize + pDevMode->dmDriverExtra);
  672. //
  673. // In the remote case, append the name of the server
  674. // in the devmode.dmDeviceName. This allows dmDeviceName
  675. // to always match win.ini's [devices] section.
  676. //
  677. FixDevModeDeviceName(lpRemote ? string : pIniPrinter->pName,
  678. pPrinter2->pDevMode,
  679. pIniPrinter->cbDevMode);
  680. } else {
  681. pPrinter2->pDevMode=NULL;
  682. }
  683. pPrinter2->Attributes = Attributes;
  684. pPrinter2->Priority = pIniPrinter->Priority;
  685. pPrinter2->DefaultPriority = pIniPrinter->DefaultPriority;
  686. pPrinter2->StartTime = pIniPrinter->StartTime;
  687. pPrinter2->UntilTime = pIniPrinter->UntilTime;
  688. if (pSecondPrinter2) {
  689. pPrinter2->cJobs = pSecondPrinter2->cJobs;
  690. pPrinter2->Status = pSecondPrinter2->Status;
  691. if( pIniPrinter->Status & PRINTER_PENDING_DELETION ){
  692. pPrinter2->Status |= PRINTER_STATUS_PENDING_DELETION;
  693. }
  694. } else {
  695. pPrinter2->cJobs=pIniPrinter->cJobs;
  696. pPrinter2->Status = MapPrinterStatus(MAP_READABLE,
  697. pIniPrinter->Status) |
  698. pIniPrinter->PortStatus;
  699. }
  700. pPrinter2->AveragePPM=pIniPrinter->AveragePPM;
  701. if( CopySecurityDescriptor ) {
  702. pEnd = CopyIniPrinterSecurityDescriptor(pIniPrinter,
  703. Level,
  704. pPrinterInfo,
  705. pEnd,
  706. GrantedAccess);
  707. } else {
  708. pPrinter2->pSecurityDescriptor = NULL;
  709. }
  710. break;
  711. case 3:
  712. pEnd = CopyIniPrinterSecurityDescriptor(pIniPrinter,
  713. Level,
  714. pPrinterInfo,
  715. pEnd,
  716. GrantedAccess);
  717. break;
  718. case 5:
  719. if (lpRemote) {
  720. if (!BoolFromHResult(StringCchPrintf(string, COUNTOF(string), L"%ws\\%ws", lpRemote, pIniPrinter->pName))) {
  721. pEnd = NULL;
  722. break;
  723. }
  724. *pSourceStrings++=string;
  725. } else {
  726. *pSourceStrings++=pIniPrinter->pName;
  727. }
  728. cbNeeded = 0;
  729. GetPrinterPorts(pIniPrinter, 0, &cbNeeded);
  730. if (pszPorts = AllocSplMem(cbNeeded)) {
  731. GetPrinterPorts(pIniPrinter, pszPorts, &cbNeeded);
  732. *pSourceStrings++ = pszPorts;
  733. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter5, pOffsets, pEnd);
  734. pPrinter5->Attributes = Attributes;
  735. pPrinter5->DeviceNotSelectedTimeout = pIniPrinter->dnsTimeout;
  736. pPrinter5->TransmissionRetryTimeout = pIniPrinter->txTimeout;
  737. FreeSplMem(pszPorts);
  738. }
  739. else
  740. pEnd = NULL;
  741. break;
  742. case 6:
  743. if (pSecondPrinter2) {
  744. pPrinter6->dwStatus = pSecondPrinter2->Status;
  745. if( pIniPrinter->Status & PRINTER_PENDING_DELETION ){
  746. pPrinter6->dwStatus |= PRINTER_STATUS_PENDING_DELETION;
  747. }
  748. } else {
  749. pPrinter6->dwStatus = MapPrinterStatus(MAP_READABLE,
  750. pIniPrinter->Status) |
  751. pIniPrinter->PortStatus;
  752. }
  753. break;
  754. case 7:
  755. *pSourceStrings++ = pIniPrinter->pszObjectGUID;
  756. pEnd = PackStrings(SourceStrings, (LPBYTE)pPrinter7, pOffsets, pEnd);
  757. if ( pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CACHE) {
  758. //
  759. // For connections, we rely directly on dwAction. The caching code
  760. // is the only one that updates dwAction in RefreshPrinterInfo7.
  761. //
  762. pPrinter7->dwAction = pIniPrinter->dwAction;
  763. } else {
  764. if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
  765. pPrinter7->dwAction = DSPRINT_PUBLISH;
  766. if (!pIniPrinter->pszObjectGUID ||
  767. pIniPrinter->DsKeyUpdate ||
  768. pIniPrinter->DsKeyUpdateForeground) {
  769. pPrinter7->dwAction |= DSPRINT_PENDING;
  770. }
  771. } else {
  772. pPrinter7->dwAction = DSPRINT_UNPUBLISH;
  773. if (pIniPrinter->pszObjectGUID ||
  774. (pIniPrinter->DsKeyUpdate & DS_KEY_UNPUBLISH) ||
  775. (pIniPrinter->DsKeyUpdateForeground & DS_KEY_UNPUBLISH)) {
  776. pPrinter7->dwAction |= DSPRINT_PENDING;
  777. }
  778. }
  779. }
  780. break;
  781. default:
  782. return pEnd;
  783. }
  784. return pEnd;
  785. }
  786. BOOL
  787. SplGetPrinter(
  788. HANDLE hPrinter,
  789. DWORD Level,
  790. LPBYTE pPrinter,
  791. DWORD cbBuf,
  792. LPDWORD pcbNeeded
  793. )
  794. {
  795. PSPOOL pSpool = (PSPOOL)hPrinter;
  796. BOOL AccessIsGranted = FALSE; // Must intialize
  797. PPRINTER_INFO_2 pSecondPrinter=NULL;
  798. LPBYTE pEnd;
  799. LPWSTR lpRemote;
  800. BOOL bReturn = FALSE;
  801. PDEVMODE pDevMode = NULL;
  802. PINIPRINTER pIniPrinter;
  803. BOOL bNt3xClient;
  804. PWSTR pszCN = NULL, pszDN = NULL;
  805. DWORD dwRet;
  806. EnterSplSem();
  807. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
  808. goto Cleanup;
  809. }
  810. pIniPrinter = pSpool->pIniPrinter;
  811. bNt3xClient = (pSpool->TypeofHandle & PRINTER_HANDLE_3XCLIENT);
  812. //
  813. // If Nt3x client we will converted devmode. If driver can't convert we will not return devmode
  814. //
  815. if ( bNt3xClient && Level == 2 && pIniPrinter->pDevMode ) {
  816. //
  817. // Call driver to get a Nt3x DevMode (if fails no devmode is given)
  818. //
  819. if (wcsstr(pSpool->pName, gszDrvConvert))
  820. pDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
  821. pIniPrinter->pDevMode,
  822. NULL,
  823. pSpool->pName,
  824. NT3X_VERSION);
  825. else
  826. pDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
  827. pIniPrinter->pDevMode,
  828. NULL,
  829. NULL,
  830. NT3X_VERSION);
  831. }
  832. SplInSem();
  833. if (( pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_DATA ) ||
  834. ( pSpool->pIniSpooler != pLocalIniSpooler )) {
  835. lpRemote = pSpool->pFullMachineName;
  836. } else {
  837. lpRemote = NULL;
  838. }
  839. switch (Level) {
  840. case STRESSINFOLEVEL:
  841. case 1:
  842. case 2:
  843. case 4:
  844. case 5:
  845. case 6:
  846. case 7:
  847. if ( !AccessGranted(SPOOLER_OBJECT_PRINTER,
  848. PRINTER_ACCESS_USE,
  849. pSpool) ) {
  850. SetLastError(ERROR_ACCESS_DENIED);
  851. goto Cleanup;
  852. }
  853. break;
  854. case 3:
  855. if (!AreAnyAccessesGranted(pSpool->GrantedAccess,
  856. READ_CONTROL | ACCESS_SYSTEM_SECURITY)) {
  857. SetLastError(ERROR_ACCESS_DENIED);
  858. goto Cleanup;
  859. }
  860. break;
  861. default:
  862. break;
  863. }
  864. if (pSpool->pIniPort && !(pSpool->pIniPort->Status & PP_MONITOR)) {
  865. HANDLE hPort = pSpool->hPort;
  866. if (hPort == INVALID_PORT_HANDLE) {
  867. DBGMSG(DBG_WARNING, ("GetPrinter called with bad port handle. Setting error %d\n",
  868. pSpool->OpenPortError));
  869. //
  870. // If this value is 0, then when we return GetLastError,
  871. // the client will think we succeeded.
  872. //
  873. SPLASSERT(pSpool->OpenPortError);
  874. goto PartialSuccess;
  875. }
  876. LeaveSplSem();
  877. if ((Level == 2 || Level == 6)) {
  878. if (!RetrieveMasqPrinterInfo(pSpool, &pSecondPrinter)) {
  879. goto CleanupFromOutsideSplSem;
  880. }
  881. }
  882. EnterSplSem();
  883. /* Re-validate the handle, since it might possibly have been closed
  884. * while we were outside the semaphore:
  885. */
  886. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
  887. goto Cleanup;
  888. }
  889. }
  890. PartialSuccess:
  891. *pcbNeeded = GetPrinterSize(pIniPrinter, Level, 0, lpRemote,
  892. bNt3xClient ? pDevMode : pIniPrinter->pDevMode);
  893. if (*pcbNeeded > cbBuf) {
  894. DBGMSG(DBG_TRACE, ("SplGetPrinter Failure with ERROR_INSUFFICIENT_BUFFER cbBuf is %d and pcbNeeded is %d\n", cbBuf, *pcbNeeded));
  895. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  896. goto Cleanup;
  897. }
  898. pEnd = CopyIniPrinterToPrinter(pIniPrinter, Level, pPrinter,
  899. pPrinter+cbBuf, pSecondPrinter,
  900. lpRemote,
  901. TRUE, pSpool->GrantedAccess,
  902. bNt3xClient ? pDevMode : pIniPrinter->pDevMode);
  903. if ( pEnd != NULL)
  904. bReturn = TRUE;
  905. Cleanup:
  906. LeaveSplSem();
  907. CleanupFromOutsideSplSem:
  908. SplOutSem();
  909. FreeSplMem(pSecondPrinter);
  910. FreeSplMem(pDevMode);
  911. if ( bReturn == FALSE ) {
  912. SPLASSERT(GetLastError() != ERROR_SUCCESS);
  913. }
  914. return bReturn;
  915. }
  916. BOOL
  917. EnumerateNetworkPrinters(
  918. LPBYTE pPrinter,
  919. DWORD cbBuf,
  920. LPDWORD pcbNeeded,
  921. LPDWORD pcReturned,
  922. PINISPOOLER pIniSpooler
  923. )
  924. {
  925. PININETPRINT pIniNetPrint;
  926. DWORD cb;
  927. LPBYTE pEnd;
  928. BOOL bReturnValue = FALSE;
  929. EnterSplSem();
  930. //
  931. // All network printers reside in pLocalIniSpooler to avoid
  932. // duplicates.
  933. //
  934. RemoveOldNetPrinters( NULL, pLocalIniSpooler );
  935. //
  936. // If the Server has not been up long enough, then fail
  937. // so the client will ask another Server for the Browse List.
  938. //
  939. if ( bNetInfoReady == FALSE ) {
  940. SetLastError( ERROR_CAN_NOT_COMPLETE );
  941. goto Done;
  942. }
  943. cb = 0;
  944. pIniNetPrint = pIniSpooler->pIniNetPrint;
  945. while (pIniNetPrint) {
  946. cb += GetIniNetPrintSize( pIniNetPrint );
  947. pIniNetPrint = pIniNetPrint->pNext;
  948. }
  949. *pcbNeeded = cb;
  950. if (cb > cbBuf) {
  951. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  952. goto Done;
  953. }
  954. pIniNetPrint = pIniSpooler->pIniNetPrint;
  955. pEnd = pPrinter + cbBuf;
  956. while ( pIniNetPrint ) {
  957. pEnd = CopyIniNetPrintToPrinter( pIniNetPrint, pPrinter, pEnd );
  958. (*pcReturned)++;
  959. pPrinter += sizeof(PRINTER_INFO_1);
  960. pIniNetPrint = pIniNetPrint->pNext;
  961. }
  962. if ( *pcReturned == 0 ) {
  963. bNetInfoReady = FALSE;
  964. FirstAddNetPrinterTickCount = 0;
  965. SetLastError( ERROR_CAN_NOT_COMPLETE );
  966. DBGMSG( DBG_TRACE, ("EnumerateNetworkPrinters returning ERROR_CAN_NOT_COMPELTE becase there is no browse list\n"));
  967. } else {
  968. pIniSpooler->cEnumerateNetworkPrinters++; // Stats only
  969. bReturnValue = TRUE;
  970. DBGMSG( DBG_TRACE, (" EnumerateNetworkPrnters called %d times returning %d printers\n", pIniSpooler->cEnumerateNetworkPrinters, *pcReturned ));
  971. }
  972. Done:
  973. LeaveSplSem();
  974. SplOutSem();
  975. return bReturnValue;
  976. }
  977. /*++
  978. Routine Name
  979. UpdateSpoolersRef
  980. Routine Description:
  981. Does and AddRef or a DecRef on all pIniSpooler matching a certain criteria
  982. Arguments:
  983. SpoolerType - Type of pIniSpoolers which to addref/decref
  984. (Ex. SPL_TYPE_CLUSTER | SPL_TYPE_LOCAL)
  985. bAddRef - TRUE means AddRef, FALSE means DecRef
  986. Return Value:
  987. None
  988. --*/
  989. VOID
  990. UpdateSpoolersRef(
  991. IN DWORD SpoolerType,
  992. IN BOOL bAddRef
  993. )
  994. {
  995. PINISPOOLER pIniSpooler;
  996. EnterSplSem();
  997. //
  998. // AddRef or DecRef all local and cluster spoolers
  999. //
  1000. for (pIniSpooler = pLocalIniSpooler; pIniSpooler; pIniSpooler = pIniSpooler->pIniNextSpooler)
  1001. {
  1002. if (pIniSpooler->SpoolerFlags & SpoolerType)
  1003. {
  1004. if (bAddRef)
  1005. {
  1006. INCSPOOLERREF(pIniSpooler);
  1007. }
  1008. else
  1009. {
  1010. DECSPOOLERREF(pIniSpooler);
  1011. }
  1012. }
  1013. }
  1014. LeaveSplSem();
  1015. }
  1016. /*++
  1017. Routine Name
  1018. SplEnumAllClusterPrinters
  1019. Routine Description:
  1020. Enumerates all printers in the local spooler and all cluster
  1021. spoolers hosted by localspl at the time of the call.
  1022. Arguments:
  1023. InputFlags - combination of ENUM_PRINTER_xxx
  1024. pszInputName - name of the print provider
  1025. Level - level of the call
  1026. pPrinter - buffer to hold the PRINTER_INFO_xxx structures
  1027. cbInputBufSize - size of pPrinter buffer
  1028. pcbNeeded - bytes required to hold all the printer info structures
  1029. pcReturned - number of structures returned by this function
  1030. Return Value:
  1031. TRUE - cal succeeded
  1032. FALSE - an error occurred, the function sets the last error
  1033. --*/
  1034. BOOL
  1035. SplEnumAllClusterPrinters(
  1036. DWORD InputFlags,
  1037. LPWSTR pszInputName,
  1038. DWORD Level,
  1039. LPBYTE pPrinter,
  1040. DWORD cbInputBufSize,
  1041. LPDWORD pcbNeeded,
  1042. LPDWORD pcReturned
  1043. )
  1044. {
  1045. PINISPOOLER pIniSpooler;
  1046. DWORD cbBuf = cbInputBufSize;
  1047. DWORD cTotalReturned = 0;
  1048. DWORD cbTotalNeeded = 0;
  1049. DWORD dwError = ERROR_SUCCESS;
  1050. DWORD cbStruct;
  1051. switch (Level)
  1052. {
  1053. case STRESSINFOLEVEL:
  1054. cbStruct = sizeof(PRINTER_INFO_STRESS);
  1055. break;
  1056. case 1:
  1057. cbStruct = sizeof(PRINTER_INFO_1);
  1058. break;
  1059. case 2:
  1060. cbStruct = sizeof(PRINTER_INFO_2);
  1061. break;
  1062. case 4:
  1063. cbStruct = sizeof(PRINTER_INFO_4);
  1064. break;
  1065. case 5:
  1066. cbStruct = sizeof(PRINTER_INFO_5);
  1067. break;
  1068. default:
  1069. dwError = ERROR_INVALID_LEVEL;
  1070. }
  1071. if (dwError == ERROR_SUCCESS)
  1072. {
  1073. //
  1074. // AddRef all ini spoolers
  1075. //
  1076. UpdateSpoolersRef(SPL_TYPE_LOCAL | SPL_TYPE_CLUSTER, TRUE);
  1077. //
  1078. // Enumerate all the printers
  1079. //
  1080. for (pIniSpooler = pLocalIniSpooler; pIniSpooler; pIniSpooler = pIniSpooler->pIniNextSpooler)
  1081. {
  1082. if (pIniSpooler->SpoolerFlags & (SPL_TYPE_LOCAL | SPL_TYPE_CLUSTER))
  1083. {
  1084. DWORD cReturned;
  1085. DWORD cbNeeded;
  1086. DWORD Flags = InputFlags;
  1087. LPWSTR pszName = pszInputName;
  1088. //
  1089. // For clusters force the printer name to be fully qualified
  1090. //
  1091. if (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER)
  1092. {
  1093. Flags |= PRINTER_ENUM_NAME;
  1094. pszName = pIniSpooler->pMachineName;
  1095. }
  1096. if (SplEnumPrinters(Flags,
  1097. pszName,
  1098. Level,
  1099. pPrinter,
  1100. cbBuf,
  1101. &cbNeeded,
  1102. &cReturned,
  1103. pIniSpooler))
  1104. {
  1105. cTotalReturned += cReturned;
  1106. cbBuf -= cbNeeded;
  1107. pPrinter += cReturned * cbStruct;
  1108. }
  1109. else
  1110. {
  1111. dwError = GetLastError();
  1112. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  1113. {
  1114. cbBuf = 0;
  1115. }
  1116. else
  1117. {
  1118. //
  1119. // We cannot continue on an error different than insufficient buffer
  1120. //
  1121. break;
  1122. }
  1123. }
  1124. cbTotalNeeded += cbNeeded;
  1125. }
  1126. }
  1127. //
  1128. // DecRef all ini spoolers
  1129. //
  1130. UpdateSpoolersRef(SPL_TYPE_LOCAL | SPL_TYPE_CLUSTER, FALSE);
  1131. //
  1132. // Update out variables
  1133. //
  1134. if (dwError == ERROR_SUCCESS)
  1135. {
  1136. *pcbNeeded = cbTotalNeeded;
  1137. *pcReturned = cTotalReturned;
  1138. }
  1139. else if (dwError == ERROR_INSUFFICIENT_BUFFER)
  1140. {
  1141. *pcbNeeded = cbTotalNeeded;
  1142. }
  1143. else
  1144. {
  1145. SetLastError(dwError);
  1146. }
  1147. }
  1148. return dwError == ERROR_SUCCESS;
  1149. }
  1150. /*
  1151. EnumPrinters can be called with the following combinations:
  1152. Flags Name Meaning
  1153. PRINTER_ENUM_LOCAL NULL Enumerate all Printers on this machine
  1154. PRINTER_ENUM_NAME MachineName Enumerate all Printers on this machine
  1155. PRINTER_ENUM_NAME | MachineName Enumerate all shared Printers on this
  1156. PRINTER_ENUM_SHARED MachineName machine
  1157. PRINTER_ENUM_NETWORK MachineName Enumerate all added remote printers
  1158. PRINTER_ENUM_REMOTE ? Return error - let win32spl handle it
  1159. PRINTER_ENUM_NAME NULL Give back Print Providor name
  1160. PRINTER_ENUM_NAME "Windows NT Local Print Providor"
  1161. same as PRINTER_ENUM_LOCAL
  1162. It is not an error if no known flag is specified.
  1163. In this case we just return TRUE without any data
  1164. (This is so that other print providers may define
  1165. their own flags.)
  1166. */
  1167. BOOL
  1168. LocalEnumPrinters(
  1169. DWORD Flags,
  1170. LPWSTR pName,
  1171. DWORD Level,
  1172. LPBYTE pPrinter,
  1173. DWORD cbBuf,
  1174. LPDWORD pcbNeeded,
  1175. LPDWORD pcReturned
  1176. )
  1177. {
  1178. BOOL bReturn = ROUTER_UNKNOWN;
  1179. if (Flags & PRINTER_ENUM_CLUSTER)
  1180. {
  1181. bReturn = SplEnumAllClusterPrinters(Flags,
  1182. pName,
  1183. Level,
  1184. pPrinter,
  1185. cbBuf,
  1186. pcbNeeded,
  1187. pcReturned);
  1188. }
  1189. else
  1190. {
  1191. PINISPOOLER pIniSpooler;
  1192. //
  1193. // Mask cluster flag
  1194. //
  1195. Flags &= ~PRINTER_ENUM_CLUSTER;
  1196. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  1197. if (pIniSpooler)
  1198. {
  1199. bReturn = SplEnumPrinters(Flags,
  1200. pName,
  1201. Level,
  1202. pPrinter,
  1203. cbBuf,
  1204. pcbNeeded,
  1205. pcReturned,
  1206. pIniSpooler);
  1207. FindSpoolerByNameDecRef(pIniSpooler);
  1208. }
  1209. }
  1210. return bReturn;
  1211. }
  1212. BOOL
  1213. EnumThisPrinter(
  1214. DWORD Flags,
  1215. PINIPRINTER pIniPrinter,
  1216. PINISPOOLER pIniSpooler
  1217. )
  1218. {
  1219. //
  1220. // If they only want shared Printers
  1221. //
  1222. if ( (Flags & PRINTER_ENUM_SHARED) &&
  1223. !(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) )
  1224. return FALSE;
  1225. //
  1226. // Only allow them to see printers which are being deleted if they have jobs
  1227. // This allows remote admin to work well.
  1228. if ( (pIniPrinter->Status & PRINTER_PENDING_DELETION) &&
  1229. pIniPrinter->cJobs == 0 )
  1230. return FALSE;
  1231. //
  1232. // Don't count printers which are partially created
  1233. //
  1234. if ( pIniPrinter->Status & PRINTER_PENDING_CREATION )
  1235. return FALSE;
  1236. return TRUE;
  1237. }
  1238. BOOL
  1239. SplEnumPrinters(
  1240. DWORD Flags,
  1241. LPWSTR Name,
  1242. DWORD Level,
  1243. LPBYTE pPrinter,
  1244. DWORD cbBuf,
  1245. LPDWORD pcbNeeded,
  1246. LPDWORD pcReturned,
  1247. PINISPOOLER pIniSpooler
  1248. )
  1249. {
  1250. PINIPRINTER pIniPrinter;
  1251. PPRINTER_INFO_1 pPrinter1=(PPRINTER_INFO_1)pPrinter;
  1252. DWORD cb;
  1253. LPBYTE pEnd;
  1254. LPWSTR lpRemote;
  1255. *pcbNeeded = 0;
  1256. *pcReturned = 0;
  1257. if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
  1258. SERVER_ACCESS_ENUMERATE,
  1259. NULL, NULL, pIniSpooler )) {
  1260. return FALSE;
  1261. }
  1262. if ( Flags & PRINTER_ENUM_NAME ) {
  1263. if ( Name && *Name ) {
  1264. if (lstrcmpi(Name, szPrintProvidorName) && !MyName( Name, pIniSpooler)) {
  1265. return FALSE;
  1266. }
  1267. // If it's PRINTER_ENUM_NAME of our name,
  1268. // do the same as PRINTER_ENUM_LOCAL:
  1269. Flags |= PRINTER_ENUM_LOCAL;
  1270. // Also if it is for us then ignore the REMOTE flag.
  1271. // Otherwise the call will get passed to Win32Spl which
  1272. // will end up calling us back forever.
  1273. Flags &= ~PRINTER_ENUM_REMOTE;
  1274. }
  1275. }
  1276. if ( Flags & PRINTER_ENUM_REMOTE ) {
  1277. SetLastError( ERROR_INVALID_NAME );
  1278. return FALSE;
  1279. }
  1280. lpRemote = NULL;
  1281. if ( Name && *Name ) {
  1282. if ( MyName( Name, pIniSpooler ) ) {
  1283. lpRemote = Name;
  1284. }
  1285. }
  1286. if ((Level == 1) && (Flags & PRINTER_ENUM_NETWORK)) {
  1287. SplOutSem();
  1288. return EnumerateNetworkPrinters( pPrinter, cbBuf, pcbNeeded, pcReturned, pIniSpooler );
  1289. }
  1290. EnterSplSem();
  1291. if ((Level == 1 ) && (Flags & PRINTER_ENUM_NAME) && !Name) {
  1292. LPWSTR SourceStrings[sizeof(PRINTER_INFO_1)/sizeof(LPWSTR)];
  1293. LPWSTR *pSourceStrings=SourceStrings;
  1294. cb = wcslen(szPrintProvidorName)*sizeof(WCHAR) + sizeof(WCHAR) +
  1295. wcslen(szPrintProvidorDescription)*sizeof(WCHAR) + sizeof(WCHAR) +
  1296. wcslen(szPrintProvidorComment)*sizeof(WCHAR) + sizeof(WCHAR) +
  1297. sizeof(PRINTER_INFO_1);
  1298. *pcbNeeded=cb;
  1299. if (cb > cbBuf) {
  1300. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1301. LeaveSplSem();
  1302. return FALSE;
  1303. }
  1304. *pcReturned = 1;
  1305. pPrinter1->Flags = PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON1;
  1306. *pSourceStrings++=szPrintProvidorDescription;
  1307. *pSourceStrings++=szPrintProvidorName;
  1308. *pSourceStrings++=szPrintProvidorComment;
  1309. PackStrings(SourceStrings, pPrinter, PrinterInfo1Strings,
  1310. pPrinter+cbBuf);
  1311. LeaveSplSem();
  1312. return TRUE;
  1313. }
  1314. cb=0;
  1315. if (Flags & (PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME)) {
  1316. //
  1317. // For remote user's who are not admins enumerate shared printers only
  1318. //
  1319. if ( S_FALSE == CheckLocalCall() &&
  1320. !(Flags & PRINTER_ENUM_SHARED) &&
  1321. !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  1322. SERVER_ACCESS_ADMINISTER,
  1323. NULL,
  1324. NULL,
  1325. pIniSpooler) )
  1326. Flags |= PRINTER_ENUM_SHARED;
  1327. //
  1328. // Calculate the size required
  1329. //
  1330. for ( pIniPrinter = pIniSpooler->pIniPrinter;
  1331. pIniPrinter != NULL;
  1332. pIniPrinter = pIniPrinter->pNext ) {
  1333. if ( EnumThisPrinter(Flags, pIniPrinter, pIniSpooler) && ShowThisPrinter(pIniPrinter, NULL))
  1334. cb += GetPrinterSize(pIniPrinter, Level, Flags,
  1335. lpRemote, pIniPrinter->pDevMode);
  1336. }
  1337. }
  1338. *pcbNeeded=cb;
  1339. if (cb > cbBuf) {
  1340. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1341. LeaveSplSem();
  1342. return FALSE;
  1343. }
  1344. if (Flags & (PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME)) {
  1345. for ( pIniPrinter = pIniSpooler->pIniPrinter, pEnd = pPrinter + cbBuf;
  1346. pIniPrinter != NULL;
  1347. pIniPrinter = pIniPrinter->pNext ) {
  1348. if ( !EnumThisPrinter(Flags, pIniPrinter, pIniSpooler) )
  1349. continue;
  1350. //
  1351. // Do not list printers without access
  1352. if( !ShowThisPrinter(pIniPrinter, NULL) ) {
  1353. continue;
  1354. }
  1355. pEnd = CopyIniPrinterToPrinter( pIniPrinter, Level, pPrinter,
  1356. pEnd, NULL, lpRemote, FALSE, 0,
  1357. pIniPrinter->pDevMode );
  1358. if (!pEnd) {
  1359. LeaveSplSem();
  1360. return FALSE;
  1361. }
  1362. (*pcReturned)++;
  1363. switch (Level) {
  1364. case STRESSINFOLEVEL:
  1365. pPrinter+=sizeof(PRINTER_INFO_STRESS);
  1366. break;
  1367. case 1:
  1368. pPrinter+=sizeof(PRINTER_INFO_1);
  1369. break;
  1370. case 2:
  1371. pPrinter+=sizeof(PRINTER_INFO_2);
  1372. break;
  1373. case 4:
  1374. pPrinter+=sizeof(PRINTER_INFO_4);
  1375. break;
  1376. case 5:
  1377. pPrinter+=sizeof(PRINTER_INFO_5);
  1378. break;
  1379. }
  1380. }
  1381. }
  1382. LeaveSplSem();
  1383. return TRUE;
  1384. }
  1385. /* ShowThisPrinter
  1386. *
  1387. * Returns whether this printer should be visible to the current
  1388. * user.
  1389. *
  1390. * We do not show printers that the caller does not
  1391. * have access to. This is for two reasons:
  1392. *
  1393. * 1: A multi-user system with 200 users each with their
  1394. * own client printers would cause a large confusing
  1395. * list of printers from within applications such as word.
  1396. * "Client" printers are owned by the user of that station,
  1397. * and by default only allow print access for that user.
  1398. * This provides a simple way of filtering printers to show
  1399. * to the user for a selection.
  1400. *
  1401. * 2: Programs such as Windows write get confused when
  1402. * they see a printer they can not open. This is a bad
  1403. * program, since normal NT can have a printer denied to a user, but we must
  1404. * make it work anyway.
  1405. *
  1406. *
  1407. * Must work out security modes!
  1408. *
  1409. * Parameters
  1410. *
  1411. * pIniPrinter - A pointer to the spooler's internal data structure
  1412. * for the printer concerned.
  1413. * hToken - An optional pointer to the token for the user we are
  1414. wanting to make the test for.
  1415. */
  1416. BOOL
  1417. ShowThisPrinter(
  1418. IN PINIPRINTER pIniPrinter,
  1419. IN HANDLE hToken OPTIONAL
  1420. )
  1421. {
  1422. LPWSTR pObjectName;
  1423. BOOL bRet = TRUE;
  1424. BOOL AccessStatus = TRUE;
  1425. HANDLE hClientToken = NULL;
  1426. ACCESS_MASK MappedDesiredAccess;
  1427. DWORD GrantedAccess = 0;
  1428. PBOOL pGenerateOnClose;
  1429. BYTE PrivilegeSetBuffer[256];
  1430. DWORD PrivilegeSetBufferLength = 256;
  1431. PPRIVILEGE_SET pPrivilegeSet;
  1432. DWORD dwRetCode;
  1433. PTOKEN_PRIVILEGES pPreviousTokenPrivileges;
  1434. DWORD PreviousTokenPrivilegesLength;
  1435. //
  1436. // External references to global variables in security.c
  1437. //
  1438. extern GENERIC_MAPPING GenericMapping[];
  1439. extern WCHAR *szSpooler;
  1440. //
  1441. // If Hydra is not enabled, keep NT behavior unchanged
  1442. //
  1443. if( !(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer)) )
  1444. {
  1445. bRet = TRUE;
  1446. }
  1447. else
  1448. {
  1449. //
  1450. // If we weren't passed in a token handle, then use the current
  1451. // impersonation token or the process token.
  1452. //
  1453. if (!hToken)
  1454. {
  1455. bRet = GetTokenHandle(&hClientToken);
  1456. }
  1457. else
  1458. {
  1459. hClientToken = hToken;
  1460. }
  1461. //
  1462. // Administrators see all printers. This allows an
  1463. // Admin to take ownership of a printer whose ACL is
  1464. // messed up.
  1465. //
  1466. if (bRet)
  1467. {
  1468. bRet = ValidateObjectAccessWithToken(hClientToken, SPOOLER_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL, pIniPrinter->pIniSpooler);
  1469. if (!bRet)
  1470. {
  1471. MapGenericToSpecificAccess(SPOOLER_OBJECT_PRINTER, PRINTER_ACCESS_USE, &MappedDesiredAccess);
  1472. pPrivilegeSet = (PPRIVILEGE_SET)PrivilegeSetBuffer;
  1473. //
  1474. // Call AccessCheck followed by ObjectOpenAuditAlarm rather than
  1475. // AccessCheckAndAuditAlarm, because we may need to enable
  1476. // SeSecurityPrivilege in order to check for ACCESS_SYSTEM_SECURITY
  1477. // privilege. We must ensure that the security access-checking
  1478. // API has the actual token whose security privilege we have enabled.
  1479. // AccessCheckAndAuditAlarm is no good for this, because it opens
  1480. // the client's token again, which may not have the privilege enabled.
  1481. //
  1482. // We do not audit and set off alarms because the caller
  1483. // did not really try and open the printer.
  1484. // We the server tried to check access for display purposes, not
  1485. // for handle create.
  1486. //
  1487. bRet = AccessCheck(pIniPrinter->pSecurityDescriptor,
  1488. hClientToken,
  1489. MappedDesiredAccess,
  1490. &GenericMapping[SPOOLER_OBJECT_PRINTER],
  1491. pPrivilegeSet,
  1492. &PrivilegeSetBufferLength,
  1493. &GrantedAccess,
  1494. &AccessStatus);
  1495. //
  1496. // If the access check failed, but it was because we didn't have an
  1497. // impersonation token, then we can view the printer.
  1498. //
  1499. if (!bRet)
  1500. {
  1501. if (GetLastError() == ERROR_NO_IMPERSONATION_TOKEN)
  1502. {
  1503. bRet = TRUE;
  1504. DBGMSG( DBG_ERROR, ("ShowThisPrinter: No impersonation token. Printer will be enumerated\n"));
  1505. }
  1506. else
  1507. {
  1508. DBGMSG( DBG_TRACE, ("ShowThisPrinter: Printer %ws Not accessable by caller Access Check failuer %d\n",pIniPrinter->pName,GetLastError()));
  1509. }
  1510. }
  1511. else if (!AccessStatus)
  1512. {
  1513. DBGMSG( DBG_TRACE, ("ShowThisPrinter: Printer %ws Not accessable by caller AccessStatus failure %d\n",pIniPrinter->pName,GetLastError()));
  1514. bRet = FALSE;
  1515. }
  1516. }
  1517. }
  1518. }
  1519. //
  1520. // If we have a client token and one was not passed in, then close the token
  1521. // handle.
  1522. //
  1523. if (hClientToken && !hToken)
  1524. {
  1525. CloseHandle(hClientToken);
  1526. }
  1527. return bRet;
  1528. }
  1529. /*++
  1530. Routine Name:
  1531. RetrieveMasqPrinterInfo
  1532. Description:
  1533. This retrieves Masq information for the printer, it is either cached state
  1534. or a direct call into the provider depending on Reg Settings.
  1535. Arguments:
  1536. pSpool - The spool handle that we use for synchronisation.
  1537. ppPrinterInfo - The returned printer info.
  1538. Returns:
  1539. A Boolean, if FALSE, last error is set.
  1540. --*/
  1541. BOOL
  1542. RetrieveMasqPrinterInfo(
  1543. IN PSPOOL pSpool,
  1544. OUT PRINTER_INFO_2 **ppPrinterInfo
  1545. )
  1546. {
  1547. BOOL bRet = TRUE;
  1548. PINIPRINTER pIniPrinter = NULL;
  1549. pIniPrinter = pSpool->pIniPrinter;
  1550. SplOutSem();
  1551. if (!(pSpool->pIniSpooler->dwSpoolerSettings & SPOOLER_CACHEMASQPRINTERS))
  1552. {
  1553. //
  1554. // Just synchronously return the data from the partial print provider.
  1555. //
  1556. bRet = BoolFromStatus(GetPrinterInfoFromRouter(pSpool->hPort, ppPrinterInfo));
  1557. }
  1558. else
  1559. {
  1560. //
  1561. // Kick off the thread that goes and reads the masq status.
  1562. //
  1563. BOOL bCreateThread = FALSE;
  1564. PRINTER_INFO_2 *pPrinterInfo2 = NULL;
  1565. EnterSplSem();
  1566. if (!pIniPrinter->MasqCache.bThreadRunning)
  1567. {
  1568. bCreateThread = TRUE;
  1569. pIniPrinter->MasqCache.bThreadRunning = TRUE;
  1570. INCPRINTERREF(pIniPrinter);
  1571. }
  1572. LeaveSplSem();
  1573. SplOutSem();
  1574. if (bCreateThread)
  1575. {
  1576. HANDLE hThread = NULL;
  1577. MasqUpdateThreadData *pThreadData = NULL;
  1578. DWORD dwThreadId = 0;
  1579. pThreadData = AllocSplMem(sizeof(*pThreadData));
  1580. bRet = pThreadData != NULL;
  1581. if (bRet)
  1582. {
  1583. bRet = GetSid(&pThreadData->hUserToken);
  1584. }
  1585. if (bRet)
  1586. {
  1587. pThreadData->pIniPrinter = pIniPrinter;
  1588. hThread = CreateThread(NULL, 0, AsyncPopulateMasqPrinterCache, (VOID *)pThreadData, 0, &dwThreadId);
  1589. bRet = hThread != NULL;
  1590. }
  1591. if (bRet)
  1592. {
  1593. pThreadData = NULL;
  1594. }
  1595. //
  1596. // If we couldn't create the thread, then drop the ref count on the
  1597. // pIniPrinter again and set thread running to false.
  1598. //
  1599. if (!bRet)
  1600. {
  1601. EnterSplSem();
  1602. pIniPrinter->MasqCache.bThreadRunning = FALSE;
  1603. DECPRINTERREF(pIniPrinter);
  1604. LeaveSplSem();
  1605. }
  1606. if (hThread)
  1607. {
  1608. CloseHandle(hThread);
  1609. }
  1610. if (pThreadData)
  1611. {
  1612. if (pThreadData->hUserToken)
  1613. {
  1614. CloseHandle(pThreadData->hUserToken);
  1615. }
  1616. FreeSplMem(pThreadData);
  1617. }
  1618. }
  1619. //
  1620. // Check to see the cached error return for the printer.
  1621. //
  1622. if (bRet)
  1623. {
  1624. EnterSplSem();
  1625. if (pIniPrinter->MasqCache.dwError != ERROR_SUCCESS)
  1626. {
  1627. SetLastError(pIniPrinter->MasqCache.dwError);
  1628. bRet = FALSE;
  1629. }
  1630. //
  1631. // Caller is only interested in the Status and cJobs members, all strings
  1632. // are set to NULL by the allocation.
  1633. //
  1634. if (bRet)
  1635. {
  1636. pPrinterInfo2 = AllocSplMem(sizeof(PRINTER_INFO_2));
  1637. bRet = pPrinterInfo2 != NULL;
  1638. }
  1639. if (bRet)
  1640. {
  1641. pPrinterInfo2->Status = pIniPrinter->MasqCache.Status;
  1642. pPrinterInfo2->cJobs = pIniPrinter->MasqCache.cJobs;
  1643. *ppPrinterInfo = pPrinterInfo2;
  1644. pPrinterInfo2 = NULL;
  1645. }
  1646. LeaveSplSem();
  1647. }
  1648. FreeSplMem(pPrinterInfo2);
  1649. }
  1650. return bRet;
  1651. }
  1652. /*++
  1653. Routine Name:
  1654. GetPrinterInfoFromRouter
  1655. Description:
  1656. This does a GetPrinter call against the router, it returns the error code
  1657. as a status.
  1658. Arguments:
  1659. hMasqPrinter - Handle to the masq printer.
  1660. ppPrinterInfo - Returned printer info.
  1661. Returns:
  1662. Status Code.
  1663. --*/
  1664. DWORD
  1665. GetPrinterInfoFromRouter(
  1666. IN HANDLE hMasqPrinter,
  1667. OUT PRINTER_INFO_2 **ppPrinterInfo
  1668. )
  1669. {
  1670. DWORD Status = ERROR_SUCCESS;
  1671. DWORD cb = 4096;
  1672. PRINTER_INFO_2 *pPrinterInfo2 = NULL;
  1673. DWORD cbNeeded;
  1674. SplOutSem();
  1675. pPrinterInfo2 = AllocSplMem(cb);
  1676. Status = pPrinterInfo2 != NULL ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
  1677. if (ERROR_SUCCESS == Status)
  1678. {
  1679. Status = GetPrinter(hMasqPrinter, 2, (BYTE *)pPrinterInfo2, cb, &cbNeeded) ? ERROR_SUCCESS : GetLastError();
  1680. }
  1681. if (ERROR_INSUFFICIENT_BUFFER == Status)
  1682. {
  1683. FreeSplMem(pPrinterInfo2);
  1684. pPrinterInfo2 = NULL;
  1685. cb = cbNeeded;
  1686. pPrinterInfo2 = AllocSplMem(cb);
  1687. Status = pPrinterInfo2 != NULL ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
  1688. if (ERROR_SUCCESS == Status)
  1689. {
  1690. Status = GetPrinter(hMasqPrinter, 2, (BYTE *)pPrinterInfo2, cb, &cbNeeded) ? ERROR_SUCCESS : GetLastError();
  1691. }
  1692. }
  1693. if (ERROR_SUCCESS == Status)
  1694. {
  1695. *ppPrinterInfo = pPrinterInfo2;
  1696. pPrinterInfo2 = NULL;
  1697. }
  1698. FreeSplMem(pPrinterInfo2);
  1699. return Status;
  1700. }
  1701. /*++
  1702. Routine Name:
  1703. AsyncPopulateMasqPrinterCache
  1704. Description:
  1705. This populates the Masq printer cache for a given pIniPrinter.
  1706. Arguments:
  1707. pvThreadData - Pointer to a MasqUpdateThreadData structure
  1708. Returns:
  1709. A DWORD status, ignored.
  1710. --*/
  1711. DWORD
  1712. AsyncPopulateMasqPrinterCache(
  1713. IN VOID *pvThreadData
  1714. )
  1715. {
  1716. DWORD Status = ERROR_SUCCESS;
  1717. PINIPRINTER pIniPrinter = NULL;
  1718. PINIPORT pIniPort = NULL;
  1719. PWSTR pszPrinterName = NULL;
  1720. HANDLE hMasqPrinter = NULL;
  1721. PRINTER_INFO_2 *pPrinterInfo2 = NULL;
  1722. MasqUpdateThreadData *pThreadData = NULL;
  1723. SplOutSem();
  1724. pThreadData = (MasqUpdateThreadData *)pvThreadData;
  1725. pIniPrinter = pThreadData->pIniPrinter;
  1726. Status = SetCurrentSid(pThreadData->hUserToken) ? ERROR_SUCCESS : GetLastError();
  1727. EnterSplSem();
  1728. //
  1729. // Find the port associated with the printer.
  1730. //
  1731. if (Status == ERROR_SUCCESS)
  1732. {
  1733. pIniPort = FindIniPortFromIniPrinter(pIniPrinter);
  1734. Status = pIniPort && !(pIniPort->Status & PP_MONITOR) ? ERROR_SUCCESS : ERROR_INVALID_FUNCTION;
  1735. }
  1736. if (Status == ERROR_SUCCESS)
  1737. {
  1738. INCPORTREF(pIniPort);
  1739. LeaveSplSem();
  1740. SplOutSem();
  1741. //
  1742. // This relies on the fact that a masq port cannot be renamed.
  1743. //
  1744. if (OpenPrinterPortW(pIniPort->pName, &hMasqPrinter, NULL))
  1745. {
  1746. //
  1747. // This will propogate any errors into the masq cache, which we
  1748. // don't have to do twice, so we ignore the return code.
  1749. //
  1750. Status = GetPrinterInfoFromRouter(hMasqPrinter, &pPrinterInfo2);
  1751. ClosePrinter(hMasqPrinter);
  1752. }
  1753. else
  1754. {
  1755. Status = GetLastError();
  1756. if (Status == ERROR_SUCCESS)
  1757. {
  1758. Status = ERROR_UNEXP_NET_ERR;
  1759. }
  1760. }
  1761. EnterSplSem();
  1762. if (ERROR_SUCCESS == Status)
  1763. {
  1764. pIniPrinter->MasqCache.cJobs = pPrinterInfo2->cJobs;
  1765. pIniPrinter->MasqCache.Status = pPrinterInfo2->Status;
  1766. }
  1767. else
  1768. {
  1769. pIniPrinter->MasqCache.cJobs = 0;
  1770. pIniPrinter->MasqCache.Status = 0;
  1771. }
  1772. //
  1773. // We always want to reset the status.
  1774. //
  1775. pIniPrinter->MasqCache.dwError = Status;
  1776. DECPORTREF(pIniPort);
  1777. }
  1778. SplInSem();
  1779. pIniPrinter->MasqCache.bThreadRunning = FALSE;
  1780. DECPRINTERREF(pIniPrinter);
  1781. DeletePrinterCheck(pIniPrinter);
  1782. LeaveSplSem();
  1783. if (pThreadData)
  1784. {
  1785. CloseHandle(pThreadData->hUserToken);
  1786. }
  1787. FreeSplMem(pThreadData);
  1788. FreeSplMem(pPrinterInfo2);
  1789. return Status;
  1790. }