Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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