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.

4718 lines
132 KiB

  1. /*++
  2. Copyright (c) 1994 - 2000 Microsoft Corporation
  3. Module Name:
  4. cache.c
  5. Abstract:
  6. This module contains all the Cache Printer Connection for
  7. true Connected Printers.
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. #include "TPmgr.hxx"
  12. PWCHAR pszRaw = L"RAW";
  13. PWCHAR szWin32SplDirectory = L"\\spool";
  14. WCHAR szRegistryWin32Root[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Providers\\LanMan Print Services\\Servers";
  15. WCHAR szOldLocationOfServersKey[] = L"System\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Servers";
  16. WCHAR szPrinters[] = L"\\Printers";
  17. PWCHAR pszRegistryMonitors = L"\\System\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Monitors";
  18. PWCHAR pszRegistryEnvironments = L"System\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Environments";
  19. PWCHAR pszRegistryEventLog = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\Print";
  20. PWCHAR pszRegistryProviders = L"Providers";
  21. PWCHAR pszEventLogMsgFile = L"%SystemRoot%\\System32\\Win32Spl.dll";
  22. PWCHAR pszDriversShareName = L"wn32prt$";
  23. WCHAR szForms[] = L"\\Forms";
  24. PWCHAR pszMyDllName = L"win32spl.dll";
  25. PWCHAR pszMonitorName = L"LanMan Print Services Port";
  26. const WCHAR gszRegistryPrinterPolicies[] = L"Software\\\\Microsoft\\Windows NT\\Current Version\\Print\\Providers\\LanMan Print Services";
  27. const WCHAR gszPointAndPrintPolicies[] = L"Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint";
  28. const WCHAR gszPointAndPrintRestricted[] = L"Restricted";
  29. const WCHAR gszPointAndPrintInForest[] = L"InForest";
  30. const WCHAR gszPointAndPrintTrustedServers[] = L"TrustedServers";
  31. const WCHAR gszPointAndPrintServerList[] = L"ServerList";
  32. UINT cOpenPrinterThreads = 0;
  33. PWSPOOL pFirstWSpool = NULL;
  34. WCHAR *szCachePrinterInfo2 = L"CachePrinterInfo2";
  35. WCHAR *szCacheTimeLastChange = L"CacheChangeID";
  36. WCHAR *szServerVersion = L"ServerVersion";
  37. WCHAR *szcRef = L"CacheReferenceCount";
  38. WCHAR CacheTimeoutString[] = L"CacheTimeout";
  39. DWORD CacheTimeout = 0;
  40. //
  41. // If we have an rpc handle created recently don't hit the net
  42. //
  43. #define REFRESH_TIMEOUT 15000 // 15 seconds
  44. #define CACHE_TIMEOUT 5000 // Default to 5 seconds.
  45. VOID
  46. RefreshDriverEvent(
  47. PWSPOOL pSpool
  48. )
  49. /*++
  50. Routine Description:
  51. Call out to the Printer Driver UI DLL to allow it to do any caching it might want to do.
  52. For example there might be a large FONT metric file on the print server which is too large
  53. to be written to the registry using SetPrinterData(). This callout will allow the printer
  54. driver to copy this font file to the workstation when the cache is established and will
  55. allow it to periodically check that the file is still valid.
  56. Arguments:
  57. pSpool - Handle to remote printer.
  58. Return Value:
  59. None
  60. --*/
  61. {
  62. DWORD dwPrnEvntError = ERROR_SUCCESS;
  63. SplOutSem();
  64. SplDriverEvent( pSpool->pName, PRINTER_EVENT_CACHE_REFRESH, (LPARAM)NULL, &dwPrnEvntError );
  65. }
  66. /*++
  67. -- GetCacheTimeout --
  68. Routine Description:
  69. Read the registry to see if anyone has changed the Timeout on the Cache. Default
  70. to CACHE_TIMEOUT if not.
  71. Arguments:
  72. None
  73. Return Value:
  74. Cache Timeout in Milliseconds.
  75. --*/
  76. DWORD GetCacheTimeout(
  77. VOID
  78. )
  79. {
  80. DWORD Value = CACHE_TIMEOUT;
  81. DWORD RegValue = 0;
  82. DWORD RegValueSize = sizeof(RegValue);
  83. HKEY RegKey = NULL;
  84. DWORD dwReturn = ERROR_SUCCESS;
  85. //
  86. // This will only read the timeout from the registry once, after that, it will use
  87. // the stored value. This is not ideal and could be fixed to be per-server,
  88. // depending on the connection speed to the server.
  89. //
  90. if ( CacheTimeout )
  91. {
  92. Value = CacheTimeout;
  93. }
  94. else
  95. {
  96. dwReturn = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  97. szRegistryWin32Root,
  98. 0,
  99. KEY_READ,
  100. &RegKey );
  101. if (dwReturn == ERROR_SUCCESS)
  102. {
  103. dwReturn = RegQueryValueEx( RegKey,
  104. CacheTimeoutString,
  105. NULL,
  106. NULL,
  107. (LPBYTE) &RegValue,
  108. &RegValueSize );
  109. if ( dwReturn == ERROR_SUCCESS )
  110. {
  111. Value = RegValue;
  112. }
  113. dwReturn = RegCloseKey( RegKey );
  114. }
  115. CacheTimeout = Value;
  116. }
  117. return Value;
  118. }
  119. HANDLE
  120. CacheCreateSpooler(
  121. LPWSTR pMachineName,
  122. BOOL bOpenOnly
  123. )
  124. {
  125. PWCHAR pScratch = NULL;
  126. PWCHAR pRegistryRoot = NULL;
  127. PWCHAR pRegistryPrinters = NULL;
  128. SPOOLER_INFO_1 SpoolInfo1;
  129. HANDLE hIniSpooler = INVALID_HANDLE_VALUE;
  130. PWCHAR pMachineOneSlash;
  131. MONITOR_INFO_2 MonitorInfo;
  132. DWORD dwNeeded, cchScratch;
  133. DWORD Returned;
  134. try {
  135. //
  136. // get size of szRegistryWin32Root (incl NULL) + (pMachineName + 1)
  137. //
  138. cchScratch = COUNTOF(szRegistryWin32Root) + MAX(COUNTOF(szPrinters), COUNTOF(szForms)) + wcslen(pMachineName + 1);
  139. if (!(pScratch = AllocSplMem(cchScratch * sizeof(WCHAR))))
  140. leave;
  141. pMachineOneSlash = pMachineName;
  142. pMachineOneSlash++;
  143. //
  144. // Create a "Machine" for this Printer
  145. //
  146. SpoolInfo1.pDir = gpWin32SplDir; // %systemroot%\system32\win32spl
  147. SpoolInfo1.pDefaultSpoolDir = NULL; // Default %systemroot%\system32\win32spl\PRINTERS
  148. StrNCatBuff(pScratch,
  149. cchScratch,
  150. szRegistryWin32Root,
  151. pMachineOneSlash,
  152. NULL);
  153. if (!(pRegistryRoot = AllocSplStr( pScratch )))
  154. leave;
  155. SpoolInfo1.pszRegistryRoot = pRegistryRoot;
  156. StringCchCat( pScratch, cchScratch, szPrinters );
  157. if (!(pRegistryPrinters = AllocSplStr( pScratch )))
  158. leave;
  159. SpoolInfo1.pszRegistryPrinters = pRegistryPrinters;
  160. SpoolInfo1.pszRegistryMonitors = pszRegistryMonitors;
  161. SpoolInfo1.pszRegistryEnvironments = pszRegistryEnvironments;
  162. SpoolInfo1.pszRegistryEventLog = pszRegistryEventLog;
  163. SpoolInfo1.pszRegistryProviders = pszRegistryProviders;
  164. SpoolInfo1.pszEventLogMsgFile = pszEventLogMsgFile;
  165. SpoolInfo1.pszDriversShare = pszDriversShareName;
  166. StrNCatBuff(pScratch,
  167. cchScratch,
  168. szRegistryWin32Root,
  169. pMachineOneSlash,
  170. szForms,
  171. NULL);
  172. SpoolInfo1.pszRegistryForms = pScratch;
  173. // The router graciously does the WIN.INI devices update so let have
  174. // Spl not also create a printer for us.
  175. //
  176. // CLS
  177. //
  178. SpoolInfo1.SpoolerFlags = SPL_BROADCAST_CHANGE |
  179. SPL_TYPE_CACHE |
  180. (bOpenOnly ? SPL_OPEN_EXISTING_ONLY : 0);
  181. SpoolInfo1.pfnReadRegistryExtra = (FARPROC) &CacheReadRegistryExtra;
  182. SpoolInfo1.pfnWriteRegistryExtra = (FARPROC) &CacheWriteRegistryExtra;
  183. SpoolInfo1.pfnFreePrinterExtra = (FARPROC) &CacheFreeExtraData;
  184. SplOutSem();
  185. hIniSpooler = SplCreateSpooler( pMachineName,
  186. 1,
  187. (PBYTE)&SpoolInfo1,
  188. NULL );
  189. //
  190. // CLS
  191. //
  192. if ( hIniSpooler == INVALID_HANDLE_VALUE ) {
  193. if (!bOpenOnly)
  194. {
  195. SetLastError( ERROR_INVALID_PRINTER_NAME );
  196. }
  197. } else {
  198. // Add WIN32SPL.DLL as the Monitor
  199. MonitorInfo.pName = pszMonitorName;
  200. MonitorInfo.pEnvironment = szEnvironment;
  201. MonitorInfo.pDLLName = pszMyDllName;
  202. if ( (!SplAddMonitor( NULL, 2, (LPBYTE)&MonitorInfo, hIniSpooler)) &&
  203. ( GetLastError() != ERROR_PRINT_MONITOR_ALREADY_INSTALLED ) ) {
  204. DBGMSG( DBG_WARNING, ("CacheCreateSpooler failed SplAddMonitor %d\n", GetLastError()));
  205. SplCloseSpooler( hIniSpooler );
  206. hIniSpooler = INVALID_HANDLE_VALUE;
  207. }
  208. }
  209. } finally {
  210. FreeSplStr ( pScratch );
  211. FreeSplStr ( pRegistryRoot );
  212. FreeSplStr ( pRegistryPrinters );
  213. }
  214. return hIniSpooler;
  215. }
  216. VOID
  217. RefreshCompletePrinterCache(
  218. IN PWSPOOL pSpool,
  219. IN EDriverDownload eDriverDownload
  220. )
  221. {
  222. DBGMSG( DBG_TRACE, ("RefreshCompletePrinterCache %x\n", pSpool));
  223. if (eDriverDownload == kCheckPnPPolicy)
  224. {
  225. BOOL bAllowPointAndPrint = FALSE;
  226. if (BoolFromHResult(DoesPolicyAllowPrinterConnectionsToServer(pSpool->pName, &bAllowPointAndPrint)) &&
  227. bAllowPointAndPrint)
  228. {
  229. eDriverDownload = kDownloadDriver;
  230. }
  231. else
  232. {
  233. eDriverDownload = kDontDownloadDriver;
  234. }
  235. }
  236. //
  237. // Note the order is important.
  238. // Refreshing the printer might require that the new driver has
  239. // been installed on the system. If policy doesn't allow us to
  240. // fetch the driver, you are just out of luck.
  241. //
  242. RefreshPrinterDriver(pSpool, NULL, eDriverDownload);
  243. RefreshFormsCache( pSpool );
  244. RefreshPrinterDataCache(pSpool);
  245. RefreshPrinterCopyFiles(pSpool);
  246. RefreshDriverEvent( pSpool );
  247. SplBroadcastChange(pSpool->hSplPrinter, WM_DEVMODECHANGE, 0, (LPARAM) pSpool->pName);
  248. }
  249. PPRINTER_INFO_2
  250. GetRemotePrinterInfo(
  251. PWSPOOL pSpool,
  252. LPDWORD pReturnCount
  253. )
  254. {
  255. PPRINTER_INFO_2 pRemoteInfo = NULL;
  256. HANDLE hPrinter = (HANDLE) pSpool;
  257. DWORD cbRemoteInfo = 0;
  258. DWORD dwBytesNeeded = 0;
  259. DWORD dwLastError = 0;
  260. BOOL bReturnValue = FALSE;
  261. *pReturnCount = 0;
  262. do {
  263. if ( pRemoteInfo != NULL ) {
  264. FreeSplMem( pRemoteInfo );
  265. pRemoteInfo = NULL;
  266. cbRemoteInfo = 0;
  267. }
  268. if ( dwBytesNeeded != 0 ) {
  269. pRemoteInfo = AllocSplMem( dwBytesNeeded );
  270. if ( pRemoteInfo == NULL )
  271. break;
  272. }
  273. cbRemoteInfo = dwBytesNeeded;
  274. bReturnValue = RemoteGetPrinter( hPrinter,
  275. 2,
  276. (LPBYTE)pRemoteInfo,
  277. cbRemoteInfo,
  278. &dwBytesNeeded );
  279. dwLastError = GetLastError();
  280. } while ( !bReturnValue && dwLastError == ERROR_INSUFFICIENT_BUFFER );
  281. if ( !bReturnValue && pRemoteInfo != NULL ) {
  282. FreeSplMem( pRemoteInfo );
  283. pRemoteInfo = NULL;
  284. cbRemoteInfo = 0;
  285. }
  286. *pReturnCount = cbRemoteInfo;
  287. return pRemoteInfo;
  288. }
  289. //
  290. // This routine Clones the Printer_Info_2 structure from the Remote machine
  291. //
  292. //
  293. PWCACHEINIPRINTEREXTRA
  294. AllocExtraData(
  295. PPRINTER_INFO_2W pPrinterInfo2,
  296. DWORD cbPrinterInfo2
  297. )
  298. {
  299. PWCACHEINIPRINTEREXTRA pExtraData = NULL;
  300. DWORD cbSize;
  301. SPLASSERT( cbPrinterInfo2 != 0);
  302. SPLASSERT( pPrinterInfo2 != NULL );
  303. cbSize = sizeof( WCACHEINIPRINTEREXTRA );
  304. pExtraData = AllocSplMem( cbSize );
  305. if ( pExtraData != NULL ) {
  306. pExtraData->signature = WCIP_SIGNATURE;
  307. pExtraData->cb = cbSize;
  308. pExtraData->cRef = 0;
  309. pExtraData->cbPI2 = cbPrinterInfo2;
  310. pExtraData->dwTickCount = GetTickCount();
  311. pExtraData->pPI2 = AllocSplMem( cbPrinterInfo2 );
  312. if ( pExtraData->pPI2 != NULL ) {
  313. CacheCopyPrinterInfo( pExtraData->pPI2, pPrinterInfo2, cbPrinterInfo2 );
  314. } else {
  315. FreeSplMem( pExtraData );
  316. pExtraData = NULL;
  317. }
  318. }
  319. return pExtraData;
  320. }
  321. VOID
  322. CacheFreeExtraData(
  323. PWCACHEINIPRINTEREXTRA pExtraData
  324. )
  325. {
  326. PWCACHEINIPRINTEREXTRA pPrev = NULL;
  327. PWCACHEINIPRINTEREXTRA pCur = NULL;
  328. if ( pExtraData != NULL ) {
  329. SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
  330. if ( pExtraData->cRef != 0 ) {
  331. DBGMSG( DBG_TRACE, ("CacheFreeExtraData pExtraData %x cRef %d != 0 freeing anyway\n",
  332. pExtraData,
  333. pExtraData->cRef ));
  334. }
  335. if ( pExtraData->pPI2 != NULL ) {
  336. FreeSplMem( pExtraData->pPI2 );
  337. }
  338. FreeSplMem( pExtraData );
  339. }
  340. }
  341. VOID
  342. DownAndMarshallUpStructure(
  343. LPBYTE lpStructure,
  344. LPBYTE lpSource,
  345. LPDWORD lpOffsets
  346. )
  347. {
  348. register DWORD i=0;
  349. while (lpOffsets[i] != -1) {
  350. if ((*(LPBYTE *)(lpStructure+lpOffsets[i]))) {
  351. (*(LPBYTE *)(lpStructure+lpOffsets[i]))-=(UINT_PTR)lpSource;
  352. (*(LPBYTE *)(lpStructure+lpOffsets[i]))+=(UINT_PTR)lpStructure;
  353. }
  354. i++;
  355. }
  356. }
  357. VOID
  358. CacheCopyPrinterInfo(
  359. PPRINTER_INFO_2W pDestination,
  360. PPRINTER_INFO_2W pPrinterInfo2,
  361. DWORD cbPrinterInfo2
  362. )
  363. {
  364. //
  365. // Copy the lot then fix up the pointers
  366. //
  367. CopyMemory( pDestination, pPrinterInfo2, cbPrinterInfo2 );
  368. DownAndMarshallUpStructure( (LPBYTE)pDestination, (LPBYTE)pPrinterInfo2, PrinterInfo2Offsets );
  369. }
  370. VOID
  371. ConvertRemoteInfoToLocalInfo(
  372. PPRINTER_INFO_2 pPrinterInfo2
  373. )
  374. {
  375. SPLASSERT( pPrinterInfo2 != NULL );
  376. DBGMSG(DBG_TRACE,("%ws %ws ShareName %x %ws pSecurityDesc %x Attributes %x StartTime %d UntilTime %d Status %x\n",
  377. pPrinterInfo2->pServerName,
  378. pPrinterInfo2->pPrinterName,
  379. pPrinterInfo2->pShareName,
  380. pPrinterInfo2->pPortName,
  381. pPrinterInfo2->pSecurityDescriptor,
  382. pPrinterInfo2->Attributes,
  383. pPrinterInfo2->StartTime,
  384. pPrinterInfo2->UntilTime,
  385. pPrinterInfo2->Status));
  386. //
  387. // GetPrinter returns the name \\server\printername we only want the printer name
  388. //
  389. pPrinterInfo2->pPrinterName = wcschr( pPrinterInfo2->pPrinterName + 2, L'\\' );
  390. if( !pPrinterInfo2->pPrinterName ){
  391. SPLASSERT( FALSE );
  392. pPrinterInfo2->pPrinterName = pPrinterInfo2->pPrinterName;
  393. } else {
  394. pPrinterInfo2->pPrinterName++;
  395. }
  396. //
  397. // LATER this should be a Win32Spl Port
  398. //
  399. pPrinterInfo2->pPortName = L"NExx:";
  400. pPrinterInfo2->pSepFile = NULL;
  401. pPrinterInfo2->pSecurityDescriptor = NULL;
  402. pPrinterInfo2->pPrintProcessor = L"winprint";
  403. pPrinterInfo2->pDatatype = pszRaw;
  404. pPrinterInfo2->pParameters = NULL;
  405. pPrinterInfo2->Attributes &= ~( PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_DIRECT | PRINTER_ATTRIBUTE_SHARED );
  406. pPrinterInfo2->StartTime = 0;
  407. pPrinterInfo2->UntilTime = 0;
  408. //
  409. // ConvertRemoteInfoToLocalInfo is called once before an SplAddPrinter
  410. // and once before an SplSetPrinter, both level 2. Neither SplAddPrinter, nor
  411. // SplSetPrinter look at the Status field in the printer info. So the
  412. // value below is artificial. We just give it an initial state.
  413. //
  414. pPrinterInfo2->Status = 0;
  415. pPrinterInfo2->cJobs = 0;
  416. pPrinterInfo2->AveragePPM = 0;
  417. }
  418. VOID
  419. RefreshPrinter(
  420. PWSPOOL pSpool
  421. )
  422. {
  423. PPRINTER_INFO_2 pRemoteInfo = NULL;
  424. DWORD cbRemoteInfo = 0;
  425. BOOL ReturnValue = FALSE;
  426. PWCACHEINIPRINTEREXTRA pExtraData = NULL;
  427. PWCACHEINIPRINTEREXTRA pNewExtraData = NULL;
  428. PPRINTER_INFO_2 pTempPI2 = NULL;
  429. PPRINTER_INFO_2 pCopyExtraPI2ToFree = NULL;
  430. DWORD dwLastError;
  431. //
  432. // Get the Remote Printer Info
  433. //
  434. pRemoteInfo = GetRemotePrinterInfo( pSpool, &cbRemoteInfo );
  435. if ( pRemoteInfo != NULL ) {
  436. //
  437. // Assume everything is OK for now. This is to keep the code behavior as it was.
  438. //
  439. ReturnValue = TRUE;
  440. // LATER
  441. // Optimization could be to only update the cache if something
  442. // actually changed.
  443. // IE Compare every field.
  444. //
  445. EnterSplSem();
  446. if (!SplGetPrinterExtra( pSpool->hSplPrinter, &(PBYTE)pExtraData)) {
  447. DBGMSG( DBG_ERROR, ("RefreshPrinter SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
  448. }
  449. if ( pExtraData == NULL ) {
  450. pExtraData = AllocExtraData( pRemoteInfo, cbRemoteInfo );
  451. if ( pExtraData != NULL ) {
  452. pExtraData->cRef++;
  453. }
  454. } else {
  455. //
  456. // Only continue if the remote name and the local name are the same.
  457. //
  458. ReturnValue = pExtraData->pPI2->pPrinterName && pRemoteInfo->pPrinterName && !_wcsicmp(pRemoteInfo->pPrinterName, pExtraData->pPI2->pPrinterName);
  459. if (ReturnValue) {
  460. SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
  461. pTempPI2 = AllocSplMem( cbRemoteInfo );
  462. if ( pTempPI2 != NULL ) {
  463. SplInSem();
  464. CacheCopyPrinterInfo( pTempPI2, pRemoteInfo, cbRemoteInfo );
  465. pCopyExtraPI2ToFree = pExtraData->pPI2;
  466. pExtraData->pPI2 = pTempPI2;
  467. pExtraData->cbPI2 = cbRemoteInfo;
  468. }
  469. }
  470. else {
  471. DBGMSG(DBG_TRACE, ("Printer Names are different (%s, %s)\n", pExtraData->pPI2->pPrinterName, pRemoteInfo->pPrinterName));
  472. }
  473. }
  474. LeaveSplSem();
  475. if ( pExtraData != NULL ) {
  476. SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
  477. }
  478. if (ReturnValue) {
  479. ConvertRemoteInfoToLocalInfo( pRemoteInfo );
  480. ReturnValue = SplSetPrinter( pSpool->hSplPrinter, 2, (LPBYTE)pRemoteInfo, 0 );
  481. if ( !ReturnValue ) {
  482. //
  483. // If the driver is blocked and the driver has changed, we want to log
  484. // an event.
  485. //
  486. dwLastError = GetLastError();
  487. if (ERROR_KM_DRIVER_BLOCKED == dwLastError &&
  488. pCopyExtraPI2ToFree &&
  489. pCopyExtraPI2ToFree->pDriverName &&
  490. pRemoteInfo->pDriverName &&
  491. _wcsicmp(pCopyExtraPI2ToFree->pDriverName, pRemoteInfo->pDriverName)) {
  492. //
  493. // We have entered a mismatched case through someone admin'ing a
  494. // remote server. Log an error message, we cannot throw UI at this
  495. // point.
  496. //
  497. SplLogEventExternal(LOG_ERROR,
  498. MSG_DRIVER_MISMATCHED_WITH_SERVER,
  499. pSpool->pName,
  500. pRemoteInfo->pDriverName,
  501. NULL);
  502. }
  503. else if(dwLastError == ERROR_UNKNOWN_PRINTER_DRIVER)
  504. {
  505. if (ReturnValue = AddDriverFromLocalCab( pRemoteInfo->pDriverName, pSpool->hIniSpooler))
  506. {
  507. ReturnValue = SplSetPrinter( pSpool->hSplPrinter, 2, (LPBYTE)pRemoteInfo, 0 );
  508. }
  509. }
  510. DBGMSG( DBG_WARNING, ("RefreshPrinter Failed SplSetPrinter %d\n", GetLastError() ));
  511. }
  512. ReturnValue = SplSetPrinterExtra( pSpool->hSplPrinter, (LPBYTE)pExtraData );
  513. if (!ReturnValue) {
  514. DBGMSG(DBG_ERROR, ("RefreshPrinter SplSetPrinterExtra failed %x\n", GetLastError()));
  515. }
  516. }
  517. } else {
  518. DBGMSG( DBG_WARNING, ("RefreshPrinter failed GetRemotePrinterInfo %x\n", GetLastError() ));
  519. }
  520. if ( pRemoteInfo != NULL )
  521. FreeSplMem( pRemoteInfo );
  522. if (pCopyExtraPI2ToFree != NULL) {
  523. FreeSplMem(pCopyExtraPI2ToFree);
  524. }
  525. }
  526. VOID
  527. RefreshPrinterInfo7(
  528. PWSPOOL pSpool
  529. )
  530. {
  531. PPRINTER_INFO_7 pInfo = NULL;
  532. DWORD cbNeeded = 0;
  533. BOOL bRet;
  534. bRet = RemoteGetPrinter((HANDLE) pSpool, 7, (PBYTE) pInfo, 0, &cbNeeded);
  535. if (bRet) {
  536. DBGMSG( DBG_ERROR, ("RefreshPrinterInfo7 Illegally succeeded RemoteGetPrinter %d\n"));
  537. goto done;
  538. } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  539. DBGMSG( DBG_WARNING, ("RefreshPrinterInfo7 Failed RemoteGetPrinter %d\n", GetLastError()));
  540. goto done;
  541. }
  542. if (!(pInfo = (PPRINTER_INFO_7) AllocSplMem(cbNeeded))) {
  543. DBGMSG( DBG_WARNING, ("RefreshPrinterInfo7 Failed RemoteGetPrinter %d\n", GetLastError()));
  544. goto done;
  545. }
  546. if (!RemoteGetPrinter((HANDLE) pSpool, 7, (PBYTE) pInfo, cbNeeded, &cbNeeded)) {
  547. DBGMSG( DBG_WARNING, ("RefreshPrinterInfo7 Failed RemoteGetPrinter %d\n", GetLastError()));
  548. goto done;
  549. }
  550. if (!SplSetPrinter( pSpool->hSplPrinter, 7, (PBYTE) pInfo, 0)) {
  551. DBGMSG( DBG_WARNING, ("RefreshPrinterInfo7 Failed RemoteSetPrinter %d\n", GetLastError()));
  552. goto done;
  553. }
  554. done:
  555. FreeSplMem(pInfo);
  556. }
  557. PWSPOOL
  558. InternalAddPrinterConnection(
  559. LPWSTR pName
  560. )
  561. /*++
  562. Function Description: InternalAddPrinterConnection creates a printer connection.
  563. Parameters: pName - name of the printer connection
  564. Return Values: pSpool if successful;
  565. NULL otherwise
  566. --*/
  567. {
  568. PWSPOOL pSpool = NULL;
  569. BOOL bReturnValue = FALSE;
  570. HANDLE hIniSpooler = INVALID_HANDLE_VALUE;
  571. PPRINTER_INFO_2 pPrinterInfo2 = NULL;
  572. DWORD cbPrinterInfo2 = 0;
  573. HANDLE hSplPrinter = INVALID_HANDLE_VALUE;
  574. PWCACHEINIPRINTEREXTRA pExtraData = NULL;
  575. PWCACHEINIPRINTEREXTRA pExtraData2 = NULL;
  576. BOOL bSuccess = FALSE;
  577. LPPRINTER_INFO_STRESSW pPrinter0 = NULL;
  578. DWORD dwNeeded;
  579. DWORD LastError = ERROR_SUCCESS;
  580. BOOL bLoopDetected = FALSE;
  581. BOOL bAllowPointAndPrint = FALSE;
  582. BOOL bAllowDriverDownload = FALSE;
  583. try {
  584. if (!VALIDATE_NAME(pName)) {
  585. SetLastError(ERROR_INVALID_NAME);
  586. leave;
  587. }
  588. if (!RemoteOpenPrinter(pName, &pSpool, NULL, DO_NOT_CALL_LM_OPEN)) {
  589. leave;
  590. }
  591. pPrinter0 = AllocSplMem( MAX_PRINTER_INFO0 );
  592. if ( pPrinter0 == NULL )
  593. leave;
  594. SPLASSERT( pSpool != NULL );
  595. SPLASSERT( pSpool->Type == SJ_WIN32HANDLE );
  596. DBGMSG( DBG_TRACE, ("AddPrinterConnection pName %ws pSpool %x\n",pName, pSpool ));
  597. //
  598. // Get Remote ChangeID to be certain nothing changes on the Server
  599. // whilst we are establishing our Cache.
  600. //
  601. bReturnValue = RemoteGetPrinter( pSpool, STRESSINFOLEVEL, (LPBYTE)pPrinter0, MAX_PRINTER_INFO0, &dwNeeded );
  602. if ( !bReturnValue ) {
  603. SPLASSERT( GetLastError() != ERROR_INSUFFICIENT_BUFFER );
  604. DBGMSG(DBG_TRACE, ("AddPrinterConnection failed RemoteGetPrinter %d\n", GetLastError()));
  605. pPrinter0->cChangeID = 0;
  606. }
  607. DBGMSG( DBG_TRACE, ("AddPrinterConnection << Server cCacheID %x >>\n", pPrinter0->cChangeID ));
  608. //
  609. // See If the Printer is already in the Cache
  610. //
  611. APC_OpenCache:
  612. bReturnValue = OpenCachePrinterOnly( pName, &hSplPrinter, &hIniSpooler, NULL, FALSE);
  613. if ( hIniSpooler == INVALID_HANDLE_VALUE ) {
  614. DBGMSG( DBG_WARNING, ("AddPrinterConnection - CacheCreateSpooler Failed %x\n",GetLastError()));
  615. leave;
  616. }
  617. pSpool->hIniSpooler = hIniSpooler;
  618. if ( bReturnValue ) {
  619. //
  620. // Printer Exists in Cache
  621. //
  622. SPLASSERT( ( hSplPrinter != INVALID_HANDLE_VALUE) &&
  623. ( hSplPrinter != NULL ) );
  624. DBGMSG( DBG_TRACE,("AddPrinterConnection hIniSpooler %x hSplPrinter%x\n", hIniSpooler, hSplPrinter) );
  625. pSpool->hSplPrinter = hSplPrinter;
  626. pSpool->Status |= WSPOOL_STATUS_USE_CACHE;
  627. //
  628. // Update Connection Reference Count
  629. //
  630. EnterSplSem();
  631. bReturnValue = SplGetPrinterExtra( pSpool->hSplPrinter, &(PBYTE)pExtraData );
  632. if ( bReturnValue == FALSE ) {
  633. DBGMSG( DBG_WARNING, ("AddPrinterConnection SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
  634. SPLASSERT( bReturnValue );
  635. }
  636. if ( pExtraData != NULL ) {
  637. SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
  638. pExtraData->cRef++;
  639. }
  640. LeaveSplSem();
  641. // Make Sure Reference Count Gets Updated in Registry
  642. if ( !SplSetPrinterExtra( hSplPrinter, (LPBYTE)pExtraData ) ) {
  643. DBGMSG( DBG_ERROR, ("AddPrinterConnection SplSetPrinterExtra failed %x\n", GetLastError() ));
  644. }
  645. // Refresh Cache
  646. // It could be that the remote machine is old NT Daytona 3.5 or before
  647. // which doesn't support the ChangeID, that would mean the only
  648. // way for a user to force an update is to do a connection.
  649. if ( pPrinter0->cChangeID == 0 ) {
  650. // Old NT
  651. RefreshCompletePrinterCache(pSpool, kCheckPnPPolicy);
  652. } else {
  653. //
  654. // Since we have this in the cache anyway, we might as well sync
  655. // settings, we only sync settings if we are allowed to download
  656. // the driver.
  657. //
  658. ConsistencyCheckCache(pSpool, kCheckPnPPolicy);
  659. }
  660. pExtraData = NULL;
  661. bSuccess = TRUE;
  662. leave;
  663. } else if ( GetLastError() != ERROR_INVALID_PRINTER_NAME &&
  664. GetLastError() != ERROR_INVALID_NAME ) {
  665. DBGMSG( DBG_WARNING, ("AddPrinterConnection failed OpenCachePrinterOnly %d\n", GetLastError() ));
  666. leave;
  667. }
  668. //
  669. // There is NO Cache Entry for This Printer
  670. //
  671. DBGMSG( DBG_TRACE, ("AddPrinterConnection failed SplOpenPrinter %ws %d\n", pName, GetLastError() ));
  672. //
  673. // Get PRINTER Info from Remote Machine
  674. //
  675. pPrinterInfo2 = GetRemotePrinterInfo( pSpool, &cbPrinterInfo2 );
  676. if ( pPrinterInfo2 == NULL ) {
  677. DBGMSG( DBG_WARNING, ("AddPrinterConnection failed GetRemotePrinterInfo %x\n", GetLastError() ));
  678. leave;
  679. }
  680. if (BoolFromHResult(DoesPolicyAllowPrinterConnectionsToServer(pSpool->pName, &bAllowPointAndPrint)) &&
  681. bAllowPointAndPrint)
  682. {
  683. bAllowDriverDownload = TRUE;
  684. }
  685. if (!RefreshPrinterDriver( pSpool, pPrinterInfo2->pDriverName, bAllowDriverDownload ? kDownloadDriver : kDontDownloadDriver) && (ERROR_PRINTER_DRIVER_BLOCKED == GetLastError()))
  686. {
  687. leave;
  688. }
  689. //
  690. // Allocate My Extra Data for this Printer
  691. // ( from RemoteGetPrinter )
  692. // We need a pExtraData2 - if this is blocked by KM blocking we need to have a copy to
  693. // retry the install.
  694. //
  695. pExtraData = AllocExtraData( pPrinterInfo2, cbPrinterInfo2 );
  696. if ( pExtraData == NULL )
  697. leave;
  698. pExtraData2 = AllocExtraData( pPrinterInfo2, cbPrinterInfo2 );
  699. if ( pExtraData2 == NULL )
  700. leave;
  701. pExtraData->cRef++;
  702. pExtraData2->cRef++;
  703. pExtraData2->cCacheID = pExtraData->cCacheID = pPrinter0->cChangeID;
  704. pExtraData2->dwServerVersion = pExtraData->dwServerVersion = pPrinter0->dwGetVersion;
  705. //
  706. // Convert Remote Printer_Info_2 to Local Version for Cache
  707. //
  708. ConvertRemoteInfoToLocalInfo( pPrinterInfo2 );
  709. //
  710. // Add Printer to Cache
  711. //
  712. hSplPrinter = SplAddPrinter(NULL, 2, (LPBYTE)pPrinterInfo2,
  713. hIniSpooler, (LPBYTE)pExtraData,
  714. NULL, 0);
  715. pExtraData = NULL;
  716. if ( (hSplPrinter == NULL || hSplPrinter == INVALID_HANDLE_VALUE) &&
  717. GetLastError() == ERROR_KM_DRIVER_BLOCKED ) {
  718. //
  719. // Failed due to KM Blocking
  720. // - lets try add a driver from the local cab as this should fix this.
  721. //
  722. if( !AddDriverFromLocalCab( pPrinterInfo2->pDriverName, hIniSpooler ) ) {
  723. //
  724. // Set the old last error back as we don't really care that this failed.
  725. //
  726. SetLastError( ERROR_KM_DRIVER_BLOCKED );
  727. } else {
  728. hSplPrinter = SplAddPrinter(NULL, 2, (LPBYTE)pPrinterInfo2,
  729. hIniSpooler, (LPBYTE)pExtraData2,
  730. NULL, 0);
  731. pExtraData2 = NULL;
  732. }
  733. }
  734. if ( hSplPrinter == NULL ||
  735. hSplPrinter == INVALID_HANDLE_VALUE ) {
  736. LastError = GetLastError();
  737. if ( LastError == ERROR_PRINTER_ALREADY_EXISTS ) {
  738. SplCloseSpooler( pSpool->hIniSpooler );
  739. hIniSpooler = INVALID_HANDLE_VALUE;
  740. if ( bLoopDetected == FALSE ) {
  741. bLoopDetected = TRUE;
  742. goto APC_OpenCache;
  743. } else {
  744. DBGMSG( DBG_WARNING, ("AddPrinterConnection APC_OpenCache Loop Detected << Should Never Happen >>\n"));
  745. leave;
  746. }
  747. }
  748. //
  749. // If we could not add the printer, and it wasn't because it is already
  750. // there, and we weren't able to download the driver because of policy,
  751. // then we need to return an appropriate error code so that the UI can
  752. // inform the user about it.
  753. //
  754. else if (!bAllowDriverDownload && LastError == ERROR_UNKNOWN_PRINTER_DRIVER)
  755. {
  756. LastError = ERROR_ACCESS_DISABLED_BY_POLICY;
  757. }
  758. // If we failed to Create the printer above, we should NOT be able to Open it now.
  759. DBGMSG( DBG_WARNING, ("AddPrinterConnection Failed SplAddPrinter error %d\n", LastError ));
  760. hSplPrinter = INVALID_HANDLE_VALUE;
  761. bSuccess = FALSE;
  762. leave;
  763. }
  764. DBGMSG( DBG_TRACE, ("AddPrinterConnection SplAddPrinter SUCCESS hSplPrinter %x\n", hSplPrinter));
  765. pSpool->hSplPrinter = hSplPrinter;
  766. pSpool->Status |= WSPOOL_STATUS_USE_CACHE;
  767. RefreshFormsCache(pSpool);
  768. RefreshPrinterDataCache(pSpool);
  769. RefreshPrinterCopyFiles(pSpool);
  770. RefreshDriverEvent(pSpool);
  771. //
  772. // Just In Case something change whilst we were initializing the cache
  773. // go check it again now. Don't check policy again since we have recently
  774. // verified that we can comunicate with this server.
  775. //
  776. ConsistencyCheckCache(pSpool, bAllowDriverDownload ? kDownloadDriver : kDontDownloadDriver);
  777. bSuccess = TRUE;
  778. } finally {
  779. if ( !bSuccess ) {
  780. if ( LastError == ERROR_SUCCESS )
  781. LastError = GetLastError();
  782. InternalDeletePrinterConnection( pName, FALSE );
  783. if ( pSpool != NULL && pSpool != INVALID_HANDLE_VALUE ) {
  784. pSpool->Status &= ~WSPOOL_STATUS_TEMP_CONNECTION;
  785. CacheClosePrinter( pSpool );
  786. }
  787. SetLastError( LastError );
  788. DBGMSG( DBG_TRACE, ("AddPrinterConnection %ws Failed %d\n", pName, GetLastError() ));
  789. pSpool = NULL;
  790. }
  791. if ( pPrinterInfo2 != NULL )
  792. FreeSplMem( pPrinterInfo2 );
  793. if ( pPrinter0 != NULL )
  794. FreeSplMem( pPrinter0 );
  795. if ( pExtraData != NULL )
  796. CacheFreeExtraData( pExtraData );
  797. if ( pExtraData2 != NULL )
  798. CacheFreeExtraData( pExtraData2 );
  799. }
  800. return pSpool;
  801. }
  802. /*++
  803. Function Name:
  804. AddPrinterConnectionPrivate
  805. Function Description:
  806. AddPrinterConnectionPrivate creates a printer connection. It does
  807. not check to see if the printer connection already exists in the
  808. users registry.
  809. Parameters:
  810. pName - name of the printer connection
  811. Return Values:
  812. TRUE if successful;
  813. FALSE otherwise
  814. --*/
  815. BOOL
  816. AddPrinterConnectionPrivate(
  817. LPWSTR pName
  818. )
  819. {
  820. PWSPOOL pSpool;
  821. BOOL bReturn;
  822. pSpool = InternalAddPrinterConnection(pName);
  823. if (pSpool != NULL)
  824. {
  825. //
  826. // We have a valid handle. The connection has been created. Succeed after
  827. // closing the handle
  828. //
  829. CacheClosePrinter(pSpool);
  830. bReturn = TRUE;
  831. }
  832. else
  833. {
  834. //
  835. // Failed to create the connection.
  836. //
  837. bReturn = FALSE;
  838. }
  839. return bReturn;
  840. }
  841. /*++
  842. Function Name:
  843. AddPrinterConnection
  844. Function Description:
  845. AddPrinterConnection creates a printer connection. We check to see
  846. whether the printer connection already exists in the user registry.
  847. This works because an OpenPrinter will always occur from the router
  848. before an AddPrinter Connection. So, this will always create a
  849. printer connection from the registry in CacheOpenPrinter(). If we see
  850. this state, we simpy return TRUE.
  851. Parameters:
  852. pName - name of the printer connection
  853. Return Values:
  854. TRUE if successful;
  855. FALSE otherwise
  856. --*/
  857. BOOL
  858. AddPrinterConnection(
  859. LPWSTR pName
  860. )
  861. {
  862. HRESULT hr = E_FAIL;
  863. if (PrinterConnectionExists(pName))
  864. {
  865. hr = S_OK;
  866. }
  867. else
  868. {
  869. //
  870. // Make sure this request is coming from the local machine. Otherwise,
  871. // we could be tricked into connecting back to a remote server and
  872. // downloading their driver.
  873. //
  874. hr = CheckLocalCall();
  875. hr = hr == S_FALSE ? HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) : hr;
  876. if (SUCCEEDED(hr))
  877. {
  878. hr = AddPrinterConnectionPrivate(pName) ? S_OK : GetLastErrorAsHResultAndFail();
  879. }
  880. }
  881. return BoolFromHResult(hr);
  882. }
  883. VOID
  884. RefreshFormsCache(
  885. PWSPOOL pSpool
  886. )
  887. /*++
  888. Routine Description:
  889. This routine will check to see if any forms have changed. If anything changed it adds
  890. or deletes forms from the cache so that it matches the server.
  891. Note it is very important that the order of the forms on the workstation matches those
  892. on the Server.
  893. Implementation:
  894. EnumRemoteForms
  895. EnumLocalForms
  896. If there is any difference
  897. Delete All LocalForms
  898. Add All the Remote Forms
  899. The code is optimized for the typical case
  900. Forms are added at the end only.
  901. Forms are hardly ever deleted.
  902. Arguments:
  903. pSpool - Handle to remote printer.
  904. Return Value:
  905. None
  906. --*/
  907. {
  908. PFORM_INFO_1 pRemoteForms = NULL , pSaveRemoteForms = NULL;
  909. PFORM_INFO_1 pLocalCacheForms = NULL, pSaveLocalCacheForms = NULL;
  910. PFORM_INFO_1 pRemote = NULL, pLocal = NULL;
  911. DWORD dwBuf = 0;
  912. DWORD dwSplBuf = 0;
  913. DWORD dwNeeded = 0;
  914. DWORD dwSplNeeded = 0;
  915. DWORD dwRemoteFormsReturned = 0;
  916. DWORD dwSplReturned = 0;
  917. BOOL bReturnValue = FALSE;
  918. DWORD LastError = ERROR_INSUFFICIENT_BUFFER;
  919. INT iCompRes = 0;
  920. DWORD LoopCount;
  921. BOOL bCacheMatchesRemoteMachine = FALSE;
  922. SPLASSERT( pSpool != NULL );
  923. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  924. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  925. //
  926. // Get Remote Machine Forms Data
  927. //
  928. do {
  929. bReturnValue = RemoteEnumForms( (HANDLE)pSpool, 1, (LPBYTE)pRemoteForms, dwBuf, &dwNeeded, &dwRemoteFormsReturned);
  930. if ( bReturnValue )
  931. break;
  932. LastError = GetLastError();
  933. if ( LastError != ERROR_INSUFFICIENT_BUFFER ) {
  934. DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed RemoteEnumForms error %d\n", GetLastError()));
  935. goto RefreshFormsCacheErrorReturn;
  936. }
  937. if ( pRemoteForms != NULL )
  938. FreeSplMem( pRemoteForms );
  939. pRemoteForms = AllocSplMem( dwNeeded );
  940. pSaveRemoteForms = pRemoteForms;
  941. dwBuf = dwNeeded;
  942. if ( pRemoteForms == NULL ) {
  943. DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed AllocSplMem Error %d dwNeeded %d\n", GetLastError(), dwNeeded));
  944. goto RefreshFormsCacheErrorReturn;
  945. }
  946. } while ( !bReturnValue && LastError == ERROR_INSUFFICIENT_BUFFER );
  947. if( pRemoteForms == NULL ) {
  948. DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed pRemoteForms == NULL\n"));
  949. goto RefreshFormsCacheErrorReturn;
  950. }
  951. //
  952. // Get LocalCachedForms Data
  953. //
  954. do {
  955. bReturnValue = SplEnumForms( pSpool->hSplPrinter, 1, (LPBYTE)pLocalCacheForms, dwSplBuf, &dwSplNeeded, &dwSplReturned);
  956. if ( bReturnValue )
  957. break;
  958. LastError = GetLastError();
  959. if ( LastError != ERROR_INSUFFICIENT_BUFFER ) {
  960. DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed SplEnumForms hSplPrinter %x error %d\n", pSpool->hSplPrinter, GetLastError()));
  961. goto RefreshFormsCacheErrorReturn;
  962. }
  963. if ( pLocalCacheForms != NULL )
  964. FreeSplMem( pLocalCacheForms );
  965. pLocalCacheForms = AllocSplMem( dwSplNeeded );
  966. pSaveLocalCacheForms = pLocalCacheForms;
  967. dwSplBuf = dwSplNeeded;
  968. if ( pLocalCacheForms == NULL ) {
  969. DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed AllocSplMem ( %d )\n",dwSplNeeded));
  970. goto RefreshFormsCacheErrorReturn;
  971. }
  972. } while ( !bReturnValue && LastError == ERROR_INSUFFICIENT_BUFFER );
  973. //
  974. // Optimization Check Local vs Remote
  975. // If nothing has changed no need to do anything
  976. //
  977. SPLASSERT( pRemoteForms != NULL );
  978. for ( LoopCount = 0, pRemote = pRemoteForms, pLocal = pLocalCacheForms, bCacheMatchesRemoteMachine = TRUE;
  979. LoopCount < dwSplReturned && LoopCount < dwRemoteFormsReturned && bCacheMatchesRemoteMachine;
  980. LoopCount++, pRemote++, pLocal++ ) {
  981. //
  982. // If the form name is different, or the dimensions are different,
  983. // then refresh the forms cache.
  984. //
  985. // Note: if the forms are both built-in, then bypass the string
  986. // match since built in forms are standardized. We actually
  987. // should be able to bypass all checks.
  988. //
  989. if (( wcscmp( pRemote->pName, pLocal->pName ) != STRINGS_ARE_EQUAL ) ||
  990. ( pRemote->Size.cx != pLocal->Size.cx ) ||
  991. ( pRemote->Size.cy != pLocal->Size.cy ) ||
  992. ( pRemote->ImageableArea.left != pLocal->ImageableArea.left ) ||
  993. ( pRemote->ImageableArea.top != pLocal->ImageableArea.top ) ||
  994. ( pRemote->ImageableArea.right != pLocal->ImageableArea.right ) ||
  995. ( pRemote->ImageableArea.bottom != pLocal->ImageableArea.bottom ) ) {
  996. DBGMSG( DBG_TRACE, ("RefreshFormsCache Remote cx %d cy %d left %d right %d top %d bottom %d %ws\n",
  997. pRemote->Size.cx, pRemote->Size.cy,
  998. pRemote->ImageableArea.left,
  999. pRemote->ImageableArea.right,
  1000. pRemote->ImageableArea.top,
  1001. pRemote->ImageableArea.bottom,
  1002. pRemote->pName));
  1003. DBGMSG( DBG_TRACE, ("RefreshFormsCache Local cx %d cy %d left %d right %d top %d bottom %d %ws - Does Not Match\n",
  1004. pLocal->Size.cx, pLocal->Size.cy,
  1005. pLocal->ImageableArea.left,
  1006. pLocal->ImageableArea.right,
  1007. pLocal->ImageableArea.top,
  1008. pLocal->ImageableArea.bottom,
  1009. pLocal->pName));
  1010. bCacheMatchesRemoteMachine = FALSE;
  1011. }
  1012. }
  1013. //
  1014. // If Everything matches we're done.
  1015. //
  1016. if ( bCacheMatchesRemoteMachine ) {
  1017. if ( dwRemoteFormsReturned == dwSplReturned ) {
  1018. DBGMSG( DBG_TRACE, ("RefreshFormsCache << Cache Forms Match Remote Forms - Nothing to do >>\n"));
  1019. goto RefreshFormsCacheReturn;
  1020. } else if (dwRemoteFormsReturned > dwSplReturned){
  1021. //
  1022. // All the forms we have in the cache match
  1023. // Now add the Extra Remote Forms.
  1024. dwRemoteFormsReturned -= dwSplReturned;
  1025. pRemoteForms = pRemote;
  1026. // dwSplReturned == 0 will skip the delete loop
  1027. dwSplReturned = 0;
  1028. }
  1029. }
  1030. DBGMSG( DBG_TRACE, ("RefreshFormsCache - Something Doesn't Match, Delete all the Cache and Refresh it\n"));
  1031. //
  1032. // Delete all the forms in the Cache
  1033. //
  1034. for ( LoopCount = dwSplReturned, pLocal = pLocalCacheForms;
  1035. LoopCount != 0;
  1036. pLocal++, LoopCount-- ) {
  1037. bReturnValue = SplDeleteForm( pSpool->hSplPrinter, pLocal->pName );
  1038. DBGMSG( DBG_TRACE, ("RefreshFormsCache %x SplDeleteForm( %x, %ws)\n",bReturnValue, pSpool->hSplPrinter, pLocal->pName));
  1039. }
  1040. //
  1041. // Add all the Remote Forms to the Cache
  1042. //
  1043. for ( LoopCount = dwRemoteFormsReturned, pRemote = pRemoteForms;
  1044. LoopCount != 0;
  1045. LoopCount--, pRemote++ ) {
  1046. SPLASSERT( pRemote != NULL );
  1047. bReturnValue = SplAddForm( pSpool->hSplPrinter, 1, (LPBYTE)pRemote );
  1048. DBGMSG( DBG_TRACE, ("RefreshFormsCache %x SplAddForm( %x, 1, %ws)\n",bReturnValue, pSpool->hSplPrinter, pRemote->pName));
  1049. }
  1050. RefreshFormsCacheReturn:
  1051. RefreshFormsCacheErrorReturn:
  1052. if ( pSaveRemoteForms != NULL )
  1053. FreeSplMem( pSaveRemoteForms );
  1054. if ( pSaveLocalCacheForms != NULL )
  1055. FreeSplMem( pSaveLocalCacheForms );
  1056. }
  1057. VOID
  1058. RefreshDriverDataCache(
  1059. PWSPOOL pSpool
  1060. )
  1061. {
  1062. DWORD iCount = 0;
  1063. DWORD dwType = 0;
  1064. DWORD ReturnValue = 0;
  1065. LPBYTE lpbData = NULL;
  1066. DWORD dwSizeData;
  1067. DWORD dwMaxSizeData;
  1068. LPWSTR pValueString = NULL;
  1069. DWORD dwSizeValueString;
  1070. DWORD dwMaxSizeValueString = 0;
  1071. SPLASSERT( pSpool != NULL );
  1072. SPLASSERT( pSpool->signature == WSJ_SIGNATURE );
  1073. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  1074. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  1075. SPLASSERT( pSpool->pName != NULL );
  1076. // Get the required sizes
  1077. ReturnValue = RemoteEnumPrinterData(pSpool,
  1078. iCount,
  1079. pValueString,
  1080. 0,
  1081. &dwMaxSizeValueString,
  1082. &dwType,
  1083. lpbData,
  1084. 0,
  1085. &dwMaxSizeData);
  1086. if (ReturnValue != ERROR_SUCCESS) {
  1087. DBGMSG( DBG_TRACE, ("RefreshDriverDataCache Failed first RemoteEnumPrinterData %d\n", GetLastError()));
  1088. goto RefreshDriverDataCacheError;
  1089. }
  1090. // Allocate
  1091. if ((pValueString = AllocSplMem(dwMaxSizeValueString)) == NULL) {
  1092. DBGMSG( DBG_WARNING, ("RefreshDriverDataCache Failed to allocate enough memory\n"));
  1093. goto RefreshDriverDataCacheError;
  1094. }
  1095. if ((lpbData = AllocSplMem(dwMaxSizeData)) == NULL) {
  1096. DBGMSG( DBG_WARNING, ("RefreshDriverDataCache Failed to allocate enough memory\n"));
  1097. goto RefreshDriverDataCacheError;
  1098. }
  1099. // Enumerate
  1100. for (iCount = 0 ;
  1101. RemoteEnumPrinterData( pSpool,
  1102. iCount,
  1103. pValueString,
  1104. dwMaxSizeValueString,
  1105. &dwSizeValueString,
  1106. &dwType,
  1107. lpbData,
  1108. dwMaxSizeData,
  1109. &dwSizeData) == ERROR_SUCCESS ;
  1110. ++iCount) {
  1111. //
  1112. // Optimization - Do NOT write the data if it is the same
  1113. //
  1114. if ((ReturnValue = SplSetPrinterData(pSpool->hSplPrinter,
  1115. (LPWSTR)pValueString,
  1116. dwType,
  1117. lpbData,
  1118. dwSizeData )) != ERROR_SUCCESS) {
  1119. DBGMSG( DBG_WARNING, ("RefreshDriverDataCache Failed SplSetPrinterData %d\n",ReturnValue ));
  1120. goto RefreshDriverDataCacheError;
  1121. }
  1122. }
  1123. RefreshDriverDataCacheError:
  1124. FreeSplMem( lpbData );
  1125. FreeSplStr( pValueString );
  1126. }
  1127. VOID
  1128. RefreshPrinterDataCache(
  1129. PWSPOOL pSpool
  1130. )
  1131. {
  1132. DWORD ReturnValue = 0;
  1133. DWORD cbSubKeys;
  1134. DWORD dwResult;
  1135. SPLASSERT( pSpool != NULL );
  1136. SPLASSERT( pSpool->signature == WSJ_SIGNATURE );
  1137. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  1138. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  1139. SPLASSERT( pSpool->pName != NULL );
  1140. // This call to RemoteEnumPrinterKey is here so we can find out
  1141. // if the server exists and supports EnumPrinterKey
  1142. dwResult = RemoteEnumPrinterKey(pSpool,
  1143. L"",
  1144. NULL,
  1145. 0,
  1146. &cbSubKeys);
  1147. DBGMSG(DBG_TRACE, ("RefreshPrinterDataCache: EnumPrinterKey Return: %0x\n", dwResult));
  1148. if (dwResult == ERROR_MORE_DATA) { // Server exists and supports EnumPrinterKey
  1149. // Clean out old data
  1150. SplDeletePrinterKey(pSpool->hSplPrinter, L"");
  1151. // Enumerate and copy keys
  1152. ReturnValue = EnumerateAndCopyKey(pSpool, L"");
  1153. }
  1154. else if (dwResult == RPC_S_PROCNUM_OUT_OF_RANGE) { // Server exists but doesn't support EnumPrinterKey
  1155. // we still call refreshdriverdatacache so downlevel gets cached
  1156. // Optimize: Only call for downlevel since EnumerateAndCopyKey copies Driver Data
  1157. RefreshDriverDataCache(pSpool);
  1158. }
  1159. else if (dwResult == ERROR_INVALID_HANDLE || dwResult == RPC_S_CALL_FAILED) { // Server does not exist
  1160. DBGMSG(DBG_TRACE, ("RefreshPrinterDataCache: Server \"%ws\" absent\n", pSpool->pName));
  1161. }
  1162. // Refresh PrinterInfo2
  1163. RefreshPrinter(pSpool);
  1164. // Refresh PrinterInfo7
  1165. RefreshPrinterInfo7(pSpool);
  1166. }
  1167. DWORD
  1168. EnumerateAndCopyKey(
  1169. PWSPOOL pSpool,
  1170. LPWSTR pKeyName
  1171. )
  1172. {
  1173. DWORD i;
  1174. DWORD dwResult = ERROR_SUCCESS;
  1175. LPWSTR pSubKeys = NULL;
  1176. LPWSTR pSubKey = NULL;
  1177. LPWSTR pFullSubKey = NULL;
  1178. DWORD cbSubKey;
  1179. DWORD cbSubKeys;
  1180. LPBYTE pEnumValues = NULL;
  1181. DWORD cbEnumValues;
  1182. DWORD nEnumValues;
  1183. PPRINTER_ENUM_VALUES pEnumValue = NULL;
  1184. // Get SubKey size
  1185. dwResult = RemoteEnumPrinterKey(pSpool,
  1186. pKeyName,
  1187. pSubKeys,
  1188. 0,
  1189. &cbSubKeys);
  1190. if (dwResult != ERROR_MORE_DATA)
  1191. goto Cleanup;
  1192. // Allocate SubKey buffer
  1193. pSubKeys = AllocSplMem(cbSubKeys);
  1194. if(!pSubKeys) {
  1195. dwResult = GetLastError();
  1196. goto Cleanup;
  1197. }
  1198. // Get SubKeys
  1199. dwResult = RemoteEnumPrinterKey(pSpool,
  1200. pKeyName,
  1201. pSubKeys,
  1202. cbSubKeys,
  1203. &cbSubKeys);
  1204. if (dwResult == ERROR_SUCCESS) { // Found subkeys
  1205. DWORD cbFullSubKey = 0;
  1206. // Enumerate and copy Keys
  1207. if (*pKeyName && *pSubKeys) {
  1208. cbFullSubKey = cbSubKeys + (wcslen(pKeyName) + 2)*sizeof(WCHAR);
  1209. // Allocate buffer for L"pKeyName\pSubKey"
  1210. pFullSubKey = AllocSplMem(cbFullSubKey);
  1211. if(!pFullSubKey) {
  1212. dwResult = GetLastError();
  1213. goto Cleanup;
  1214. }
  1215. }
  1216. for(pSubKey = pSubKeys ; *pSubKey ; pSubKey += wcslen(pSubKey) + 1) {
  1217. if (*pKeyName) {
  1218. StringCbPrintf(pFullSubKey, cbFullSubKey, L"%ws\\%ws", pKeyName, pSubKey);
  1219. dwResult = EnumerateAndCopyKey(pSpool, pFullSubKey);
  1220. } else {
  1221. dwResult = EnumerateAndCopyKey(pSpool, pSubKey);
  1222. }
  1223. if (dwResult != ERROR_SUCCESS)
  1224. goto Cleanup;
  1225. }
  1226. }
  1227. dwResult = RemoteEnumPrinterDataEx( pSpool,
  1228. pKeyName,
  1229. pEnumValues,
  1230. 0,
  1231. &cbEnumValues,
  1232. &nEnumValues);
  1233. // We quit here if *pKeyName == NULL so we don't copy root key values
  1234. if (dwResult != ERROR_MORE_DATA || !*pKeyName)
  1235. goto Cleanup;
  1236. // Allocate EnumValues buffer
  1237. pEnumValues = AllocSplMem(cbEnumValues);
  1238. if(!pEnumValues) {
  1239. dwResult = GetLastError();
  1240. goto Cleanup;
  1241. }
  1242. // Get Values
  1243. dwResult = RemoteEnumPrinterDataEx( pSpool,
  1244. pKeyName,
  1245. pEnumValues,
  1246. cbEnumValues,
  1247. &cbEnumValues,
  1248. &nEnumValues);
  1249. // Did we get any data, this could fail.
  1250. if (dwResult == ERROR_SUCCESS)
  1251. {
  1252. // Set Values for current key
  1253. for (i = 0, pEnumValue = (PPRINTER_ENUM_VALUES) pEnumValues ; i < nEnumValues ; ++i, ++pEnumValue)
  1254. {
  1255. dwResult = SplSetPrinterDataEx( pSpool->hSplPrinter,
  1256. pKeyName,
  1257. pEnumValue->pValueName,
  1258. pEnumValue->dwType,
  1259. pEnumValue->pData,
  1260. pEnumValue->cbData);
  1261. if (dwResult != ERROR_SUCCESS)
  1262. {
  1263. goto Cleanup;
  1264. }
  1265. }
  1266. }
  1267. Cleanup:
  1268. FreeSplMem(pSubKeys);
  1269. FreeSplMem(pEnumValues);
  1270. FreeSplMem(pFullSubKey);
  1271. return dwResult;
  1272. }
  1273. BOOL
  1274. CacheEnumForms(
  1275. HANDLE hPrinter,
  1276. DWORD Level,
  1277. LPBYTE pForm,
  1278. DWORD cbBuf,
  1279. LPDWORD pcbNeeded,
  1280. LPDWORD pcReturned
  1281. )
  1282. {
  1283. PWSPOOL pSpool = (PWSPOOL) hPrinter;
  1284. BOOL ReturnValue;
  1285. VALIDATEW32HANDLE( pSpool );
  1286. if ((pSpool->Status & WSPOOL_STATUS_USE_CACHE) && !IsAdminAccess(&pSpool->PrinterDefaults)) {
  1287. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  1288. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  1289. ReturnValue = SplEnumForms( pSpool->hSplPrinter,
  1290. Level,
  1291. pForm,
  1292. cbBuf,
  1293. pcbNeeded,
  1294. pcReturned );
  1295. } else {
  1296. ReturnValue = RemoteEnumForms( hPrinter,
  1297. Level,
  1298. pForm,
  1299. cbBuf,
  1300. pcbNeeded,
  1301. pcReturned );
  1302. }
  1303. return ReturnValue;
  1304. }
  1305. BOOL
  1306. CacheGetForm(
  1307. HANDLE hPrinter,
  1308. LPWSTR pFormName,
  1309. DWORD Level,
  1310. LPBYTE pForm,
  1311. DWORD cbBuf,
  1312. LPDWORD pcbNeeded
  1313. )
  1314. {
  1315. PWSPOOL pSpool = (PWSPOOL) hPrinter;
  1316. BOOL ReturnValue;
  1317. VALIDATEW32HANDLE( pSpool );
  1318. if ((pSpool->Status & WSPOOL_STATUS_USE_CACHE) && !IsAdminAccess(&pSpool->PrinterDefaults)) {
  1319. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  1320. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  1321. ReturnValue = SplGetForm( pSpool->hSplPrinter,
  1322. pFormName,
  1323. Level,
  1324. pForm,
  1325. cbBuf,
  1326. pcbNeeded );
  1327. } else {
  1328. ReturnValue = RemoteGetForm( hPrinter,
  1329. pFormName,
  1330. Level,
  1331. pForm,
  1332. cbBuf,
  1333. pcbNeeded );
  1334. }
  1335. return ReturnValue;
  1336. }
  1337. DWORD
  1338. CacheGetPrinterData(
  1339. HANDLE hPrinter,
  1340. LPWSTR pValueName,
  1341. LPDWORD pType,
  1342. LPBYTE pData,
  1343. DWORD nSize,
  1344. LPDWORD pcbNeeded
  1345. )
  1346. {
  1347. PWSPOOL pSpool = (PWSPOOL) hPrinter;
  1348. DWORD ReturnValue;
  1349. BOOL bPrintProc = FALSE;
  1350. WCHAR szPrintProcKey[] = L"PrintProcCaps_";
  1351. VALIDATEW32HANDLE( pSpool );
  1352. //
  1353. // If the pValueName is "PrintProcCaps_[datatype]" call the remote print processor which
  1354. // supports that datatype and return the options that it supports.
  1355. //
  1356. if (pValueName && wcsstr(pValueName, szPrintProcKey)) {
  1357. bPrintProc = TRUE;
  1358. }
  1359. if ((pSpool->Status & WSPOOL_STATUS_USE_CACHE) && !bPrintProc && !IsAdminAccess(&pSpool->PrinterDefaults)) {
  1360. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  1361. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  1362. ReturnValue = SplGetPrinterData( pSpool->hSplPrinter,
  1363. pValueName,
  1364. pType,
  1365. pData,
  1366. nSize,
  1367. pcbNeeded );
  1368. } else {
  1369. ReturnValue = RemoteGetPrinterData( hPrinter,
  1370. pValueName,
  1371. pType,
  1372. pData,
  1373. nSize,
  1374. pcbNeeded );
  1375. }
  1376. return ReturnValue;
  1377. }
  1378. DWORD
  1379. CacheGetPrinterDataEx(
  1380. HANDLE hPrinter,
  1381. LPCWSTR pKeyName,
  1382. LPCWSTR pValueName,
  1383. LPDWORD pType,
  1384. LPBYTE pData,
  1385. DWORD nSize,
  1386. LPDWORD pcbNeeded
  1387. )
  1388. {
  1389. PWSPOOL pSpool = (PWSPOOL) hPrinter;
  1390. DWORD ReturnValue;
  1391. VALIDATEW32HANDLE( pSpool );
  1392. if ((pSpool->Status & WSPOOL_STATUS_USE_CACHE) && !IsAdminAccess(&pSpool->PrinterDefaults)) {
  1393. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  1394. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  1395. ReturnValue = SplGetPrinterDataEx( pSpool->hSplPrinter,
  1396. pKeyName,
  1397. pValueName,
  1398. pType,
  1399. pData,
  1400. nSize,
  1401. pcbNeeded );
  1402. } else {
  1403. ReturnValue = RemoteGetPrinterDataEx( hPrinter,
  1404. pKeyName,
  1405. pValueName,
  1406. pType,
  1407. pData,
  1408. nSize,
  1409. pcbNeeded );
  1410. }
  1411. return ReturnValue;
  1412. }
  1413. DWORD
  1414. CacheEnumPrinterDataEx(
  1415. HANDLE hPrinter,
  1416. LPCWSTR pKeyName,
  1417. LPBYTE pEnumValues,
  1418. DWORD cbEnumValues,
  1419. LPDWORD pcbEnumValues,
  1420. LPDWORD pnEnumValues
  1421. )
  1422. {
  1423. PWSPOOL pSpool = (PWSPOOL) hPrinter;
  1424. DWORD ReturnValue;
  1425. VALIDATEW32HANDLE( pSpool );
  1426. if ((pSpool->Status & WSPOOL_STATUS_USE_CACHE) && !IsAdminAccess(&pSpool->PrinterDefaults)) {
  1427. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  1428. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  1429. ReturnValue = SplEnumPrinterDataEx( pSpool->hSplPrinter,
  1430. pKeyName,
  1431. pEnumValues,
  1432. cbEnumValues,
  1433. pcbEnumValues,
  1434. pnEnumValues );
  1435. } else {
  1436. ReturnValue = RemoteEnumPrinterDataEx( hPrinter,
  1437. pKeyName,
  1438. pEnumValues,
  1439. cbEnumValues,
  1440. pcbEnumValues,
  1441. pnEnumValues );
  1442. }
  1443. return ReturnValue;
  1444. }
  1445. DWORD
  1446. CacheEnumPrinterKey(
  1447. HANDLE hPrinter,
  1448. LPCWSTR pKeyName,
  1449. LPWSTR pSubkey,
  1450. DWORD cbSubkey,
  1451. LPDWORD pcbSubkey
  1452. )
  1453. {
  1454. PWSPOOL pSpool = (PWSPOOL) hPrinter;
  1455. DWORD ReturnValue;
  1456. VALIDATEW32HANDLE( pSpool );
  1457. if ((pSpool->Status & WSPOOL_STATUS_USE_CACHE) && !IsAdminAccess(&pSpool->PrinterDefaults)) {
  1458. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  1459. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  1460. ReturnValue = SplEnumPrinterKey(pSpool->hSplPrinter,
  1461. pKeyName,
  1462. pSubkey,
  1463. cbSubkey,
  1464. pcbSubkey);
  1465. } else {
  1466. ReturnValue = RemoteEnumPrinterKey( hPrinter,
  1467. pKeyName,
  1468. pSubkey,
  1469. cbSubkey,
  1470. pcbSubkey);
  1471. }
  1472. return ReturnValue;
  1473. }
  1474. BOOL
  1475. CacheOpenPrinter(
  1476. LPWSTR pName,
  1477. LPHANDLE phPrinter,
  1478. LPPRINTER_DEFAULTS pDefault
  1479. )
  1480. {
  1481. PWSPOOL pSpool = NULL;
  1482. PWSPOOL pRemoteSpool = NULL;
  1483. HANDLE hSplPrinter = INVALID_HANDLE_VALUE;
  1484. BOOL ReturnValue = FALSE;
  1485. HANDLE hIniSpooler = INVALID_HANDLE_VALUE;
  1486. BOOL DoOpenOnError = TRUE;
  1487. DWORD LastError = ERROR_SUCCESS;
  1488. BOOL bSync = FALSE;
  1489. BOOL bCreateCacheAfterCheck = FALSE;
  1490. LPWSTR pCommastr, pFixname = NULL;
  1491. if (!VALIDATE_NAME(pName)) {
  1492. SetLastError(ERROR_INVALID_NAME);
  1493. return FALSE;
  1494. }
  1495. //
  1496. // search for pszCnvrtdmToken on the end of pName
  1497. // note that pszCnvrtdmToken must begin with a ','
  1498. //
  1499. SPLASSERT(pszCnvrtdmToken[0] == L',');
  1500. pFixname = AllocSplStr( pName );
  1501. if ( pFixname == NULL )
  1502. {
  1503. EnterSplSem();
  1504. goto OpenPrinterError;
  1505. }
  1506. StripString(pFixname, pszCnvrtdmToken, L",");
  1507. StripString(pFixname, pszDrvConvert, L",");
  1508. pName = pFixname;
  1509. ReturnValue = OpenCachePrinterOnly( pName, &hSplPrinter, &hIniSpooler, pDefault , TRUE);
  1510. if ( hIniSpooler == INVALID_HANDLE_VALUE ) {
  1511. //
  1512. // This means that the inispooler does not exist yet. Only create it
  1513. // after some more confirmation.
  1514. //
  1515. hSplPrinter = INVALID_HANDLE_VALUE;
  1516. bCreateCacheAfterCheck = TRUE;
  1517. }
  1518. if ( ReturnValue == FALSE ) {
  1519. // Printer Not Found in Cache
  1520. DBGMSG(DBG_TRACE, ("CacheOpenPrinter SplOpenPrinter %ws error %d\n",
  1521. pName,
  1522. GetLastError() ));
  1523. // FLOATING PROFILE
  1524. // If this is a Floating Profile then the following condition applies
  1525. // there is an entry in HKEY_CURRENT_USER but not entry in
  1526. // HKEY_LOCAL_MACHINE for the cache.
  1527. // If this is the case then we need to establish the Cache now
  1528. if (PrinterConnectionExists( pName )) {
  1529. //
  1530. // The printer connection exists in the registry. See if the inispooler
  1531. // did not exist yet. If it does not, create it. This is to prevent us
  1532. // hitting the wire on a default printer when some apps start up.
  1533. //
  1534. if (bCreateCacheAfterCheck) {
  1535. bCreateCacheAfterCheck = FALSE;
  1536. ReturnValue = OpenCachePrinterOnly( pName, &hSplPrinter, &hIniSpooler, pDefault, FALSE);
  1537. if (hIniSpooler == INVALID_HANDLE_VALUE) {
  1538. EnterSplSem();
  1539. hSplPrinter = INVALID_HANDLE_VALUE;
  1540. goto OpenPrinterError;
  1541. }
  1542. }
  1543. if ( ReturnValue == FALSE ) {
  1544. if ( !AddPrinterConnectionPrivate( pName ) ||
  1545. SplOpenPrinter( pName ,
  1546. &hSplPrinter,
  1547. pDefault,
  1548. hIniSpooler,
  1549. NULL,
  1550. 0) != ROUTER_SUCCESS ) {
  1551. DBGMSG( DBG_TRACE, ("CacheOpenPrinter Failed to establish Floating Profile into Cache %d\n",
  1552. GetLastError() ));
  1553. DoOpenOnError = FALSE;
  1554. EnterSplSem();
  1555. goto OpenPrinterError;
  1556. }
  1557. DBGMSG( DBG_TRACE, ("CacheOpenPrinter Floating Profile Added to Cache\n"));
  1558. }
  1559. }
  1560. else {
  1561. //
  1562. // This is just a remote open printer, just hit the wire.
  1563. //
  1564. EnterSplSem();
  1565. goto OpenPrinterError;
  1566. }
  1567. }
  1568. EnterSplSem();
  1569. SplInSem();
  1570. //
  1571. // Create a pSpool Object for this Cached Printer
  1572. //
  1573. pSpool = AllocWSpool();
  1574. if ( pSpool == NULL ) {
  1575. DBGMSG(DBG_WARNING, ("CacheOpenPrinter AllocWSpool error %d\n", GetLastError() ));
  1576. ReturnValue = FALSE;
  1577. goto OpenPrinterError;
  1578. }
  1579. pSpool->pName = AllocSplStr( pName );
  1580. if ( pSpool->pName == NULL ) {
  1581. DBGMSG(DBG_WARNING, ("CacheOpenPrinter AllocSplStr error %d\n", GetLastError() ));
  1582. ReturnValue = FALSE;
  1583. goto OpenPrinterError;
  1584. }
  1585. pSpool->Status = WSPOOL_STATUS_USE_CACHE | WSPOOL_STATUS_NO_RPC_HANDLE;
  1586. if (pFixname)
  1587. pSpool->Status |= WSPOOL_STATUS_CNVRTDEVMODE;
  1588. pSpool->hIniSpooler = hIniSpooler;
  1589. pSpool->hSplPrinter = hSplPrinter;
  1590. SPLASSERT( hIniSpooler != INVALID_HANDLE_VALUE );
  1591. SPLASSERT( hSplPrinter != INVALID_HANDLE_VALUE );
  1592. //
  1593. // We want to hit the network if:
  1594. // 1. The dwSyncOpenPrinter is non-zero, OR
  1595. // 2. A default is specified AND:
  1596. // a. A datatype is specified, and it's not RAW OR
  1597. // b. Administrative access is requested.
  1598. //
  1599. // For admin, we want to get the true status of the printer, since
  1600. // they will be administering it.
  1601. //
  1602. // If a non-default and non-RAW datatype is specified, we need to
  1603. // be synchronous, since the remote machine may refuse the datatype
  1604. // (e.g., connecting to 1057 with EMF).
  1605. //
  1606. if( pDefault ){
  1607. if( ( pDefault->pDatatype && ( _wcsicmp( pDefault->pDatatype, pszRaw ) != STRINGS_ARE_EQUAL )) ||
  1608. IsAdminAccess(pDefault)){
  1609. bSync = TRUE;
  1610. }
  1611. }
  1612. if( dwSyncOpenPrinter != 0 || bSync){
  1613. LeaveSplSem();
  1614. ReturnValue = RemoteOpenPrinter( pName, &pRemoteSpool, pDefault, DO_NOT_CALL_LM_OPEN );
  1615. EnterSplSem();
  1616. if ( ReturnValue ) {
  1617. DBGMSG( DBG_TRACE, ( "CacheOpenPrinter Synchronous Open OK pRemoteSpool %x pSpool %x\n", pRemoteSpool, pSpool ));
  1618. SPLASSERT( pRemoteSpool->Type == SJ_WIN32HANDLE );
  1619. pSpool->RpcHandle = pRemoteSpool->RpcHandle;
  1620. pSpool->Status |= pRemoteSpool->Status;
  1621. pSpool->RpcError = pRemoteSpool->RpcError;
  1622. pSpool->bNt3xServer = pRemoteSpool->bNt3xServer;
  1623. pRemoteSpool->RpcHandle = NULL;
  1624. FreepSpool( pRemoteSpool );
  1625. pRemoteSpool = NULL;
  1626. CopypDefaultTopSpool( pSpool, pDefault );
  1627. pSpool->Status &= ~WSPOOL_STATUS_NO_RPC_HANDLE;
  1628. LeaveSplSem();
  1629. ConsistencyCheckCache(pSpool, kCheckPnPPolicy);
  1630. EnterSplSem();
  1631. } else {
  1632. DBGMSG( DBG_TRACE, ( "CacheOpenPrinter Synchronous Open Failed pSpool %x LastError %d\n", pSpool, GetLastError() ));
  1633. DoOpenOnError = FALSE;
  1634. }
  1635. } else {
  1636. ReturnValue = DoAsyncRemoteOpenPrinter( pSpool, pDefault);
  1637. }
  1638. OpenPrinterError:
  1639. SplInSem();
  1640. if ( !ReturnValue ) {
  1641. // Failure
  1642. LeaveSplSem();
  1643. LastError = GetLastError();
  1644. if (( hSplPrinter != INVALID_HANDLE_VALUE ) &&
  1645. ( hSplPrinter != NULL ) ) {
  1646. SplClosePrinter( hSplPrinter );
  1647. }
  1648. if ( hIniSpooler != INVALID_HANDLE_VALUE ) {
  1649. SplCloseSpooler( hIniSpooler );
  1650. }
  1651. EnterSplSem();
  1652. if ( pSpool != NULL ) {
  1653. pSpool->hSplPrinter = INVALID_HANDLE_VALUE;
  1654. pSpool->hIniSpooler = INVALID_HANDLE_VALUE;
  1655. FreepSpool( pSpool );
  1656. pSpool = NULL;
  1657. }
  1658. LeaveSplSem();
  1659. SetLastError( LastError );
  1660. if ( DoOpenOnError ) {
  1661. ReturnValue = RemoteOpenPrinter( pName, phPrinter, pDefault, CALL_LM_OPEN );
  1662. }
  1663. } else {
  1664. // Success, pass back Handle
  1665. *phPrinter = (HANDLE)pSpool;
  1666. LeaveSplSem();
  1667. }
  1668. SplOutSem();
  1669. if ( ReturnValue == FALSE ) {
  1670. DBGMSG(DBG_TRACE,("CacheOpenPrinter %ws failed %d *phPrinter %x\n", pName, GetLastError(), *phPrinter ));
  1671. }
  1672. if (pFixname)
  1673. FreeSplStr(pFixname);
  1674. return ( ReturnValue );
  1675. }
  1676. /*++
  1677. ROUTINE NAME:
  1678. IncThreadCount
  1679. ROUTINE DESCRIPTION:
  1680. Increments the global thread count for the background threads allowed (cOpenPrinterThreads)
  1681. Assumes that the call is made from inside the spooler critical section.
  1682. ARGUMENTS:
  1683. VOID
  1684. RETURN VALUE:
  1685. VOID
  1686. --*/
  1687. VOID
  1688. IncThreadCount(
  1689. VOID
  1690. )
  1691. {
  1692. SplInSem();
  1693. cOpenPrinterThreads++;
  1694. }
  1695. /*++
  1696. ROUTINE NAME:
  1697. DecThreadCount
  1698. ROUTINE DESCRIPTION:
  1699. Decrements the global thread count for the background threads allowed (cOpenPrinterThreads)
  1700. Assumes that the call is made from inside the spooler critical section.
  1701. ARGUMENTS:
  1702. VOID
  1703. RETURN VALUE:
  1704. VOID
  1705. --*/
  1706. VOID
  1707. DecThreadCount(
  1708. VOID
  1709. )
  1710. {
  1711. SplInSem();
  1712. cOpenPrinterThreads--;
  1713. }
  1714. BOOL
  1715. CopypDefaults(
  1716. LPPRINTER_DEFAULTSW pSrc,
  1717. LPPRINTER_DEFAULTSW pDest
  1718. )
  1719. {
  1720. DWORD cbDevMode = 0;
  1721. BOOL ReturnValue = TRUE;
  1722. LPWSTR pDatatype = NULL;
  1723. LPDEVMODEW pDevMode = NULL;
  1724. if ((pSrc != NULL) && (pDest != NULL))
  1725. {
  1726. if (pSrc->pDatatype)
  1727. {
  1728. pDatatype = AllocSplStr(pSrc->pDatatype);
  1729. if (!pDatatype)
  1730. {
  1731. ReturnValue = FALSE;
  1732. }
  1733. }
  1734. if (ReturnValue && pSrc->pDevMode != NULL)
  1735. {
  1736. cbDevMode = pSrc->pDevMode->dmSize + pSrc->pDevMode->dmDriverExtra;
  1737. pDevMode = AllocSplMem(cbDevMode);
  1738. if (pDevMode != NULL)
  1739. {
  1740. CopyMemory(pDevMode, pSrc->pDevMode, cbDevMode);
  1741. }
  1742. else
  1743. {
  1744. ReturnValue = FALSE;
  1745. }
  1746. }
  1747. if (ReturnValue)
  1748. {
  1749. if (pDest->pDatatype)
  1750. {
  1751. FreeSplStr(pDest->pDatatype);
  1752. }
  1753. pDest->pDatatype = pDatatype;
  1754. pDatatype = NULL;
  1755. if (pDest->pDevMode)
  1756. {
  1757. FreeSplMem(pDest->pDevMode);
  1758. }
  1759. pDest->pDevMode = pDevMode;
  1760. pDevMode = NULL;
  1761. pDest->DesiredAccess = pSrc->DesiredAccess;
  1762. }
  1763. }
  1764. FreeSplStr(pDatatype);
  1765. FreeSplMem(pDevMode);
  1766. return ReturnValue;
  1767. }
  1768. BOOL
  1769. CopypDefaultTopSpool(
  1770. PWSPOOL pSpool,
  1771. LPPRINTER_DEFAULTSW pDefault
  1772. )
  1773. {
  1774. DWORD cbDevMode = 0;
  1775. BOOL ReturnValue = FALSE;
  1776. //
  1777. // Copy the pDefaults so we can use them later
  1778. //
  1779. try {
  1780. if ( ( pDefault != NULL ) &&
  1781. ( pDefault != &pSpool->PrinterDefaults ) ) {
  1782. if (!ReallocSplStr( &pSpool->PrinterDefaults.pDatatype , pDefault->pDatatype )) {
  1783. leave;
  1784. }
  1785. if ( pSpool->PrinterDefaults.pDevMode != NULL ) {
  1786. cbDevMode = pSpool->PrinterDefaults.pDevMode->dmSize +
  1787. pSpool->PrinterDefaults.pDevMode->dmDriverExtra;
  1788. FreeSplMem( pSpool->PrinterDefaults.pDevMode );
  1789. pSpool->PrinterDefaults.pDevMode = NULL;
  1790. }
  1791. if ( pDefault->pDevMode != NULL ) {
  1792. cbDevMode = pDefault->pDevMode->dmSize + pDefault->pDevMode->dmDriverExtra;
  1793. pSpool->PrinterDefaults.pDevMode = AllocSplMem( cbDevMode );
  1794. if ( pSpool->PrinterDefaults.pDevMode != NULL ) {
  1795. CopyMemory( pSpool->PrinterDefaults.pDevMode, pDefault->pDevMode, cbDevMode );
  1796. } else {
  1797. leave;
  1798. }
  1799. } else pSpool->PrinterDefaults.pDevMode = NULL;
  1800. pSpool->PrinterDefaults.DesiredAccess = pDefault->DesiredAccess;
  1801. }
  1802. ReturnValue = TRUE;
  1803. } finally {
  1804. }
  1805. return ReturnValue;
  1806. }
  1807. BOOL
  1808. DoAsyncRemoteOpenPrinter(
  1809. PWSPOOL pSpool,
  1810. LPPRINTER_DEFAULTS pDefault
  1811. )
  1812. {
  1813. HRESULT hResult = E_FAIL;
  1814. SplInSem();
  1815. SPLASSERT(pSpool->Status & WSPOOL_STATUS_USE_CACHE);
  1816. hResult = pSpool ? S_OK : E_INVALIDARG;
  1817. if (SUCCEEDED(hResult))
  1818. {
  1819. hResult = CopypDefaultTopSpool(pSpool, pDefault) ? S_OK : E_OUTOFMEMORY;
  1820. if (SUCCEEDED(hResult))
  1821. {
  1822. hResult = BindThreadToHandle(pSpool);
  1823. }
  1824. }
  1825. return BoolFromHResult(hResult);
  1826. }
  1827. BOOL
  1828. DoRemoteOpenPrinter(
  1829. LPWSTR pPrinterName,
  1830. LPPRINTER_DEFAULTS pDefault,
  1831. PWSPOOL pSpool
  1832. )
  1833. {
  1834. PWSPOOL pRemoteSpool = NULL;
  1835. BOOL bReturnValue;
  1836. DWORD dwLastError;
  1837. SplOutSem();
  1838. bReturnValue = RemoteOpenPrinter( pPrinterName, &pRemoteSpool, pDefault, DO_NOT_CALL_LM_OPEN );
  1839. dwLastError = GetLastError();
  1840. //
  1841. // Copy useful values to our CacheHandle and discard the new handle
  1842. //
  1843. EnterSplSem();
  1844. if ( bReturnValue ) {
  1845. DBGMSG(DBG_TRACE, ("DoRemoteOpenPrinter RemoteOpenPrinter OK hRpcHandle %x\n", pRemoteSpool->RpcHandle ));
  1846. SPLASSERT( WSJ_SIGNATURE == pSpool->signature );
  1847. SPLASSERT( WSJ_SIGNATURE == pRemoteSpool->signature );
  1848. SPLASSERT( pRemoteSpool->Type == SJ_WIN32HANDLE );
  1849. SPLASSERT( pSpool->Type == pRemoteSpool->Type );
  1850. SPLASSERT( pRemoteSpool->pServer == NULL );
  1851. SPLASSERT( pRemoteSpool->pShare == NULL );
  1852. pSpool->RpcHandle = pRemoteSpool->RpcHandle;
  1853. pSpool->Status |= pRemoteSpool->Status;
  1854. pSpool->RpcError = pRemoteSpool->RpcError;
  1855. pSpool->bNt3xServer = pRemoteSpool->bNt3xServer;
  1856. pRemoteSpool->RpcHandle = NULL;
  1857. FreepSpool( pRemoteSpool );
  1858. pRemoteSpool = NULL;
  1859. if ( pSpool->RpcHandle ) {
  1860. pSpool->Status &= ~WSPOOL_STATUS_OPEN_ERROR;
  1861. }
  1862. } else {
  1863. DBGMSG(DBG_WARNING, ("DoRemoteOpenPrinter RemoteOpenPrinter %ws failed %d\n", pPrinterName, dwLastError ));
  1864. pSpool->RpcHandle = NULL;
  1865. pSpool->Status |= WSPOOL_STATUS_OPEN_ERROR;
  1866. pSpool->RpcError = dwLastError;
  1867. if (pSpool->pThread)
  1868. {
  1869. pSpool->pThread->dwRpcOpenPrinterError = dwLastError;
  1870. }
  1871. }
  1872. pSpool->Status &= ~WSPOOL_STATUS_NO_RPC_HANDLE;
  1873. if (pSpool->pThread)
  1874. {
  1875. pSpool->pThread->hRpcHandle = pSpool->RpcHandle;
  1876. if ( !SetEvent( pSpool->pThread->hWaitValidHandle ))
  1877. {
  1878. DBGMSG(DBG_ERROR, ("RemoteOpenPrinterThread failed SetEvent pThread %x pThread->hWaitValidHandle %x\n",
  1879. pSpool->pThread, pSpool->pThread->hWaitValidHandle ));
  1880. }
  1881. }
  1882. LeaveSplSem();
  1883. // Check Cache Consistency
  1884. // The Workstation and the Server have a version ID
  1885. // If the version number has changed on the server then update the
  1886. // workstation Cache.
  1887. ConsistencyCheckCache(pSpool, kCheckPnPPolicy);
  1888. SplOutSem();
  1889. return ( bReturnValue );
  1890. }
  1891. DWORD
  1892. RemoteOpenPrinterThread(
  1893. PWIN32THREAD pThread
  1894. )
  1895. {
  1896. HRESULT hResult = E_FAIL;
  1897. PWSPOOL pSpool = NULL;
  1898. HANDLE hSplPrinter = INVALID_HANDLE_VALUE;
  1899. HANDLE hIniSpooler = INVALID_HANDLE_VALUE;
  1900. PPRINTER_DEFAULTSW pDefaults = NULL;
  1901. SplOutSem();
  1902. EnterSplSem();
  1903. hResult = pThread ? S_OK : E_INVALIDARG;
  1904. if (SUCCEEDED(hResult))
  1905. {
  1906. SetCurrentSid( pThread->hToken );
  1907. pSpool = AllocWSpool();
  1908. hResult = pSpool ? S_OK : E_OUTOFMEMORY;
  1909. }
  1910. if (SUCCEEDED(hResult))
  1911. {
  1912. pSpool->Status = WSPOOL_STATUS_USE_CACHE;
  1913. pSpool->pThread = pThread;
  1914. pDefaults = (PPRINTER_DEFAULTSW)AllocSplMem(sizeof(PRINTER_DEFAULTSW));
  1915. hResult = pDefaults && CopypDefaults(pThread->pDefaults, pDefaults) ? S_OK : E_OUTOFMEMORY;
  1916. }
  1917. if (SUCCEEDED(hResult))
  1918. {
  1919. pSpool->pName = AllocSplStr( pThread->pName );
  1920. hResult = pSpool->pName ? S_OK : E_OUTOFMEMORY;
  1921. }
  1922. if (SUCCEEDED(hResult))
  1923. {
  1924. LeaveSplSem();
  1925. SplOutSem();
  1926. hResult = OpenCachePrinterOnly(pSpool->pName, &(hSplPrinter), &(hIniSpooler), pDefaults, TRUE) ? S_OK : GetLastErrorAsHResultAndFail();
  1927. EnterSplSem();
  1928. }
  1929. if (SUCCEEDED(hResult))
  1930. {
  1931. SPLASSERT( hIniSpooler != INVALID_HANDLE_VALUE );
  1932. SPLASSERT( hSplPrinter != INVALID_HANDLE_VALUE );
  1933. pSpool->hIniSpooler = hIniSpooler;
  1934. pSpool->hSplPrinter = hSplPrinter;
  1935. SPLASSERT( pSpool->signature == WSJ_SIGNATURE );
  1936. LeaveSplSem();
  1937. SplOutSem();
  1938. hResult = DoRemoteOpenPrinter(pSpool->pName, pDefaults, pSpool) ? S_OK : GetLastErrorAsHResultAndFail();
  1939. EnterSplSem();
  1940. }
  1941. if (SUCCEEDED(hResult))
  1942. {
  1943. LeaveSplSem();
  1944. ConsistencyCheckCache(pSpool, kCheckPnPPolicy);
  1945. EnterSplSem();
  1946. }
  1947. //
  1948. // Indicate that the background this is complete.
  1949. //
  1950. if (pThread)
  1951. {
  1952. BackgroundThreadFinished(&pThread, pSpool);
  1953. }
  1954. DecThreadCount();
  1955. if (pSpool)
  1956. {
  1957. //
  1958. // Delete our temporary pSpool. If it still has the RpcHandle then we
  1959. // haven't assigned it to the thread object.
  1960. //
  1961. if (pSpool->RpcHandle)
  1962. {
  1963. LeaveSplSem();
  1964. SplOutSem();
  1965. RemoteClosePrinter((HANDLE)pSpool);
  1966. EnterSplSem();
  1967. SplInSem();
  1968. }
  1969. LeaveSplSem();
  1970. SplOutSem();
  1971. if (pSpool->hSplPrinter != INVALID_HANDLE_VALUE)
  1972. {
  1973. SplClosePrinter( pSpool->hSplPrinter );
  1974. }
  1975. if (pSpool->hIniSpooler != INVALID_HANDLE_VALUE)
  1976. {
  1977. SplCloseSpooler( pSpool->hIniSpooler );
  1978. }
  1979. EnterSplSem();
  1980. pSpool->hSplPrinter = INVALID_HANDLE_VALUE;
  1981. pSpool->hIniSpooler = INVALID_HANDLE_VALUE;
  1982. FreepSpool( pSpool );
  1983. }
  1984. LeaveSplSem();
  1985. SetCurrentSid( NULL );
  1986. if (pDefaults)
  1987. {
  1988. FreeSplStr(pDefaults->pDatatype);
  1989. FreeSplMem(pDefaults->pDevMode);
  1990. FreeSplMem(pDefaults);
  1991. }
  1992. ExitThread( 0 );
  1993. return( 0 );
  1994. }
  1995. PWSPOOL
  1996. AllocWSpool(
  1997. VOID
  1998. )
  1999. {
  2000. PWSPOOL pSpool = NULL;
  2001. SplInSem();
  2002. if (pSpool = AllocSplMem(sizeof(WSPOOL))) {
  2003. pSpool->signature = WSJ_SIGNATURE;
  2004. pSpool->Type = SJ_WIN32HANDLE;
  2005. pSpool->RpcHandle = NULL;
  2006. pSpool->hFile = INVALID_HANDLE_VALUE;
  2007. pSpool->hIniSpooler = INVALID_HANDLE_VALUE;
  2008. pSpool->hSplPrinter = INVALID_HANDLE_VALUE;
  2009. pSpool->pThread = NULL;
  2010. // Add to List
  2011. pSpool->pNext = pFirstWSpool;
  2012. pSpool->pPrev = NULL;
  2013. if ( pFirstWSpool != NULL ) {
  2014. pFirstWSpool->pPrev = pSpool;
  2015. }
  2016. pFirstWSpool = pSpool;
  2017. } else {
  2018. DBGMSG( DBG_WARNING, ("AllocWSpool failed %d\n", GetLastError() ));
  2019. }
  2020. return ( pSpool );
  2021. }
  2022. VOID
  2023. FreepSpool(
  2024. PWSPOOL pSpool
  2025. )
  2026. {
  2027. SplInSem();
  2028. SPLASSERT( pSpool->hSplPrinter == INVALID_HANDLE_VALUE );
  2029. SPLASSERT( pSpool->hIniSpooler == INVALID_HANDLE_VALUE );
  2030. SPLASSERT( !pSpool->RpcHandle );
  2031. SPLASSERT( pSpool->hFile == INVALID_HANDLE_VALUE );
  2032. // Remove form linked List
  2033. if ( pSpool->pNext != NULL ) {
  2034. SPLASSERT( pSpool->pNext->pPrev == pSpool);
  2035. pSpool->pNext->pPrev = pSpool->pPrev;
  2036. }
  2037. if ( pSpool->pPrev == NULL ) {
  2038. SPLASSERT( pFirstWSpool == pSpool );
  2039. pFirstWSpool = pSpool->pNext;
  2040. } else {
  2041. SPLASSERT( pSpool->pPrev->pNext == pSpool );
  2042. pSpool->pPrev->pNext = pSpool->pNext;
  2043. }
  2044. FreeSplStr( pSpool->pName );
  2045. FreeSplStr( pSpool->PrinterDefaults.pDatatype );
  2046. if ( pSpool->PrinterDefaults.pDevMode != NULL ) {
  2047. FreeSplMem( pSpool->PrinterDefaults.pDevMode );
  2048. }
  2049. FreeSplMem(pSpool);
  2050. }
  2051. BOOL
  2052. CacheClosePrinter(
  2053. HANDLE hPrinter
  2054. )
  2055. {
  2056. BOOL ReturnValue = TRUE;
  2057. PWSPOOL pSpool = (PWSPOOL)hPrinter;
  2058. SplOutSem();
  2059. VALIDATEW32HANDLE( pSpool );
  2060. if (pSpool->Status & WSPOOL_STATUS_PRINT_FILE)
  2061. {
  2062. RemoteEndDocPrinter( pSpool );
  2063. }
  2064. ReturnThreadFromHandle(pSpool);
  2065. EnterSplSem();
  2066. if ( pSpool->Status & WSPOOL_STATUS_TEMP_CONNECTION )
  2067. {
  2068. pSpool->Status &= ~WSPOOL_STATUS_TEMP_CONNECTION;
  2069. LeaveSplSem();
  2070. if (!DeletePrinterConnection( pSpool->pName ))
  2071. {
  2072. DBGMSG( DBG_TRACE, ("CacheClosePrinter failed DeletePrinterConnection %ws %d\n",
  2073. pSpool->pName, GetLastError() ));
  2074. }
  2075. EnterSplSem();
  2076. SPLASSERT( pSpool->signature == WSJ_SIGNATURE );
  2077. }
  2078. SplInSem();
  2079. if ( pSpool->Status & WSPOOL_STATUS_USE_CACHE )
  2080. {
  2081. if ( !(pSpool->Status & WSPOOL_STATUS_ASYNC) && pSpool->RpcHandle )
  2082. {
  2083. DBGMSG(DBG_TRACE, ("CacheClosePrinter pSpool %x RpcHandle %x Status %x\n",
  2084. pSpool, pSpool->RpcHandle, pSpool->Status));
  2085. LeaveSplSem();
  2086. SplOutSem();
  2087. ReturnValue = RemoteClosePrinter( hPrinter );
  2088. EnterSplSem();
  2089. }
  2090. SplInSem();
  2091. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  2092. SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
  2093. LeaveSplSem();
  2094. SplOutSem();
  2095. SplClosePrinter( pSpool->hSplPrinter );
  2096. SplCloseSpooler( pSpool->hIniSpooler );
  2097. EnterSplSem();
  2098. pSpool->hSplPrinter = INVALID_HANDLE_VALUE;
  2099. pSpool->hIniSpooler = INVALID_HANDLE_VALUE;
  2100. pSpool->Status &= ~WSPOOL_STATUS_USE_CACHE;
  2101. FreepSpool( pSpool );
  2102. LeaveSplSem();
  2103. }
  2104. else
  2105. {
  2106. SplInSem();
  2107. if ( pSpool->hIniSpooler != INVALID_HANDLE_VALUE )
  2108. {
  2109. SplCloseSpooler( pSpool->hIniSpooler );
  2110. pSpool->hIniSpooler = INVALID_HANDLE_VALUE;
  2111. }
  2112. LeaveSplSem();
  2113. ReturnValue = RemoteClosePrinter( hPrinter );
  2114. EnterSplSem();
  2115. FreepSpool( pSpool );
  2116. LeaveSplSem();
  2117. }
  2118. SplOutSem();
  2119. return( ReturnValue );
  2120. }
  2121. BOOL
  2122. CacheSyncRpcHandle(
  2123. PWSPOOL pSpool
  2124. )
  2125. {
  2126. DWORD dwLastError = ERROR_SUCCESS;
  2127. EnterSplSem();
  2128. WaitAndAcquireRpcHandle(pSpool);
  2129. if ( pSpool->Status & WSPOOL_STATUS_OPEN_ERROR ) {
  2130. BOOL bRet = FALSE;
  2131. DBGMSG(DBG_WARNING, ("CacheSyncRpcHandle pSpool %x Status %x; setting last error = %d\n",
  2132. pSpool,
  2133. pSpool->Status,
  2134. pSpool->RpcError));
  2135. dwLastError = pSpool->RpcError;
  2136. //
  2137. // If we failed to open the Server because it was unavailable
  2138. // then try and open it again ( provided the asynchronous thread is not active ).
  2139. //
  2140. if ((!pSpool->RpcHandle) &&
  2141. (pSpool->RpcError != ERROR_ACCESS_DENIED)) {
  2142. LeaveSplSem();
  2143. ReturnThreadFromHandle(pSpool);
  2144. EnterSplSem();
  2145. DBGMSG( DBG_WARNING, ("CacheSyncRpcHandle retrying Async OpenPrinter\n"));
  2146. //
  2147. // We have abadoned our RPC handle.
  2148. //
  2149. pSpool->Status |= WSPOOL_STATUS_NO_RPC_HANDLE;
  2150. //
  2151. // We don't have an asynchronous thread for now.
  2152. // We keep the error until we know we have spun a new thread.
  2153. //
  2154. pSpool->Status &= ~WSPOOL_STATUS_ASYNC;
  2155. //
  2156. // If this succeeds, then we know we have a background thread that
  2157. // we can wait on. Otherwise, we don't have an RPC handle and the
  2158. // pSpool status is definitely asynchronous.
  2159. //
  2160. if (DoAsyncRemoteOpenPrinter(pSpool, &pSpool->PrinterDefaults)) {
  2161. //
  2162. // We let the OpenPrinter error come from WaitAndAcquireRpcHandle;
  2163. //
  2164. pSpool->Status &= ~WSPOOL_STATUS_OPEN_ERROR;
  2165. pSpool->RpcError = ERROR_SUCCESS;
  2166. WaitAndAcquireRpcHandle(pSpool);
  2167. //
  2168. // Either get the last error code or if there wasn't an open error clear it.
  2169. //
  2170. if (pSpool->Status & WSPOOL_STATUS_OPEN_ERROR)
  2171. {
  2172. dwLastError = pSpool->RpcError;
  2173. }
  2174. else
  2175. {
  2176. bRet = TRUE;
  2177. }
  2178. }
  2179. }
  2180. LeaveSplSem();
  2181. if (!bRet) {
  2182. if (dwLastError == ERROR_SUCCESS) {
  2183. SetLastError( ERROR_INVALID_FUNCTION );
  2184. }
  2185. else {
  2186. SetLastError( dwLastError );
  2187. }
  2188. }
  2189. return bRet;
  2190. }
  2191. if ( pSpool->RpcHandle &&
  2192. pSpool->Status & WSPOOL_STATUS_RESETPRINTER_PENDING ) {
  2193. DBGMSG(DBG_TRACE, ("CacheSyncRpcHandle calling RemoteResetPrinter\n"));
  2194. pSpool->Status &= ~ WSPOOL_STATUS_RESETPRINTER_PENDING;
  2195. LeaveSplSem();
  2196. if ( ! RemoteResetPrinter( pSpool, &pSpool->PrinterDefaults ) ) {
  2197. EnterSplSem();
  2198. pSpool->Status |= WSPOOL_STATUS_RESETPRINTER_PENDING;
  2199. }
  2200. else {
  2201. EnterSplSem();
  2202. }
  2203. SplInSem();
  2204. }
  2205. LeaveSplSem();
  2206. return TRUE;
  2207. }
  2208. /*++
  2209. Name:
  2210. WaitAndAcquireRpcHandle
  2211. Description:
  2212. If the handle doesn't have an RPC handle assigned to it then wait for the
  2213. background thread to complete opening the RPC handle and write it into the
  2214. foreground structure.
  2215. Arguments:
  2216. pSpool - The foreground handle to use.
  2217. Return Value:
  2218. Nothing
  2219. --*/
  2220. VOID
  2221. WaitAndAcquireRpcHandle(
  2222. IN PWSPOOL pSpool
  2223. )
  2224. {
  2225. SplInSem();
  2226. if ( pSpool->Status & WSPOOL_STATUS_NO_RPC_HANDLE ) {
  2227. if (pSpool->pThread) {
  2228. LeaveSplSem();
  2229. DBGMSG(DBG_TRACE,("CacheSyncRpcHandle Status WSPOOL_STATUS_NO_RPC_HANDLE waiting for RpcHandle....\n"));
  2230. SplOutSem();
  2231. WaitForSingleObject(pSpool->pThread->hWaitValidHandle, INFINITE);
  2232. EnterSplSem();
  2233. pSpool->RpcHandle = pSpool->pThread->hRpcHandle;
  2234. pSpool->Status &= ~WSPOOL_STATUS_NO_RPC_HANDLE;
  2235. }
  2236. }
  2237. if (pSpool->pThread && pSpool->pThread->dwRpcOpenPrinterError != ERROR_SUCCESS) {
  2238. pSpool->Status |= WSPOOL_STATUS_OPEN_ERROR;
  2239. pSpool->RpcError = pSpool->pThread->dwRpcOpenPrinterError;
  2240. }
  2241. }
  2242. BOOL
  2243. CacheGetPrinterDriver(
  2244. HANDLE hPrinter,
  2245. LPWSTR pEnvironment,
  2246. DWORD Level,
  2247. LPBYTE pDriverInfo,
  2248. DWORD cbBuf,
  2249. LPDWORD pcbNeeded
  2250. )
  2251. {
  2252. BOOL ReturnValue = FALSE;
  2253. DWORD dwServerMajorVersion = 0, dwServerMinorVersion = 0, dwPrivateFlag = 0;
  2254. PWSPOOL pSpool = (PWSPOOL) hPrinter, pTempSpool = NULL;
  2255. DWORD dwLastError;
  2256. VALIDATEW32HANDLE( pSpool );
  2257. try {
  2258. if (pSpool->Type != SJ_WIN32HANDLE) {
  2259. SetLastError(ERROR_INVALID_FUNCTION);
  2260. leave;
  2261. }
  2262. if ( !(pSpool->Status & WSPOOL_STATUS_USE_CACHE) ) {
  2263. // Someone is calling GetPrinterDriver without a connection
  2264. // we must NEVER EVER pass the caller a UNC name since they
  2265. // will LoadLibrary accross the network, which might lead
  2266. // to InPageIOErrors ( if the net goes down).
  2267. // The solution is to establish a Temporary Connection for the life
  2268. // of the pSpool handle, the connection will be removed
  2269. // in CacheClosePrinter. The connection will ensure that the
  2270. // drivers are copied locally and a local cache is established
  2271. // for this printer.
  2272. pSpool->Status |= WSPOOL_STATUS_TEMP_CONNECTION;
  2273. pTempSpool = InternalAddPrinterConnection( pSpool->pName );
  2274. if ( !pTempSpool )
  2275. {
  2276. pSpool->Status &= ~WSPOOL_STATUS_TEMP_CONNECTION;
  2277. DBGMSG( DBG_TRACE, ("CacheGetPrinterDriver failed AddPrinterConnection %d\n",
  2278. GetLastError() ));
  2279. leave;
  2280. }
  2281. ReturnValue = OpenCachePrinterOnly( pSpool->pName, &pSpool->hSplPrinter,
  2282. &pSpool->hIniSpooler, NULL, FALSE);
  2283. if ( !ReturnValue )
  2284. {
  2285. SplCloseSpooler( pSpool->hIniSpooler );
  2286. DBGMSG( DBG_WARNING,
  2287. ("CacheGetPrinterDriver Connection OK Failed CacheOpenPrinter %d\n",
  2288. GetLastError() ));
  2289. leave;
  2290. }
  2291. pSpool->Status |= WSPOOL_STATUS_USE_CACHE;
  2292. }
  2293. SPLASSERT( pSpool->Status & WSPOOL_STATUS_USE_CACHE );
  2294. ReturnValue = SplGetPrinterDriverEx( pSpool->hSplPrinter,
  2295. pEnvironment,
  2296. Level,
  2297. pDriverInfo,
  2298. cbBuf,
  2299. pcbNeeded,
  2300. cThisMajorVersion,
  2301. cThisMinorVersion,
  2302. &dwServerMajorVersion,
  2303. &dwServerMinorVersion);
  2304. } finally {
  2305. if (pTempSpool) {
  2306. dwLastError = GetLastError();
  2307. CacheClosePrinter(pTempSpool);
  2308. SetLastError(dwLastError);
  2309. }
  2310. }
  2311. return ReturnValue;
  2312. }
  2313. BOOL
  2314. CacheResetPrinter(
  2315. HANDLE hPrinter,
  2316. LPPRINTER_DEFAULTS pDefault
  2317. )
  2318. {
  2319. PWSPOOL pSpool = (PWSPOOL) hPrinter;
  2320. BOOL ReturnValue = FALSE;
  2321. VALIDATEW32HANDLE(pSpool);
  2322. if (pSpool->Status & WSPOOL_STATUS_USE_CACHE)
  2323. {
  2324. EnterSplSem();
  2325. ReturnValue = SplResetPrinter(pSpool->hSplPrinter, pDefault);
  2326. if (ReturnValue)
  2327. {
  2328. CopypDefaultTopSpool(pSpool, pDefault);
  2329. if (pSpool->RpcHandle)
  2330. {
  2331. //
  2332. // Have RPC Handle
  2333. //
  2334. LeaveSplSem();
  2335. ReturnValue = RemoteResetPrinter(hPrinter, pDefault);
  2336. }
  2337. else
  2338. {
  2339. //
  2340. // No RpcHandle
  2341. //
  2342. DBGMSG( DBG_TRACE, ("CacheResetPrinter %x NO_RPC_HANDLE Status Pending\n",
  2343. pSpool ));
  2344. pSpool->Status |= WSPOOL_STATUS_RESETPRINTER_PENDING;
  2345. LeaveSplSem();
  2346. }
  2347. }
  2348. else
  2349. {
  2350. LeaveSplSem();
  2351. }
  2352. }
  2353. else
  2354. {
  2355. ReturnValue = RemoteResetPrinter(hPrinter, pDefault);
  2356. }
  2357. return ReturnValue;
  2358. }
  2359. BOOL
  2360. CacheGetPrinter(
  2361. HANDLE hPrinter,
  2362. DWORD Level,
  2363. LPBYTE pPrinter,
  2364. DWORD cbBuf,
  2365. LPDWORD pcbNeeded
  2366. )
  2367. {
  2368. PWSPOOL pSpool = (PWSPOOL) hPrinter;
  2369. BOOL ReturnValue = FALSE;
  2370. PWCACHEINIPRINTEREXTRA pExtraData = NULL;
  2371. DWORD LastError = ERROR_SUCCESS;
  2372. DWORD cbSize = 0;
  2373. DWORD cbDevMode;
  2374. DWORD cbSecDesc;
  2375. LPWSTR SourceStrings[sizeof(PRINTER_INFO_2)/sizeof(LPWSTR)];
  2376. LPWSTR *pSourceStrings=SourceStrings;
  2377. LPBYTE pEnd;
  2378. DWORD *pOffsets;
  2379. PPRINTER_INFO_2W pPrinter2 = (PPRINTER_INFO_2)pPrinter;
  2380. PPRINTER_INFO_4W pPrinter4 = (PPRINTER_INFO_4)pPrinter;
  2381. PPRINTER_INFO_5W pPrinter5 = (PPRINTER_INFO_5)pPrinter;
  2382. BOOL bCallRemote = TRUE;
  2383. VALIDATEW32HANDLE( pSpool );
  2384. try {
  2385. if ( (Level == 2 || Level == 5) &&
  2386. (pSpool->Status & WSPOOL_STATUS_USE_CACHE) ) {
  2387. ReturnValue = SplGetPrinterExtra( pSpool->hSplPrinter, &(PBYTE)pExtraData );
  2388. if (ReturnValue && pExtraData) {
  2389. if ( (GetTickCount() - pExtraData->dwTickCount) < REFRESH_TIMEOUT )
  2390. bCallRemote = FALSE;
  2391. }
  2392. pExtraData = NULL;
  2393. }
  2394. if (( Level != 4) &&
  2395. ( ((pSpool->RpcHandle) && bCallRemote ) ||
  2396. IsAdminAccess(&pSpool->PrinterDefaults) ||
  2397. !( pSpool->Status & WSPOOL_STATUS_USE_CACHE ) ||
  2398. ( Level == GET_SECURITY_DESCRIPTOR ) ||
  2399. ( Level == STRESSINFOLEVEL ))) {
  2400. ReturnValue = RemoteGetPrinter( hPrinter,
  2401. Level,
  2402. pPrinter,
  2403. cbBuf,
  2404. pcbNeeded );
  2405. if ( ReturnValue ) {
  2406. leave;
  2407. }
  2408. LastError = GetLastError();
  2409. if (IsAdminAccess(&pSpool->PrinterDefaults) ||
  2410. !( pSpool->Status & WSPOOL_STATUS_USE_CACHE ) ||
  2411. ( Level == GET_SECURITY_DESCRIPTOR ) ||
  2412. ( Level == STRESSINFOLEVEL )) {
  2413. leave;
  2414. }
  2415. SPLASSERT( pSpool->Status & WSPOOL_STATUS_USE_CACHE );
  2416. if (( LastError != RPC_S_SERVER_UNAVAILABLE ) &&
  2417. ( LastError != RPC_S_CALL_FAILED ) &&
  2418. ( LastError != RPC_S_CALL_FAILED_DNE ) &&
  2419. ( LastError != RPC_S_SERVER_TOO_BUSY )) {
  2420. // Valid Error like ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_HANDLE.
  2421. leave;
  2422. }
  2423. }
  2424. //
  2425. // If it is level 4, we must check if we have the information in the cache
  2426. // If not, we return ERROR_INVALID_LEVEL.
  2427. //
  2428. if (Level == 4 && (! (pSpool->Status & WSPOOL_STATUS_USE_CACHE))) {
  2429. LastError = ERROR_INVALID_LEVEL;
  2430. ReturnValue = FALSE;
  2431. }
  2432. else {
  2433. //
  2434. // Assert to make sure the data is in the cache.
  2435. //
  2436. SPLASSERT( pSpool->Status & WSPOOL_STATUS_USE_CACHE );
  2437. switch ( Level ) {
  2438. case 1:
  2439. case 7:
  2440. ReturnValue = SplGetPrinter( pSpool->hSplPrinter,
  2441. Level,
  2442. pPrinter,
  2443. cbBuf,
  2444. pcbNeeded );
  2445. if ( ReturnValue == FALSE ) {
  2446. LastError = GetLastError();
  2447. }
  2448. break;
  2449. case 4:
  2450. EnterSplSem();
  2451. ReturnValue = SplGetPrinterExtra( pSpool->hSplPrinter, &(PBYTE)pExtraData );
  2452. if ( ReturnValue == FALSE ) {
  2453. DBGMSG( DBG_WARNING, ("CacheGetPrinter SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
  2454. SPLASSERT( ReturnValue );
  2455. }
  2456. if ( pExtraData == NULL ) {
  2457. LeaveSplSem();
  2458. break;
  2459. }
  2460. SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
  2461. cbSize = pExtraData->cbPI2;
  2462. *pcbNeeded = cbSize;
  2463. if ( cbSize > cbBuf ) {
  2464. LastError = ERROR_INSUFFICIENT_BUFFER;
  2465. ReturnValue = FALSE;
  2466. LeaveSplSem();
  2467. break;
  2468. }
  2469. *pSourceStrings++ = pExtraData->pPI2->pPrinterName;
  2470. *pSourceStrings++ = pExtraData->pPI2->pServerName;
  2471. pOffsets = PrinterInfo4Strings;
  2472. pEnd = pPrinter + cbBuf;
  2473. pEnd = PackStrings(SourceStrings, pPrinter, pOffsets, pEnd);
  2474. pPrinter4->Attributes = pExtraData->pPI2->Attributes;
  2475. ReturnValue = TRUE;
  2476. LeaveSplSem();
  2477. break;
  2478. case 2:
  2479. EnterSplSem();
  2480. ReturnValue = SplGetPrinterExtra( pSpool->hSplPrinter, &(PBYTE)pExtraData );
  2481. if ( ReturnValue == FALSE ) {
  2482. DBGMSG( DBG_WARNING, ("CacheGetPrinter SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
  2483. SPLASSERT( ReturnValue );
  2484. }
  2485. if ( pExtraData == NULL ) {
  2486. LeaveSplSem();
  2487. break;
  2488. }
  2489. SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
  2490. cbSize = pExtraData->cbPI2;
  2491. *pcbNeeded = cbSize;
  2492. if ( cbSize > cbBuf ) {
  2493. LastError = ERROR_INSUFFICIENT_BUFFER;
  2494. ReturnValue = FALSE;
  2495. LeaveSplSem();
  2496. break;
  2497. }
  2498. // NOTE
  2499. // In the case of EnumerateFavoritePrinters it expects us to pack our
  2500. // strings at the end of the structure not just following it.
  2501. // You might wrongly assume that you could just copy the complete structure
  2502. // inluding strings but you would be wrong.
  2503. *pSourceStrings++ = pExtraData->pPI2->pServerName;
  2504. *pSourceStrings++ = pExtraData->pPI2->pPrinterName;
  2505. *pSourceStrings++ = pExtraData->pPI2->pShareName;
  2506. *pSourceStrings++ = pExtraData->pPI2->pPortName;
  2507. *pSourceStrings++ = pExtraData->pPI2->pDriverName;
  2508. *pSourceStrings++ = pExtraData->pPI2->pComment;
  2509. *pSourceStrings++ = pExtraData->pPI2->pLocation;
  2510. *pSourceStrings++ = pExtraData->pPI2->pSepFile;
  2511. *pSourceStrings++ = pExtraData->pPI2->pPrintProcessor;
  2512. *pSourceStrings++ = pExtraData->pPI2->pDatatype;
  2513. *pSourceStrings++ = pExtraData->pPI2->pParameters;
  2514. pOffsets = PrinterInfo2Strings;
  2515. pEnd = pPrinter + cbBuf;
  2516. pEnd = PackStrings(SourceStrings, pPrinter, pOffsets, pEnd);
  2517. if ( pExtraData->pPI2->pDevMode != NULL ) {
  2518. cbDevMode = ( pExtraData->pPI2->pDevMode->dmSize + pExtraData->pPI2->pDevMode->dmDriverExtra );
  2519. pEnd -= cbDevMode;
  2520. pEnd = (LPBYTE)ALIGN_PTR_DOWN(pEnd);
  2521. pPrinter2->pDevMode = (LPDEVMODE)pEnd;
  2522. CopyMemory(pPrinter2->pDevMode, pExtraData->pPI2->pDevMode, cbDevMode );
  2523. } else {
  2524. pPrinter2->pDevMode = NULL;
  2525. }
  2526. if ( pExtraData->pPI2->pSecurityDescriptor != NULL ) {
  2527. cbSecDesc = GetSecurityDescriptorLength( pExtraData->pPI2->pSecurityDescriptor );
  2528. pEnd -= cbSecDesc;
  2529. pEnd = (LPBYTE)ALIGN_PTR_DOWN(pEnd);
  2530. pPrinter2->pSecurityDescriptor = pEnd;
  2531. CopyMemory( pPrinter2->pSecurityDescriptor, pExtraData->pPI2->pSecurityDescriptor, cbSecDesc );
  2532. } else {
  2533. pPrinter2->pSecurityDescriptor = NULL;
  2534. }
  2535. pPrinter2->Attributes = pExtraData->pPI2->Attributes;
  2536. pPrinter2->Priority = pExtraData->pPI2->Priority;
  2537. pPrinter2->DefaultPriority = pExtraData->pPI2->DefaultPriority;
  2538. pPrinter2->StartTime = pExtraData->pPI2->StartTime;
  2539. pPrinter2->UntilTime = pExtraData->pPI2->UntilTime;
  2540. pPrinter2->Status = pExtraData->pPI2->Status;
  2541. pPrinter2->cJobs = pExtraData->pPI2->cJobs;
  2542. pPrinter2->AveragePPM = pExtraData->pPI2->AveragePPM;
  2543. ReturnValue = TRUE;
  2544. LeaveSplSem();
  2545. break;
  2546. case 5:
  2547. //
  2548. // We need to support a cached level 5 get, the printer, the port
  2549. // name and the attributes we get from the Cached PI2. For the port
  2550. // attributes, we just return the default.
  2551. //
  2552. EnterSplSem();
  2553. ReturnValue = SplGetPrinterExtra( pSpool->hSplPrinter, &(PBYTE)pExtraData );
  2554. if ( ReturnValue == FALSE ) {
  2555. DBGMSG( DBG_WARNING, ("CacheGetPrinter SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
  2556. SPLASSERT( ReturnValue );
  2557. }
  2558. if ( pExtraData == NULL ) {
  2559. LeaveSplSem();
  2560. break;
  2561. }
  2562. SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
  2563. //
  2564. // The size is the size of the printer name, the port name, their NULL
  2565. // terminating characters and the size of the PRINTER_INFO_5 structure
  2566. // itself.
  2567. //
  2568. cbSize = (pExtraData->pPI2->pPrinterName ? (wcslen(pExtraData->pPI2->pPrinterName) + 1) : 0) * sizeof(WCHAR) +
  2569. (pExtraData->pPI2->pPortName ? (wcslen(pExtraData->pPI2->pPortName) + 1) : 0) * sizeof(WCHAR) +
  2570. sizeof(PRINTER_INFO_5);
  2571. *pcbNeeded = cbSize;
  2572. if ( cbSize > cbBuf ) {
  2573. LastError = ERROR_INSUFFICIENT_BUFFER;
  2574. ReturnValue = FALSE;
  2575. LeaveSplSem();
  2576. break;
  2577. }
  2578. *pSourceStrings++ = pExtraData->pPI2->pPrinterName;
  2579. *pSourceStrings++ = pExtraData->pPI2->pPortName;
  2580. pOffsets = PrinterInfo5Strings;
  2581. pEnd = pPrinter + cbBuf;
  2582. pEnd = PackStrings(SourceStrings, pPrinter, pOffsets, pEnd);
  2583. pPrinter5->Attributes = pExtraData->pPI2->Attributes;
  2584. pPrinter5->DeviceNotSelectedTimeout = kDefaultDnsTimeout;
  2585. pPrinter5->TransmissionRetryTimeout = kDefaultTxTimeout;
  2586. ReturnValue = TRUE;
  2587. LeaveSplSem();
  2588. break;
  2589. case 3:
  2590. DBGMSG( DBG_ERROR, ("CacheGetPrinter Level 3 impossible\n"));
  2591. default:
  2592. LastError = ERROR_INVALID_LEVEL;
  2593. ReturnValue = FALSE;
  2594. break;
  2595. }
  2596. }
  2597. } finally {
  2598. if ( !ReturnValue ) {
  2599. SetLastError( LastError );
  2600. }
  2601. }
  2602. return ReturnValue;
  2603. }
  2604. //
  2605. // Called When the Printer is read back from the registry
  2606. //
  2607. PWCACHEINIPRINTEREXTRA
  2608. CacheReadRegistryExtra(
  2609. HKEY hPrinterKey
  2610. )
  2611. {
  2612. PWCACHEINIPRINTEREXTRA pExtraData = NULL;
  2613. LONG ReturnValue;
  2614. PPRINTER_INFO_2W pPrinterInfo2 = NULL;
  2615. DWORD cbSizeRequested = 0;
  2616. DWORD cbSizeInfo2 = 0;
  2617. ReturnValue = RegQueryValueEx( hPrinterKey, szCachePrinterInfo2, NULL, NULL, NULL, &cbSizeRequested );
  2618. if ((ReturnValue == ERROR_MORE_DATA) || (ReturnValue == ERROR_SUCCESS)) {
  2619. cbSizeInfo2 = cbSizeRequested;
  2620. pPrinterInfo2 = AllocSplMem( cbSizeInfo2 );
  2621. if ( pPrinterInfo2 != NULL ) {
  2622. ReturnValue = RegQueryValueEx( hPrinterKey,
  2623. szCachePrinterInfo2,
  2624. NULL, NULL, (LPBYTE)pPrinterInfo2,
  2625. &cbSizeRequested );
  2626. if ( ReturnValue == ERROR_SUCCESS ) {
  2627. //
  2628. // Cached Structures on Disk have offsets for pointers
  2629. //
  2630. if (MarshallUpStructure((LPBYTE)pPrinterInfo2, PrinterInfo2Fields,
  2631. sizeof(PRINTER_INFO_2), NATIVE_CALL))
  2632. {
  2633. pExtraData = AllocExtraData( pPrinterInfo2, cbSizeInfo2 );
  2634. }
  2635. }
  2636. FreeSplMem( pPrinterInfo2 );
  2637. }
  2638. }
  2639. //
  2640. // Read the timestamp for the Cached Printer Data
  2641. //
  2642. if ( pExtraData != NULL ) {
  2643. cbSizeRequested = sizeof( pExtraData->cCacheID );
  2644. ReturnValue = RegQueryValueEx(hPrinterKey,
  2645. szCacheTimeLastChange,
  2646. NULL, NULL,
  2647. (LPBYTE)&pExtraData->cCacheID, &cbSizeRequested );
  2648. // Read the Connection Reference Count
  2649. cbSizeRequested = sizeof( pExtraData->cRef );
  2650. ReturnValue = RegQueryValueEx(hPrinterKey,
  2651. szcRef,
  2652. NULL, NULL,
  2653. (LPBYTE)&pExtraData->cRef, &cbSizeRequested );
  2654. cbSizeRequested = sizeof(pExtraData->dwServerVersion);
  2655. ReturnValue = RegQueryValueEx(hPrinterKey,
  2656. szServerVersion,
  2657. NULL, NULL,
  2658. (LPBYTE)&pExtraData->dwServerVersion,
  2659. &cbSizeRequested);
  2660. }
  2661. return pExtraData;
  2662. }
  2663. BOOL
  2664. CacheWriteRegistryExtra(
  2665. LPWSTR pName,
  2666. HKEY hPrinterKey,
  2667. PWCACHEINIPRINTEREXTRA pExtraData
  2668. )
  2669. {
  2670. PPRINTER_INFO_2 pPrinterInfo2 = NULL;
  2671. DWORD cbSize = 0;
  2672. DWORD dwLastError = ERROR_SUCCESS;
  2673. DWORD Status;
  2674. if ( pExtraData == NULL ) return FALSE;
  2675. SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
  2676. cbSize = pExtraData->cbPI2;
  2677. if ( cbSize != 0 ) {
  2678. pPrinterInfo2 = AllocSplMem( cbSize );
  2679. if ( pPrinterInfo2 != NULL ) {
  2680. CacheCopyPrinterInfo( pPrinterInfo2, pExtraData->pPI2, cbSize );
  2681. //
  2682. // Before writing it to the registry make all pointers offsets
  2683. //
  2684. if (MarshallDownStructure((LPBYTE)pPrinterInfo2, PrinterInfo2Fields,
  2685. sizeof(PRINTER_INFO_2), NATIVE_CALL))
  2686. {
  2687. dwLastError = RegSetValueEx( hPrinterKey, szCachePrinterInfo2, 0,
  2688. REG_BINARY, (LPBYTE)pPrinterInfo2, cbSize );
  2689. }
  2690. else
  2691. {
  2692. dwLastError = GetLastError();
  2693. }
  2694. FreeSplMem( pPrinterInfo2 );
  2695. } else {
  2696. dwLastError = GetLastError();
  2697. }
  2698. }
  2699. //
  2700. // Write Cache TimeStamp to Registry
  2701. //
  2702. cbSize = sizeof ( pExtraData->cCacheID );
  2703. Status = RegSetValueEx( hPrinterKey, szCacheTimeLastChange, 0, REG_DWORD, (LPBYTE)&pExtraData->cCacheID, cbSize );
  2704. if ( Status != ERROR_SUCCESS ) dwLastError = Status;
  2705. cbSize = sizeof(pExtraData->dwServerVersion);
  2706. Status = RegSetValueEx( hPrinterKey, szServerVersion, 0, REG_DWORD, (LPBYTE)&pExtraData->dwServerVersion, cbSize );
  2707. if ( Status != ERROR_SUCCESS ) dwLastError = Status;
  2708. cbSize = sizeof ( pExtraData->cRef );
  2709. Status = RegSetValueEx( hPrinterKey, szcRef, 0, REG_DWORD, (LPBYTE)&pExtraData->cRef, cbSize );
  2710. if ( Status != ERROR_SUCCESS ) dwLastError = Status;
  2711. if ( dwLastError == ERROR_SUCCESS ) {
  2712. return TRUE;
  2713. } else {
  2714. SetLastError( dwLastError );
  2715. return FALSE;
  2716. }
  2717. }
  2718. /*++
  2719. -- ConsistencyCheckCache --
  2720. Routine Description:
  2721. This will determine if the Printer cache needs updating, and update it if necessary.
  2722. It has a timeout value so as to reduce traffic and have less calls going across the wire.
  2723. Checks the remote printer's ChangeID, and if the value differs from one stored in the cache
  2724. it triggers an update.
  2725. Arguments:
  2726. pSpool - Handle to remote printer.
  2727. bCheckPolicy - If TRUE, we should check to policy to see if we are
  2728. allowed to download the driver.
  2729. Return Value:
  2730. None
  2731. --*/
  2732. HRESULT
  2733. ConsistencyCheckCache(
  2734. IN PWSPOOL pSpool,
  2735. IN EDriverDownload eDriverDownload
  2736. )
  2737. {
  2738. BOOL ReturnValue = FALSE;
  2739. BOOL bGotID = TRUE;
  2740. BOOL RefreshNeeded = TRUE;
  2741. DWORD cbBuf = MAX_PRINTER_INFO0;
  2742. BYTE PrinterInfoW0[ MAX_PRINTER_INFO0 ];
  2743. LPPRINTER_INFO_STRESSW pPrinter0 = (LPPRINTER_INFO_STRESSW)&PrinterInfoW0;
  2744. DWORD dwNeeded;
  2745. PWCACHEINIPRINTEREXTRA pExtraData;
  2746. BOOL bGetPrinterExtra = TRUE;
  2747. DWORD NewTick;
  2748. DWORD RemoteChangeID = 0, DataType = 0, SizeNeeded = 0;
  2749. DWORD dwRetVal = ERROR_SUCCESS;
  2750. UINT cRetries = 0;
  2751. enum
  2752. {
  2753. kMaxCacheRefreshAttempts = 10
  2754. };
  2755. HRESULT hResult = S_OK;
  2756. if ( ( !pSpool->RpcHandle ) ||
  2757. !( pSpool->Status & WSPOOL_STATUS_USE_CACHE ))
  2758. {
  2759. return hResult;
  2760. }
  2761. SPLASSERT( pSpool->Status & WSPOOL_STATUS_USE_CACHE );
  2762. //
  2763. // Get the Printer ExtraData from the cache Printer. This is used for the comparisons
  2764. // of the ChangeID and TickCount
  2765. //
  2766. bGetPrinterExtra = SplGetPrinterExtra( pSpool->hSplPrinter, &(PBYTE)pExtraData );
  2767. if ( bGetPrinterExtra && (pExtraData != NULL))
  2768. {
  2769. SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
  2770. SPLASSERT( pExtraData->pPI2 != NULL );
  2771. NewTick = GetTickCount();
  2772. //
  2773. // Make sure an appropriate amount of time has elapsed before hitting
  2774. // the network again.
  2775. //
  2776. //
  2777. // This takes care of the rollover case too, although you may get an extra refresh
  2778. // before the timeout is over.
  2779. //
  2780. if ( (NewTick > ( pExtraData->dwTickCount + GetCacheTimeout()))
  2781. || (NewTick < pExtraData->dwTickCount))
  2782. {
  2783. //
  2784. // Get the new ChangeID from the Server. Try the GetPrinterData call
  2785. // first to reduce network usage. If that fails, fall back to the old way.
  2786. //
  2787. RefreshNeeded = TRUE;
  2788. //
  2789. // Keep Updating our Cache until we match the Server or run out of retries. We dont
  2790. // want to keep doing it in an infinite loop.
  2791. //
  2792. for (cRetries = 0; cRetries < kMaxCacheRefreshAttempts && RefreshNeeded; cRetries++)
  2793. {
  2794. dwRetVal = RemoteGetPrinterData(
  2795. pSpool,
  2796. L"ChangeId",
  2797. &DataType,
  2798. (PBYTE) &RemoteChangeID,
  2799. sizeof(RemoteChangeID),
  2800. &SizeNeeded );
  2801. if ((dwRetVal == ERROR_INVALID_PARAMETER) ||
  2802. (dwRetVal == ERROR_FILE_NOT_FOUND) )
  2803. {
  2804. //
  2805. // Fall back to the old STRESSINFOLEVEL call.
  2806. //
  2807. ReturnValue = RemoteGetPrinter( pSpool, STRESSINFOLEVEL, (LPBYTE)&PrinterInfoW0, cbBuf, &dwNeeded );
  2808. if ( ReturnValue )
  2809. {
  2810. RemoteChangeID = pPrinter0->cChangeID;
  2811. bGotID = TRUE;
  2812. }
  2813. else
  2814. {
  2815. SPLASSERT( GetLastError() != ERROR_INSUFFICIENT_BUFFER );
  2816. DBGMSG( DBG_TRACE, ("ConsistencyCheckCache failed RemoteGetPrinter %d\n", GetLastError() ));
  2817. bGotID = FALSE;
  2818. hResult = HResultFromWin32(GetLastError());
  2819. }
  2820. }
  2821. else if (dwRetVal != ERROR_SUCCESS)
  2822. {
  2823. //
  2824. // Something went badly wrong here.
  2825. //
  2826. DBGMSG( DBG_TRACE, ("ConsistencyCheckCache failed RemoteGetPrinterData %d\n", GetLastError() ));
  2827. bGotID = FALSE;
  2828. hResult = HResultFromWin32(GetLastError());
  2829. }
  2830. else
  2831. {
  2832. bGotID = TRUE;
  2833. }
  2834. if ( bGotID && (pExtraData->cCacheID != RemoteChangeID) )
  2835. {
  2836. DBGMSG( DBG_TRACE, ("ConsistencyCheckCache << Server cCacheID %x Workstation cChangeID %x >>\n",
  2837. RemoteChangeID,
  2838. pExtraData->cCacheID ));
  2839. //
  2840. // Now we want to change the info, since we need to update
  2841. //
  2842. if ( !ReturnValue )
  2843. {
  2844. ReturnValue = RemoteGetPrinter(pSpool, STRESSINFOLEVEL, (LPBYTE)&PrinterInfoW0, cbBuf, &dwNeeded);
  2845. }
  2846. if ( ReturnValue )
  2847. {
  2848. //
  2849. // Update Data we can't get from GetPrinterData.
  2850. // We might be able to leave this out. Not sure yet.
  2851. //
  2852. pExtraData->dwServerVersion = pPrinter0->dwGetVersion;
  2853. pExtraData->pPI2->cJobs = pPrinter0->cJobs;
  2854. pExtraData->pPI2->Status = pPrinter0->Status;
  2855. }
  2856. else
  2857. {
  2858. SPLASSERT( GetLastError() != ERROR_INSUFFICIENT_BUFFER );
  2859. DBGMSG( DBG_TRACE, ("ConsistencyCheckCache failed RemoteGetPrinter %d\n", GetLastError() ));
  2860. hResult = HResultFromWin32(GetLastError());
  2861. }
  2862. //
  2863. // Don't have tons of threads doing a refresh at the same time
  2864. // In stress when there are lots of folks changing printer settings
  2865. // so the cChangeId changes a lot, but we don't want multiple threads
  2866. // all doing a refresh since you get a LOT, it doesn't buy anything
  2867. //
  2868. EnterSplSem();
  2869. if ( !(pExtraData->Status & EXTRA_STATUS_DOING_REFRESH) )
  2870. {
  2871. pExtraData->Status |= EXTRA_STATUS_DOING_REFRESH;
  2872. pExtraData->cCacheID = RemoteChangeID;
  2873. pExtraData->dwTickCount = GetTickCount();
  2874. LeaveSplSem();
  2875. RefreshCompletePrinterCache(pSpool, eDriverDownload);
  2876. EnterSplSem();
  2877. SPLASSERT( pExtraData->Status & EXTRA_STATUS_DOING_REFRESH );
  2878. pExtraData->Status &= ~EXTRA_STATUS_DOING_REFRESH;
  2879. }
  2880. else
  2881. {
  2882. //
  2883. // If someone else is doing the refresh we dont need to do it so we bail out.
  2884. //
  2885. RefreshNeeded = FALSE;
  2886. }
  2887. LeaveSplSem();
  2888. }
  2889. else
  2890. {
  2891. if ( bGotID )
  2892. {
  2893. //
  2894. // We need to Update the TickCount anyway
  2895. //
  2896. pExtraData->dwTickCount = GetTickCount();
  2897. }
  2898. //
  2899. // We either failed the GetPrinterData's or the ChangeID's were
  2900. // the same. Either way, we don't want to try again.
  2901. //
  2902. RefreshNeeded = FALSE;
  2903. } // if gotid
  2904. } // for cRetries < kMaxCacheRefreshAttempts && RefreshNeeded
  2905. } // if newtick > timeout
  2906. } // if SplGetPrinterExtra
  2907. else
  2908. {
  2909. DBGMSG( DBG_WARNING, ("ConsistencyCheckCache SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
  2910. SPLASSERT( bGetPrinterExtra );
  2911. }
  2912. return hResult;
  2913. }
  2914. BOOL
  2915. RefreshPrinterDriver(
  2916. IN PWSPOOL pSpool,
  2917. IN LPWSTR pszDriverName,
  2918. IN EDriverDownload eDriverDownload
  2919. )
  2920. {
  2921. LPBYTE pDriverInfo = NULL;
  2922. DWORD cbDriverInfo = MAX_DRIVER_INFO_VERSION;
  2923. DWORD cbNeeded, Level, dwLastError = ERROR_SUCCESS;
  2924. BOOL bReturnValue = FALSE;
  2925. BOOL bAttemptDownload = FALSE;
  2926. DWORD LevelArray[] = { DRIVER_INFO_VERSION_LEVEL, 6 , 4 , 3 , 2 , 1 , -1 };
  2927. DWORD dwIndex;
  2928. SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
  2929. try {
  2930. if ( !(pDriverInfo = AllocSplMem(cbDriverInfo)) )
  2931. leave;
  2932. //
  2933. // Only download a driver from the remote server if we are allowed to by
  2934. // policy, or, if the trusted path is set up, in which case we might try.
  2935. //
  2936. bAttemptDownload = eDriverDownload == kDownloadDriver || IsTrustedPathConfigured();
  2937. if (bAttemptDownload) {
  2938. //
  2939. // When the trusted path is configured, we do not try the first level
  2940. // (DRIVER_INFO_VERSION_LEVEL) in the LeveLArray, because the code in
  2941. // DownloadDriverFiles doesnt know how to handle it. DownloadDriverFiles
  2942. // fails and returns error invalid level, if the level is
  2943. // DRIVER_INFO_VERSION_LEVEL. We are saving 2 RPC calls to the remote
  2944. // server by checking ahead if the trusted path is configured and passing
  2945. // the right level.
  2946. //
  2947. for (dwIndex = IsTrustedPathConfigured() ? 1 : 0;
  2948. LevelArray[dwIndex] != -1 &&
  2949. !(bReturnValue = CopyDriversLocally(pSpool,
  2950. szEnvironment,
  2951. pDriverInfo,
  2952. LevelArray[dwIndex],
  2953. cbDriverInfo,
  2954. &cbNeeded)) &&
  2955. (dwLastError = GetLastError()) == ERROR_INVALID_LEVEL ;
  2956. dwIndex++ );
  2957. Level = LevelArray[dwIndex];
  2958. if ( !bReturnValue && dwLastError == ERROR_INSUFFICIENT_BUFFER ) {
  2959. FreeSplMem( pDriverInfo );
  2960. if ( pDriverInfo = AllocSplMem(cbNeeded) ) {
  2961. cbDriverInfo = cbNeeded;
  2962. bReturnValue = CopyDriversLocally(pSpool,
  2963. szEnvironment,
  2964. pDriverInfo,
  2965. Level,
  2966. cbDriverInfo,
  2967. &cbNeeded);
  2968. }
  2969. }
  2970. }
  2971. //
  2972. // We could be looking at a remote environment that is different from ours
  2973. // and doesn't have a relevant driver installed in my environment (eg no IA64 driver on x86)
  2974. // or my environment didn't exist on the remote machine (e.g. w2K gold for IA64).
  2975. // Try the local install on the driver name that is being used by the remote printer.
  2976. // Only do this if we don't have SERVER_INSTALL_ONLY as the policy.
  2977. //
  2978. dwLastError = GetLastError();
  2979. if( !bReturnValue &&
  2980. pszDriverName &&
  2981. (dwLastError == ERROR_UNKNOWN_PRINTER_DRIVER ||
  2982. dwLastError == ERROR_INVALID_ENVIRONMENT ||
  2983. !bAttemptDownload) ) {
  2984. bReturnValue = AddDriverFromLocalCab(pszDriverName, pSpool->hIniSpooler);
  2985. }
  2986. } finally {
  2987. FreeSplMem(pDriverInfo);
  2988. }
  2989. if ( !bReturnValue )
  2990. DBGMSG(DBG_WARNING,
  2991. ("RefreshPrinterDriver Failed SplAddPrinterDriver %d\n",
  2992. GetLastError() ));
  2993. return bReturnValue;
  2994. }
  2995. BOOL
  2996. OpenCachePrinterOnly(
  2997. LPWSTR pName,
  2998. LPHANDLE phSplPrinter,
  2999. LPHANDLE phIniSpooler,
  3000. LPPRINTER_DEFAULTS pDefault,
  3001. BOOL bOpenOnly
  3002. )
  3003. {
  3004. PWCHAR pMachineName = NULL;
  3005. PWCHAR pPrinterName;
  3006. BOOL ReturnValue = FALSE;
  3007. PWSTR psz;
  3008. if (!VALIDATE_NAME(pName)) {
  3009. SetLastError(ERROR_INVALID_NAME);
  3010. return FALSE;
  3011. }
  3012. try {
  3013. //
  3014. // See if we already known about this server in the cache
  3015. //
  3016. DBGMSG(DBG_TRACE, ("OpenCachePrinterOnly pName %ws \n",pName));
  3017. //
  3018. // Find the Machine Name
  3019. //
  3020. SPLASSERT ( 0 == _wcsnicmp( pName, L"\\\\", 2 ) ) ;
  3021. pMachineName = AllocSplStr( pName );
  3022. if ( pMachineName == NULL )
  3023. leave;
  3024. //
  3025. // Get Past leading \\ or \\server\printer
  3026. //
  3027. pPrinterName = pMachineName + 2;
  3028. pPrinterName = wcschr( pPrinterName, L'\\' );
  3029. //
  3030. // If this is a \\ServerName or contains ,XcvPort or ,XcvMonitor then don't bother with Cache
  3031. //
  3032. if ( pPrinterName == NULL ||
  3033. wcsstr(pPrinterName, L",XcvPort") ||
  3034. wcsstr(pPrinterName, L",XcvMonitor")) {
  3035. leave;
  3036. } else {
  3037. psz = wcsstr(pName, L",NoCache");
  3038. if (psz) {
  3039. *psz = L'\0';
  3040. leave;
  3041. }
  3042. }
  3043. *pPrinterName = L'\0';
  3044. DBGMSG(DBG_TRACE,("MachineName %ws pName %ws\n", pMachineName, pName));
  3045. //
  3046. // Does this Machine Exist in the Cache ?
  3047. //
  3048. *phIniSpooler = CacheCreateSpooler( pMachineName , bOpenOnly);
  3049. if ( *phIniSpooler == INVALID_HANDLE_VALUE ) {
  3050. SPLASSERT( GetLastError( ));
  3051. leave;
  3052. }
  3053. //
  3054. // Try to Open the Cached Printer
  3055. //
  3056. ReturnValue = ( SplOpenPrinter( pName ,
  3057. phSplPrinter,
  3058. pDefault,
  3059. *phIniSpooler,
  3060. NULL,
  3061. 0) == ROUTER_SUCCESS );
  3062. } finally {
  3063. FreeSplStr( pMachineName );
  3064. }
  3065. return ReturnValue;
  3066. }
  3067. /*++
  3068. Routine Name:
  3069. DoesPolicyAllowPrinterConnectionsToServer
  3070. Description:
  3071. Check to see whether policy allows us to connect to the server. The policy
  3072. might allow unrestricted access to point and print, or it might only allow
  3073. us to only point and print within our domain or it might allow us to only
  3074. point and print to a restricted subset of print servers.
  3075. Arguments:
  3076. pszQueue - The queue we are considering allowing point and
  3077. print on.
  3078. pbAllowPointAndPrint - If TRUE, we can point and print to the server.
  3079. Return Value:
  3080. An HRESULT.
  3081. --*/
  3082. HRESULT
  3083. DoesPolicyAllowPrinterConnectionsToServer(
  3084. IN PCWSTR pszQueue,
  3085. OUT BOOL *pbAllowPointAndPrint
  3086. )
  3087. {
  3088. HRESULT hr = pszQueue && pbAllowPointAndPrint ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  3089. BOOL bAllowPointAndPrint = FALSE;
  3090. HKEY hKeyUser = NULL;
  3091. HKEY hKeyPolicy = NULL;
  3092. //
  3093. // First, are we on a domain? The policies only apply to domain joined machines.
  3094. //
  3095. if (SUCCEEDED(hr) && gbMachineInDomain)
  3096. {
  3097. DWORD dwPointAndPrintRestricted = 0;
  3098. DWORD dwPointAndPrintInForest = 1;
  3099. DWORD dwPointAndPrintTrustedServers = 0;
  3100. DWORD Type;
  3101. DWORD cbData = 0;
  3102. PWSTR pszServerName = NULL;
  3103. cbData = sizeof(dwPointAndPrintRestricted);
  3104. hr = HResultFromWin32(RegOpenCurrentUser(KEY_READ, &hKeyUser));
  3105. //
  3106. // Next, is the policy on.
  3107. //
  3108. if (SUCCEEDED(hr))
  3109. {
  3110. hr = HResultFromWin32(RegOpenKeyEx(hKeyUser, gszPointAndPrintPolicies, 0, KEY_READ, &hKeyPolicy));
  3111. }
  3112. //
  3113. // Read the value.
  3114. //
  3115. if (SUCCEEDED(hr))
  3116. {
  3117. hr = HResultFromWin32(RegQueryValueEx(hKeyPolicy,
  3118. gszPointAndPrintRestricted,
  3119. NULL,
  3120. &Type,
  3121. (BYTE *)&dwPointAndPrintRestricted,
  3122. &cbData));
  3123. hr = SUCCEEDED(hr) ? (Type == REG_DWORD ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_DATA)) : hr;
  3124. }
  3125. if (SUCCEEDED(hr))
  3126. {
  3127. bAllowPointAndPrint = dwPointAndPrintRestricted == 0;
  3128. if (!bAllowPointAndPrint)
  3129. {
  3130. cbData = sizeof(dwPointAndPrintInForest);
  3131. hr = HResultFromWin32(RegQueryValueEx(hKeyPolicy,
  3132. gszPointAndPrintInForest,
  3133. NULL,
  3134. &Type,
  3135. (BYTE *)(&dwPointAndPrintInForest),
  3136. &cbData));
  3137. hr = SUCCEEDED(hr) ? (Type == REG_DWORD ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_DATA)) : hr;
  3138. if (SUCCEEDED(hr))
  3139. {
  3140. cbData = sizeof(dwPointAndPrintTrustedServers);
  3141. hr = HResultFromWin32(RegQueryValueEx(hKeyPolicy,
  3142. gszPointAndPrintTrustedServers,
  3143. NULL,
  3144. &Type,
  3145. (BYTE *)(&dwPointAndPrintTrustedServers),
  3146. &cbData));
  3147. hr = SUCCEEDED(hr) ? (Type == REG_DWORD ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_DATA)) : hr;
  3148. }
  3149. }
  3150. }
  3151. else
  3152. {
  3153. //
  3154. // If the policy is unconfigured, we only allow point and print to
  3155. // a machine within the forst.
  3156. //
  3157. hr = S_OK;
  3158. }
  3159. if (SUCCEEDED(hr) && !bAllowPointAndPrint)
  3160. {
  3161. hr = CheckUserPrintAdmin(&bAllowPointAndPrint);
  3162. }
  3163. //
  3164. // If we are still not allowed to point and print we need to get the
  3165. // server name from the queue name.
  3166. //
  3167. if (SUCCEEDED(hr) && !bAllowPointAndPrint)
  3168. {
  3169. hr = GetServerNameFromPrinterName(pszQueue, &pszServerName);
  3170. }
  3171. //
  3172. // If the policy suggests checking against a set of trusted servers,
  3173. // then let's try that. We do this first because it is the faster
  3174. // check.
  3175. //
  3176. if (SUCCEEDED(hr) && dwPointAndPrintTrustedServers && !bAllowPointAndPrint)
  3177. {
  3178. hr = IsServerExplicitlyTrusted(hKeyPolicy, pszServerName, &bAllowPointAndPrint);
  3179. }
  3180. if (SUCCEEDED(hr) && dwPointAndPrintInForest && !bAllowPointAndPrint)
  3181. {
  3182. hr = IsServerInSameForest(pszServerName, &bAllowPointAndPrint);
  3183. }
  3184. FreeSplMem(pszServerName);
  3185. }
  3186. if (SUCCEEDED(hr) && !gbMachineInDomain)
  3187. {
  3188. bAllowPointAndPrint = TRUE;
  3189. }
  3190. if (pbAllowPointAndPrint)
  3191. {
  3192. *pbAllowPointAndPrint = bAllowPointAndPrint;
  3193. }
  3194. if (hKeyPolicy)
  3195. {
  3196. RegCloseKey(hKeyPolicy);
  3197. }
  3198. if (hKeyUser)
  3199. {
  3200. RegCloseKey(hKeyUser);
  3201. }
  3202. return hr;
  3203. }
  3204. /*++
  3205. Routine Name:
  3206. IsServerExplicitlyTrusted
  3207. Description:
  3208. Returns whether the server is in the semi-colon separated list of explicitely
  3209. trusted servers as read from the policy key. We always use fully qualified
  3210. DNS names for two reasons:
  3211. 1. It prevents the admin having to type in all the possible variants that a
  3212. user might type.
  3213. 2. It prevents the user getting away with specifying another name that maps
  3214. within their DNS search path.
  3215. Arguments:
  3216. hKeyPolicy - The key under which the policy is located.
  3217. pszServerName - The server name. We fully qualify
  3218. pbServerTrusted - If TRUE, then the server is trusted.
  3219. Return Value:
  3220. An HRESULT.
  3221. --*/
  3222. HRESULT
  3223. IsServerExplicitlyTrusted(
  3224. IN HKEY hKeyPolicy,
  3225. IN PCWSTR pszServerName,
  3226. OUT BOOL *pbServerTrusted
  3227. )
  3228. {
  3229. HRESULT hr = hKeyPolicy && pszServerName && pbServerTrusted ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  3230. PWSTR pszServerList = NULL;
  3231. PWSTR pszFullyQualified = NULL;
  3232. BOOL bServerTrusted = FALSE;
  3233. //
  3234. // Get the list of servers, if this is empty, then no point and print.
  3235. //
  3236. if (SUCCEEDED(hr))
  3237. {
  3238. hr = SafeRegQueryValueAsStringPointer(hKeyPolicy, gszPointAndPrintServerList, &pszServerList, 0);
  3239. }
  3240. //
  3241. // See if we can get the actual DNS name, this is done through reverse
  3242. // address lookup and is gauranteed to be singular to the machine (of
  3243. // course, the DNS has to have the mapping).
  3244. //
  3245. if (SUCCEEDED(hr))
  3246. {
  3247. hr = GetFullyQualifiedDomainName(pszServerName, &pszFullyQualified);
  3248. //
  3249. // If full reverse lookup failed, just do the best be can with the host
  3250. // name.
  3251. //
  3252. if (hr == HRESULT_FROM_WIN32(WSANO_DATA))
  3253. {
  3254. hr = GetDNSNameFromServerName(pszServerName, &pszFullyQualified);
  3255. }
  3256. //
  3257. // OK, we could not get the fully qualified name, just use whatever
  3258. // name is specified.
  3259. //
  3260. if (FAILED(hr))
  3261. {
  3262. pszFullyQualified = AllocSplStr(pszServerName);
  3263. hr = pszFullyQualified ? S_OK : HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  3264. }
  3265. }
  3266. //
  3267. // Run the fully qualified server name against the list in the registry.
  3268. //
  3269. if (SUCCEEDED(hr))
  3270. {
  3271. PWSTR pszServerStart = pszServerList;
  3272. PWSTR pszServerEnd = NULL;
  3273. SIZE_T cchFullyQualified = 0;
  3274. cchFullyQualified = wcslen(pszFullyQualified);
  3275. for(pszServerEnd = wcschr(pszServerStart, L';'); !bServerTrusted;
  3276. pszServerStart = pszServerEnd, pszServerEnd = wcschr(pszServerStart, L';'))
  3277. {
  3278. if (pszServerEnd)
  3279. {
  3280. //
  3281. // Are the names exactly the same? (Case insensitive comparison).
  3282. //
  3283. if (pszServerEnd - pszServerStart == cchFullyQualified)
  3284. {
  3285. bServerTrusted = !_wcsnicmp(pszFullyQualified, pszServerStart, cchFullyQualified);
  3286. }
  3287. //
  3288. // Skip past the ; to the next server name.
  3289. //
  3290. pszServerEnd++;
  3291. }
  3292. else
  3293. {
  3294. bServerTrusted = !_wcsicmp(pszFullyQualified, pszServerStart);
  3295. break;
  3296. }
  3297. }
  3298. }
  3299. if (SUCCEEDED(hr))
  3300. {
  3301. *pbServerTrusted = bServerTrusted;
  3302. }
  3303. FreeSplMem(pszServerList);
  3304. FreeSplMem(pszFullyQualified);
  3305. return hr;
  3306. }
  3307. /*++
  3308. Routine Name:
  3309. IsServerInSameForest
  3310. Description:
  3311. This routine determines whether the given server is in the same forest as we
  3312. are.
  3313. Arguments:
  3314. pszServerName - The server name.
  3315. pbServerInSameForest - If TRUE, then the server is in the same forest.
  3316. Return Value:
  3317. An HRESULT.
  3318. --*/
  3319. HRESULT
  3320. IsServerInSameForest(
  3321. IN PCWSTR pszServerName,
  3322. OUT BOOL *pbServerInSameForest
  3323. )
  3324. {
  3325. WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 2];
  3326. DWORD cchComputerName = COUNTOF(ComputerName);
  3327. PSID pSid = NULL;
  3328. PWSTR pszDomainName = NULL;
  3329. DWORD cbSid = 0;
  3330. DWORD cchDomainName = 0;
  3331. PWSTR pszFullName = NULL;
  3332. BOOL bServerInForest = FALSE;
  3333. BOOL bSameAddress = FALSE;
  3334. PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
  3335. PUSER_INFO_1 pUserInfo1 = NULL;
  3336. SID_NAME_USE SidType;
  3337. HRESULT hr = pszServerName && pbServerInSameForest ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  3338. //
  3339. // Use the fully qualified DNS name if we can get it. This is to handle
  3340. // dotted notation resolution to the names. If we can't get it, then we
  3341. // just use the passed in name. This requires reverse domain lookup, which
  3342. // might not be available.
  3343. //
  3344. hr = GetFullyQualifiedDomainName(pszServerName, &pszFullName);
  3345. if (SUCCEEDED(hr))
  3346. {
  3347. hr = DnsHostnameToComputerName(pszFullName, ComputerName, &cchComputerName) ? S_OK : GetLastErrorAsHResultAndFail();
  3348. }
  3349. else if (hr == HRESULT_FROM_WIN32(WSANO_DATA))
  3350. {
  3351. hr = DnsHostnameToComputerName(pszServerName, ComputerName, &cchComputerName) ? S_OK : GetLastErrorAsHResultAndFail();
  3352. }
  3353. //
  3354. // Check to see whether the truncated computer name and the server name are
  3355. // the same machine. This is to prevent printserver.hack3rz.org being confused
  3356. // with printserver.mydomain.com.
  3357. //
  3358. if (SUCCEEDED(hr))
  3359. {
  3360. hr = CheckSamePhysicalAddress(pszServerName, ComputerName, &bSameAddress);
  3361. }
  3362. if (SUCCEEDED(hr) && bSameAddress)
  3363. {
  3364. if (SUCCEEDED(hr))
  3365. {
  3366. hr = StringCchCat(ComputerName, COUNTOF(ComputerName), L"$");
  3367. }
  3368. if (SUCCEEDED(hr))
  3369. {
  3370. hr = LookupAccountName(NULL, ComputerName, NULL, &cbSid, NULL, &cchDomainName, &SidType) ? S_OK : GetLastErrorAsHResultAndFail();
  3371. //
  3372. // This should only return ERROR_INSUFFICIENT_BUFFER, any other return
  3373. // or a success is a failure.
  3374. //
  3375. hr = hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) ? S_OK : (SUCCEEDED(hr) ? E_FAIL : hr);
  3376. }
  3377. if (SUCCEEDED(hr))
  3378. {
  3379. pszDomainName = AllocSplMem(cchDomainName * sizeof(WCHAR));
  3380. pSid = AllocSplMem(cbSid);
  3381. hr = pszDomainName && pSid ? S_OK : HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  3382. }
  3383. if (SUCCEEDED(hr))
  3384. {
  3385. hr = LookupAccountName(NULL, ComputerName, pSid, &cbSid, pszDomainName, &cchDomainName, &SidType) ? S_OK : GetLastErrorAsHResultAndFail();
  3386. }
  3387. //
  3388. // COMPUTER$ accounts are returned as user accounts when looked up, we don't
  3389. // want a disabled or inactive account.
  3390. //
  3391. if (SUCCEEDED(hr) && SidType == SidTypeUser)
  3392. {
  3393. //
  3394. // The account must be active. Otherwise I could create a workgroup machine
  3395. // with the same name as an inactive account and fox the system that way.
  3396. //
  3397. hr = HResultFromWin32(DsGetDcName(NULL, pszDomainName, NULL, NULL, DS_IS_FLAT_NAME | DS_RETURN_DNS_NAME, &pDomainControllerInfo));
  3398. if (SUCCEEDED(hr))
  3399. {
  3400. hr = HResultFromWin32(NetUserGetInfo(pDomainControllerInfo->DomainControllerName, ComputerName, 1, (BYTE **)(&pUserInfo1)));
  3401. }
  3402. //
  3403. // The account cannot be locked out or disabled.
  3404. //
  3405. if (SUCCEEDED(hr))
  3406. {
  3407. bServerInForest = !(pUserInfo1->usri1_flags & (UF_LOCKOUT | UF_ACCOUNTDISABLE));
  3408. }
  3409. }
  3410. }
  3411. if (pbServerInSameForest)
  3412. {
  3413. *pbServerInSameForest = bServerInForest;
  3414. }
  3415. if (pUserInfo1)
  3416. {
  3417. NetApiBufferFree(pUserInfo1);
  3418. }
  3419. if (pDomainControllerInfo)
  3420. {
  3421. NetApiBufferFree(pDomainControllerInfo);
  3422. }
  3423. FreeSplMem(pszDomainName);
  3424. FreeSplMem(pSid);
  3425. FreeSplMem(pszFullName);
  3426. return hr;
  3427. }