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

2240 lines
65 KiB

  1. /*++
  2. Copyright (c) 1990 - 1996 Microsoft Corporation
  3. Module Name:
  4. openprn.c
  5. Abstract:
  6. This module provides all the public exported APIs relating to Printer
  7. management for the Local Print Providor
  8. LocalOpenPrinter
  9. SplClosePrinter
  10. Author:
  11. Dave Snipp (DaveSn) 15-Mar-1991
  12. Revision History:
  13. Matthew A Felton (mattfe) June 1994 RapidPrint
  14. Jan 95 Cleanup CreatePrinterHandle
  15. --*/
  16. #define NOMINMAX
  17. #include <precomp.h>
  18. #include "jobid.h"
  19. #include "filepool.hxx"
  20. #define SZXCVPORT L"XcvPort "
  21. #define SZXCVMONITOR L"XcvMonitor "
  22. LPCTSTR pszLocalOnlyToken = L"LocalOnly";
  23. LPCTSTR pszLocalsplOnlyToken = L"LocalsplOnly";
  24. HANDLE
  25. CreatePrinterHandle(
  26. LPWSTR pPrinterName,
  27. LPWSTR pFullMachineName,
  28. PINIPRINTER pIniPrinter,
  29. PINIPORT pIniPort,
  30. PINIPORT pIniNetPort,
  31. PINIJOB pIniJob,
  32. DWORD TypeofHandle,
  33. HANDLE hPort,
  34. PPRINTER_DEFAULTS pDefaults,
  35. PINISPOOLER pIniSpooler,
  36. DWORD DesiredAccess,
  37. LPBYTE pSplClientInfo,
  38. DWORD dwLevel,
  39. HANDLE hReadFile
  40. )
  41. {
  42. PSPOOL pSpool = NULL;
  43. BOOL bStatus = FALSE;
  44. HANDLE hReturnHandle = NULL;
  45. LPDEVMODE pDevMode = NULL;
  46. PSPLCLIENT_INFO_1 pSplClientInfo1 = (PSPLCLIENT_INFO_1)pSplClientInfo;
  47. DWORD ObjectType;
  48. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  49. if ( dwLevel && ( dwLevel != 1 || !pSplClientInfo) ) {
  50. DBGMSG(DBG_ERROR,
  51. ("CreatePrintHandle: Invalid client info %x - %d\n",
  52. pSplClientInfo, dwLevel));
  53. pSplClientInfo = NULL;
  54. }
  55. try {
  56. pSpool = (PSPOOL)AllocSplMem( SPOOL_SIZE );
  57. if ( pSpool == NULL ) {
  58. DBGMSG( DBG_WARNING, ("CreatePrinterHandle failed to allocate SPOOL %d\n", GetLastError() ));
  59. leave;
  60. }
  61. pSpool->signature = SJ_SIGNATURE;
  62. pSpool->pIniPrinter = pIniPrinter;
  63. pSpool->hReadFile = hReadFile;
  64. pSpool->pIniPort = pIniPort;
  65. pSpool->pIniNetPort = pIniNetPort;
  66. pSpool->pIniJob = pIniJob;
  67. pSpool->TypeofHandle = TypeofHandle;
  68. pSpool->hPort = hPort;
  69. pSpool->Status = 0;
  70. pSpool->pDevMode = NULL;
  71. pSpool->pName = AllocSplStr( pPrinterName );
  72. pSpool->pFullMachineName = AllocSplStr( pFullMachineName );
  73. pSpool->pSplMapView = NULL;
  74. pSpool->pMappedJob = NULL;
  75. pSpool->hClientToken = NULL;
  76. if ( pSpool->pName == NULL ||
  77. ( pFullMachineName && !pSpool->pFullMachineName )) {
  78. leave;
  79. }
  80. pSpool->pIniSpooler = pIniSpooler;
  81. if (!GetClientSessionData(&pSpool->SessionId))
  82. {
  83. leave;
  84. }
  85. //
  86. // Check if it's a local call.
  87. //
  88. if( TypeofHandle & PRINTER_HANDLE_REMOTE_CALL ) {
  89. //
  90. // We get other useful info like build #, client architecture
  91. // we do not need this info now -- so we do not put it in PSPOOL
  92. //
  93. if ( !pSplClientInfo ) {
  94. if ( IsNamedPipeRpcCall() )
  95. TypeofHandle |= PRINTER_HANDLE_3XCLIENT;
  96. } else if ( dwLevel == 1 ) {
  97. SPLASSERT(pSplClientInfo1->pUserName && pSplClientInfo1->pMachineName);
  98. CopyMemory(&pSpool->SplClientInfo1, pSplClientInfo1, sizeof(SPLCLIENT_INFO_1));
  99. pSpool->SplClientInfo1.pUserName = AllocSplStr(pSplClientInfo1->pUserName);
  100. pSpool->SplClientInfo1.pMachineName = AllocSplStr(pSplClientInfo1->pMachineName);
  101. if ( !pSpool->SplClientInfo1.pUserName ||
  102. !pSpool->SplClientInfo1.pMachineName ) {
  103. DBGMSG(DBG_WARNING, ("CreatePrinterHandle: could not allocate memory for user name or machine name\n"));
  104. }
  105. }
  106. }
  107. if ((TypeofHandle & PRINTER_HANDLE_SERVER) ||
  108. (TypeofHandle & PRINTER_HANDLE_XCV_PORT)) {
  109. bStatus = ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
  110. DesiredAccess,
  111. pSpool,
  112. &pSpool->GrantedAccess,
  113. pIniSpooler );
  114. if ( bStatus &&
  115. (TypeofHandle & PRINTER_HANDLE_REMOTE_CALL) &&
  116. ( (DesiredAccess & SERVER_ACCESS_ADMINISTER) &&
  117. ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  118. SERVER_ACCESS_ADMINISTER,
  119. NULL,
  120. NULL,
  121. pIniSpooler)) ){
  122. pSpool->TypeofHandle |= PRINTER_HANDLE_REMOTE_ADMIN;
  123. }
  124. ObjectType = SPOOLER_OBJECT_SERVER;
  125. } else if( TypeofHandle & PRINTER_HANDLE_JOB ){
  126. bStatus = ValidateObjectAccess( SPOOLER_OBJECT_DOCUMENT,
  127. DesiredAccess,
  128. pSpool->pIniJob,
  129. &pSpool->GrantedAccess,
  130. pIniSpooler );
  131. ObjectType = SPOOLER_OBJECT_DOCUMENT;
  132. } else {
  133. bStatus = ValidateObjectAccess( SPOOLER_OBJECT_PRINTER,
  134. DesiredAccess,
  135. pSpool,
  136. &pSpool->GrantedAccess,
  137. pIniSpooler );
  138. ObjectType = SPOOLER_OBJECT_PRINTER;
  139. }
  140. MapGenericToSpecificAccess( ObjectType,
  141. pSpool->GrantedAccess,
  142. &pSpool->GrantedAccess);
  143. if ( !bStatus ) {
  144. SetLastError(ERROR_ACCESS_DENIED);
  145. leave;
  146. }
  147. if ( pIniPrinter ) {
  148. if ( pDefaults ) {
  149. //
  150. // Allocate DevMode
  151. //
  152. if ( pDefaults->pDevMode ) {
  153. pDevMode = pDefaults->pDevMode;
  154. } else {
  155. pDevMode = pIniPrinter->pDevMode;
  156. }
  157. if ( pDevMode != NULL ) {
  158. pSpool->pDevMode = AllocSplMem( pDevMode->dmSize + pDevMode->dmDriverExtra );
  159. if ( pSpool->pDevMode == NULL ) {
  160. DBGMSG(DBG_WARNING, ("CreatePrinterHandle failed allocation for devmode %d\n", GetLastError() ));
  161. leave;
  162. }
  163. memcpy( pSpool->pDevMode, pDevMode, pDevMode->dmSize + pDevMode->dmDriverExtra );
  164. }
  165. }
  166. //
  167. // Allocate Datype and Print Processor
  168. //
  169. if ( pDefaults && pDefaults->pDatatype ) {
  170. pSpool->pDatatype = AllocSplStr( pDefaults->pDatatype );
  171. pSpool->pIniPrintProc = FindDatatype( pIniPrinter->pIniPrintProc, pSpool->pDatatype );
  172. } else {
  173. pSpool->pDatatype = AllocSplStr( pIniPrinter->pDatatype );
  174. pSpool->pIniPrintProc = pIniPrinter->pIniPrintProc;
  175. }
  176. if ( pSpool->pIniPrintProc == NULL ) {
  177. DBGMSG( DBG_WARNING,("CreatePrinterHandle failed to PrintProcessor for datatype %ws %d\n",
  178. pSpool->pDatatype, GetLastError() ));
  179. SetLastError( ERROR_INVALID_DATATYPE );
  180. leave;
  181. }
  182. SPLASSERT( pSpool->pIniPrintProc->signature == IPP_SIGNATURE );
  183. pSpool->pIniPrintProc->cRef++;
  184. if ( pSpool->pDatatype == NULL ) {
  185. DBGMSG( DBG_WARNING,("CreatePrinterHandle failed to allocate DataType %x\n", GetLastError() ));
  186. SetLastError( ERROR_INVALID_DATATYPE );
  187. leave;
  188. }
  189. }
  190. //
  191. // Add us to the linked list of handles for this printer.
  192. // This will be scanned when a change occurs on the printer,
  193. // and will be updated with a flag indicating what type of
  194. // change it was.
  195. // There is a flag for each handle, because we cannot guarantee
  196. // that all threads will have time to reference a flag in the
  197. // INIPRINTER before it is updated.
  198. //
  199. if ( TypeofHandle & PRINTER_HANDLE_PRINTER ) {
  200. pSpool->pNext = pSpool->pIniPrinter->pSpool;
  201. pSpool->pIniPrinter->pSpool = pSpool;
  202. } else if ( (TypeofHandle & PRINTER_HANDLE_SERVER) ||
  203. (TypeofHandle & PRINTER_HANDLE_XCV_PORT) ) {
  204. //
  205. // For server handles, hang them off the global IniSpooler:
  206. //
  207. pSpool->pNext = pIniSpooler->pSpool;
  208. pIniSpooler->pSpool = pSpool;
  209. INCSPOOLERREF( pIniSpooler );
  210. } else if( TypeofHandle & PRINTER_HANDLE_JOB ){
  211. INCJOBREF( pIniJob );
  212. }
  213. // Note Only PRINTER_HANDLE_PRINTER are attatched to the
  214. // pIniPrinter, since those are the handle which will require
  215. // change notifications.
  216. if ( pSpool->pIniPrinter != NULL ) {
  217. INCPRINTERREF( pSpool->pIniPrinter );
  218. }
  219. hReturnHandle = (HANDLE)pSpool;
  220. } finally {
  221. if ( hReturnHandle == NULL ) {
  222. // Failure CleanUP
  223. if ( pSpool != NULL ) {
  224. FreeSplStr(pSpool->SplClientInfo1.pUserName);
  225. FreeSplStr(pSpool->SplClientInfo1.pMachineName);
  226. FreeSplStr( pSpool->pName ) ;
  227. FreeSplStr( pSpool->pDatatype );
  228. FreeSplStr(pSpool->pFullMachineName);
  229. if ( pSpool->pIniPrintProc != NULL )
  230. pSpool->pIniPrintProc->cRef--;
  231. if ( pSpool->pDevMode )
  232. FreeSplMem( pSpool->pDevMode );
  233. FreeSplMem( pSpool );
  234. pSpool = NULL;
  235. }
  236. }
  237. }
  238. return hReturnHandle;
  239. }
  240. BOOL
  241. DeletePrinterHandle(
  242. PSPOOL pSpool
  243. )
  244. {
  245. BOOL bRet = FALSE;
  246. SplInSem();
  247. if (pSpool->pIniPrintProc) {
  248. pSpool->pIniPrintProc->cRef--;
  249. }
  250. if (pSpool->pDevMode)
  251. FreeSplMem(pSpool->pDevMode);
  252. if (pSpool->hClientToken)
  253. {
  254. CloseHandle(pSpool->hClientToken);
  255. }
  256. FreeSplStr(pSpool->SplClientInfo1.pUserName);
  257. FreeSplStr(pSpool->SplClientInfo1.pMachineName);
  258. FreeSplStr(pSpool->pDatatype);
  259. SetSpoolClosingChange(pSpool);
  260. FreeSplStr(pSpool->pName);
  261. FreeSplStr(pSpool->pFullMachineName);
  262. bRet = ObjectCloseAuditAlarm( szSpooler, pSpool, pSpool->GenerateOnClose );
  263. //
  264. // If there is a WaitForPrinterChange outstanding, we can't free
  265. // the pSpool, since we may try and reference it.
  266. //
  267. // Log warning for freed printer handle
  268. DBGMSG(DBG_TRACE, ("DeletePrinterHandle 0x%x", pSpool));
  269. if (pSpool->ChangeEvent) {
  270. pSpool->eStatus |= STATUS_PENDING_DELETION;
  271. } else {
  272. FreeSplMem(pSpool);
  273. }
  274. return TRUE;
  275. }
  276. DWORD
  277. CreateServerHandle(
  278. LPWSTR pPrinterName,
  279. LPHANDLE pPrinterHandle,
  280. LPPRINTER_DEFAULTS pDefaults,
  281. PINISPOOLER pIniSpooler,
  282. DWORD dwTypeofHandle
  283. )
  284. {
  285. DWORD DesiredAccess;
  286. DWORD ReturnValue = ROUTER_STOP_ROUTING;
  287. DBGMSG(DBG_TRACE, ("OpenPrinter(%ws)\n",
  288. pPrinterName ? pPrinterName : L"NULL"));
  289. EnterSplSem();
  290. if (!pDefaults || !pDefaults->DesiredAccess)
  291. DesiredAccess = SERVER_READ;
  292. else
  293. DesiredAccess = pDefaults->DesiredAccess;
  294. if (*pPrinterHandle = CreatePrinterHandle( pIniSpooler->pMachineName,
  295. pPrinterName,
  296. NULL, NULL, NULL, NULL,
  297. dwTypeofHandle,
  298. NULL,
  299. pDefaults,
  300. pIniSpooler,
  301. DesiredAccess,
  302. NULL,
  303. 0,
  304. INVALID_HANDLE_VALUE )){
  305. ReturnValue = ROUTER_SUCCESS;
  306. }
  307. LeaveSplSem();
  308. DBGMSG(DBG_TRACE, ("OpenPrinter returned handle %08x\n", *pPrinterHandle));
  309. return ReturnValue;
  310. }
  311. PINIPRINTER
  312. FindPrinterShare(
  313. LPCWSTR pszShareName,
  314. PINISPOOLER pIniSpooler
  315. )
  316. /*++
  317. Routine Description:
  318. Try and find the share name in our list of printers.
  319. Note: Even if the printer isn't shared, we still return a match.
  320. The caching code will work because it explicitly turns off
  321. the PRINTER_ATTRIBUTE_SHARE bit so that the cache pIniSpooler
  322. doesn't create a server thread or call NetShareAdd/Del.
  323. In the future, consider changing this to check the share bit.
  324. Create a new bit SPL_SHARE_PRINTERS that indicates whether sharing
  325. housekeeping should be done.
  326. Arguments:
  327. pszShareName - Name of share to search for.
  328. Return Value:
  329. PINIPRINTER Printer that has the share name, NULL if no printer.
  330. --*/
  331. {
  332. PINIPRINTER pIniPrinter;
  333. SplInSem();
  334. if (pszShareName && pszShareName[0]) {
  335. for( pIniPrinter = pIniSpooler->pIniPrinter;
  336. pIniPrinter;
  337. pIniPrinter = pIniPrinter->pNext ){
  338. if (pIniPrinter->pShareName &&
  339. !lstrcmpi(pIniPrinter->pShareName, pszShareName)) {
  340. return pIniPrinter;
  341. }
  342. }
  343. }
  344. return NULL;
  345. }
  346. PINISPOOLER
  347. LocalFindSpoolerByNameIncRef(
  348. LPWSTR pszPrinterName,
  349. LPTSTR *ppszLocalName OPTIONAL
  350. )
  351. /*++
  352. Routine Description:
  353. See if the printer is owned by localspl. This is a special
  354. case to check if it's a masquarading printer.
  355. Normally we would check for \\Server\Printer to see if \\Server
  356. is our machine, but we have to look for \\MasqServer\Printer
  357. too.
  358. Arguments:
  359. pPrinterName - Name to check.
  360. ppszLocalName - Returns pointer to local name. OPTIONAL
  361. Return Value:
  362. PINISPOOLER - Spooler match.
  363. NULL - No match.
  364. --*/
  365. {
  366. PINISPOOLER pIniSpooler;
  367. LPWSTR pTemp;
  368. if (!ppszLocalName)
  369. ppszLocalName = &pTemp;
  370. SplOutSem();
  371. //
  372. // At this time we do not know if the server name in pName refers to our local
  373. // machine. We are trying to add the server name to the name cache. The name
  374. // cache functions decide if the name refers to the local machine and if positive,
  375. // add an entry for it in the cache.
  376. //
  377. CacheAddName(pszPrinterName);
  378. EnterSplSem();
  379. pIniSpooler = FindSpoolerByName( pszPrinterName,
  380. ppszLocalName );
  381. if( !pIniSpooler ){
  382. //
  383. // Check if it's a masq printer.
  384. //
  385. // If the local name isn't the same as the original name, it
  386. // is in the syntax "\\server\printer." In this case it may
  387. // be a masq printer, so check if the printer exists in the
  388. // local spooler by this name.
  389. //
  390. if(*ppszLocalName != pszPrinterName ){
  391. //
  392. // Search for the printer, but remove any suffixes it
  393. // may have.
  394. //
  395. WCHAR string[MAX_UNC_PRINTER_NAME + PRINTER_NAME_SUFFIX_MAX];
  396. //
  397. // The pIniSpooler is NULL, so if this function fails, we will
  398. // set the last error is BoolFromHResult and return NULL for
  399. // failue.
  400. //
  401. if (BoolFromHResult(StringCchCopy(string, COUNTOF(string), pszPrinterName))) {
  402. if( pTemp = wcschr( string, L',' )){
  403. *pTemp = 0;
  404. }
  405. if(FindPrinter(string, pLocalIniSpooler )){
  406. //
  407. // The masq printer exists. The local name for this
  408. // masq printer is "\\MasqServer\Printer," so we must
  409. // reflect this change in ppszLocalName. This will ensure
  410. // that the pIniPrinter is found.
  411. //
  412. *ppszLocalName = pszPrinterName;
  413. pIniSpooler = pLocalIniSpooler;
  414. }
  415. }
  416. }
  417. }
  418. if( pIniSpooler ){
  419. INCSPOOLERREF( pIniSpooler );
  420. }
  421. LeaveSplSem();
  422. return pIniSpooler;
  423. }
  424. VOID
  425. LocalFindSpoolerByNameDecRef(
  426. PINISPOOLER pIniSpooler
  427. )
  428. /*++
  429. Routine Description:
  430. Matching call to LocalFindSpoolerByNameIncRef.
  431. Arguments:
  432. pIniSpooler - Spooler to derement; can be NULL.
  433. Return Value:
  434. --*/
  435. {
  436. EnterSplSem();
  437. if( pIniSpooler ){
  438. DECSPOOLERREF( pIniSpooler );
  439. }
  440. LeaveSplSem();
  441. }
  442. DWORD
  443. LocalOpenPrinter(
  444. LPWSTR pPrinterName,
  445. LPHANDLE pPrinterHandle,
  446. LPPRINTER_DEFAULTS pDefaults
  447. )
  448. {
  449. return LocalOpenPrinterEx( pPrinterName,
  450. pPrinterHandle,
  451. pDefaults,
  452. NULL,
  453. 0 );
  454. }
  455. DWORD
  456. LocalOpenPrinterEx(
  457. LPWSTR pPrinterName,
  458. LPHANDLE pPrinterHandle,
  459. LPPRINTER_DEFAULTS pDefaults,
  460. LPBYTE pSplClientInfo,
  461. DWORD dwLevel
  462. )
  463. {
  464. DWORD dwReturn;
  465. LPWSTR pszLocalName;
  466. PINISPOOLER pIniSpooler = LocalFindSpoolerByNameIncRef( pPrinterName,
  467. &pszLocalName);
  468. //
  469. // WMI Trace Event.
  470. //
  471. LogWmiTraceEvent(0, EVENT_TRACE_TYPE_SPL_ENDTRACKTHREAD, NULL);
  472. if( !pIniSpooler ) {
  473. //
  474. // Check for PrinterName,LocalsplOnly.
  475. // If we see this token, then fail the call since
  476. // we only want to check localspl.
  477. //
  478. LPCTSTR pSecondPart;
  479. if( pSecondPart = wcschr( pPrinterName, L',' )){
  480. ++pSecondPart;
  481. if( wcscmp( pSecondPart, pszLocalsplOnlyToken ) == STRINGS_ARE_EQUAL ){
  482. SetLastError( ERROR_INVALID_PRINTER_NAME );
  483. return ROUTER_STOP_ROUTING;
  484. }
  485. }
  486. SetLastError( ERROR_INVALID_NAME );
  487. return ROUTER_UNKNOWN;
  488. }
  489. dwReturn = SplOpenPrinter( pPrinterName,
  490. pPrinterHandle,
  491. pDefaults,
  492. pIniSpooler,
  493. pSplClientInfo,
  494. dwLevel);
  495. LocalFindSpoolerByNameDecRef( pIniSpooler );
  496. //
  497. // We need to give other provider a chance to get the printer name
  498. //
  499. return dwReturn;
  500. }
  501. DWORD
  502. OpenLocalPrinterName(
  503. LPCWSTR pPrinterName,
  504. PINISPOOLER pIniSpooler,
  505. PDWORD pTypeofHandle,
  506. PINIPRINTER* ppIniPrinter,
  507. PINIPORT* ppIniPort,
  508. PINIPORT* ppIniNetPort,
  509. PHANDLE phPort,
  510. PDWORD pOpenPortError,
  511. LPPRINTER_DEFAULTS pDefaults
  512. )
  513. {
  514. PINIPRINTER pIniPrinter;
  515. PINIPORT pIniPort;
  516. PINIPORT pIniNetPort = NULL;
  517. BOOL bOpenPrinterPort;
  518. LPWSTR pDatatype;
  519. //
  520. // If the printer name is the name of a local printer:
  521. //
  522. // Find the first port the printer's attached to.
  523. //
  524. // If the port has a monitor (e.g. LPT1:, COM1 etc.),
  525. // we're OK,
  526. // Otherwise
  527. // try to open the port - this may be a network printer
  528. //
  529. if( ( pIniPrinter = FindPrinter( pPrinterName, pIniSpooler )) ||
  530. ( pIniPrinter = FindPrinterShare( pPrinterName, pIniSpooler ))) {
  531. pIniPort = FindIniPortFromIniPrinter( pIniPrinter );
  532. if( pIniPort && ( pIniPort->Status & PP_MONITOR )){
  533. //
  534. // A Printer that has a Port with a Monitor is not a
  535. // DownLevel Connection (or LocalPrinter acting as a
  536. // remote printer - "Masquarade" case).
  537. //
  538. pIniPort = NULL;
  539. }
  540. pDatatype = (pDefaults && pDefaults->pDatatype) ?
  541. pDefaults->pDatatype :
  542. NULL;
  543. //
  544. // Validate datatypes for both masq and local.
  545. //
  546. if( pDatatype && !FindDatatype( NULL, pDatatype )){
  547. goto BadDatatype;
  548. }
  549. if( pIniPort ){
  550. //
  551. // DownLevel Connection Printer; save it in pIniNetPort.
  552. // SetPrinterPorts checks this value.
  553. //
  554. pIniNetPort = pIniPort;
  555. //
  556. // Validate datatype. We only send RAW across the net
  557. // to masq printers.
  558. //
  559. if( pDatatype && !ValidRawDatatype( pDatatype )){
  560. goto BadDatatype;
  561. }
  562. //
  563. // There is a network port associated with this printer.
  564. // Make sure we can open it, and get the handle to use on
  565. // future API calls:
  566. //
  567. INCPRINTERREF(pIniPrinter);
  568. LeaveSplSem();
  569. bOpenPrinterPort = OpenPrinterPortW( pIniPort->pName, phPort, pDefaults );
  570. EnterSplSem();
  571. DECPRINTERREF(pIniPrinter);
  572. if( !bOpenPrinterPort ){
  573. *phPort = INVALID_PORT_HANDLE;
  574. *pOpenPortError = GetLastError();
  575. //
  576. // Must be non-zero otherwise it looks like success.
  577. //
  578. SPLASSERT( *pOpenPortError );
  579. if( *pOpenPortError == ERROR_INVALID_PASSWORD ) {
  580. //
  581. // This call should fail if it's because the password
  582. // is invalid, then winspool or printman can prompt
  583. // for the password.
  584. //
  585. DBGMSG(DBG_WARNING, ("OpenPrinterPort1( %ws ) failed with ERROR_INVALID_PASSWORD . OpenPrinter returning FALSE\n", pIniPort->pName ));
  586. return ROUTER_STOP_ROUTING;
  587. }
  588. DBGMSG(DBG_WARNING, ("OpenPrinterPort1( %ws ) failed: Error %d. OpenPrinter returning TRUE\n", pIniPort->pName, *pOpenPortError));
  589. } else {
  590. //
  591. // Clear the placeholder bit from the pIniPort status. This
  592. // belongs to a partial print provider.
  593. //
  594. pIniPort->Status &= ~PP_PLACEHOLDER;
  595. }
  596. } else {
  597. //
  598. // Not a masq case. If it's direct, it must be raw.
  599. //
  600. // Note: we will use the default if no datatype is specified.
  601. // However, if the default datatype is non-RAW and the
  602. // printer is direct, the open will succeed using a
  603. // non-RAW datatype!
  604. //
  605. if(( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DIRECT ) &&
  606. pDatatype &&
  607. !ValidRawDatatype( pDatatype )) {
  608. goto BadDatatype;
  609. }
  610. }
  611. //
  612. // If this is a placeholder port, assume that it is a monitor port for now.
  613. //
  614. if (pIniPort && pIniPort->Status & PP_PLACEHOLDER) {
  615. pIniPort = NULL;
  616. pIniNetPort = NULL;
  617. }
  618. *pTypeofHandle |= ( pIniPort ?
  619. PRINTER_HANDLE_PORT :
  620. PRINTER_HANDLE_PRINTER );
  621. *ppIniPort = pIniPort;
  622. *ppIniNetPort = pIniNetPort;
  623. *ppIniPrinter = pIniPrinter;
  624. return ROUTER_SUCCESS;
  625. }
  626. SetLastError( ERROR_INVALID_NAME );
  627. return ROUTER_UNKNOWN;
  628. BadDatatype:
  629. SetLastError( ERROR_INVALID_DATATYPE );
  630. return ROUTER_STOP_ROUTING;
  631. }
  632. DWORD
  633. CheckPrinterTokens(
  634. LPCWSTR string,
  635. LPCWSTR pSecondPart,
  636. PDWORD pTypeofHandle,
  637. PINISPOOLER pIniSpooler,
  638. PINIPRINTER *ppIniPrinter,
  639. PINIPORT *ppIniPort,
  640. PINIPORT *ppIniNetPort,
  641. PHANDLE phPort,
  642. PDWORD pOpenPortError,
  643. PPRINTER_DEFAULTS pDefaults
  644. )
  645. {
  646. typedef enum {
  647. kNone = 0,
  648. kLocalOnly = 1,
  649. kLocalsplOnly = 2
  650. } ETOKEN_TYPE;
  651. ETOKEN_TYPE eTokenType = kNone;
  652. DWORD RouterReturnValue = ROUTER_UNKNOWN;
  653. //
  654. // LocalOnly
  655. //
  656. // Do not call OpenPrinterPort--use local settings only.
  657. // If not recognized by localspl, stop routing.
  658. //
  659. // This is used during upgrade of a downlevel printer connection.
  660. // The remote server may not be up, but we can return a print
  661. // handle to the local printer. Get/SetPrinterData calls will
  662. // succeed (for upgrade purposes), but printing will fail.
  663. //
  664. // LocalsplOnly
  665. //
  666. // Call OpenPrinterPort if necessary.
  667. // Stop routing after localspl even if not found.
  668. //
  669. // This is used when the system knows that the printer must exist
  670. // on the local machine, and does not want to route further.
  671. // This fixes the clustering problem when the server has a stale
  672. // print share and successfully validates it against win32spl since
  673. // it is cached.
  674. //
  675. if( wcsncmp( pSecondPart, pszLocalOnlyToken, wcslen(pszLocalOnlyToken) ) == STRINGS_ARE_EQUAL ){
  676. eTokenType = kLocalOnly;
  677. } else if( wcsncmp( pSecondPart, pszLocalsplOnlyToken, wcslen(pszLocalsplOnlyToken) ) == STRINGS_ARE_EQUAL ){
  678. eTokenType = kLocalsplOnly;
  679. }
  680. //
  681. // If we have a valid token, process it.
  682. //
  683. if( eTokenType != kNone ){
  684. switch( eTokenType ){
  685. case kLocalOnly:
  686. //
  687. // Find the printer associate with it.
  688. //
  689. *ppIniPrinter = FindPrinter( string, pIniSpooler );
  690. if( *ppIniPrinter ){
  691. *pTypeofHandle |= PRINTER_HANDLE_PRINTER;
  692. RouterReturnValue = ROUTER_SUCCESS;
  693. } else {
  694. RouterReturnValue = ROUTER_STOP_ROUTING;
  695. }
  696. break;
  697. case kLocalsplOnly:
  698. RouterReturnValue = OpenLocalPrinterName( string,
  699. pIniSpooler,
  700. pTypeofHandle,
  701. ppIniPrinter,
  702. ppIniPort,
  703. ppIniNetPort,
  704. phPort,
  705. pOpenPortError,
  706. pDefaults );
  707. *pTypeofHandle = *pTypeofHandle & (~PRINTER_HANDLE_REMOTE_CALL);
  708. if( RouterReturnValue == ROUTER_UNKNOWN ){
  709. RouterReturnValue = ROUTER_STOP_ROUTING;
  710. }
  711. }
  712. }
  713. DBGMSG( DBG_TRACE,
  714. ( "CheckPrinterTokens: %ws %d Requested %d %x\n",
  715. string, RouterReturnValue, *ppIniPrinter ));
  716. return RouterReturnValue;
  717. }
  718. DWORD
  719. CheckPrinterPortToken(
  720. LPCWSTR string,
  721. LPCWSTR pSecondPart,
  722. PDWORD pTypeofHandle,
  723. PINIPRINTER* ppIniPrinter,
  724. PINIPORT* ppIniPort,
  725. PINIJOB* ppIniJob,
  726. const LPPRINTER_DEFAULTS pDefaults,
  727. const PINISPOOLER pIniSpooler
  728. )
  729. {
  730. if( wcsncmp( pSecondPart, L"Port", 4 ) != STRINGS_ARE_EQUAL ||
  731. !( *ppIniPort = FindPort( string, pIniSpooler ))){
  732. return ROUTER_UNKNOWN;
  733. }
  734. //
  735. // The name is the name of a port:
  736. //
  737. if( pDefaults &&
  738. pDefaults->pDatatype &&
  739. !ValidRawDatatype( pDefaults->pDatatype )) {
  740. SetLastError( ERROR_INVALID_DATATYPE );
  741. return ROUTER_STOP_ROUTING;
  742. }
  743. if ( *ppIniJob = (*ppIniPort)->pIniJob ) {
  744. *ppIniPrinter = (*ppIniJob)->pIniPrinter;
  745. *pTypeofHandle |= PRINTER_HANDLE_PORT;
  746. } else if( (*ppIniPort)->cPrinters ){
  747. //
  748. // There is no current job assigned to the port
  749. // So Open the First Printer Associated with
  750. // this port.
  751. //
  752. *ppIniPrinter = (*ppIniPort)->ppIniPrinter[0];
  753. *pTypeofHandle |= PRINTER_HANDLE_PRINTER;
  754. }
  755. return ROUTER_SUCCESS;
  756. }
  757. DWORD
  758. CheckPrinterJobToken(
  759. IN PWSTR string,
  760. IN size_t cchString,
  761. IN LPCWSTR pSecondPart,
  762. OUT PDWORD pTypeofHandle,
  763. OUT PINIPRINTER *ppIniPrinter,
  764. OUT PINIJOB *ppIniJob,
  765. OUT PHANDLE phReadFile,
  766. IN const PINISPOOLER pIniSpooler
  767. )
  768. {
  769. HANDLE hImpersonationToken;
  770. DWORD Position, dwShareMode, dwDesiredAccess;
  771. DWORD JobId;
  772. PINIPRINTER pIniPrinter;
  773. PINIJOB pIniJob, pCurrentIniJob;
  774. PWSTR pszStr = NULL;
  775. if( wcsncmp( pSecondPart, L"Job ", 4 ) != STRINGS_ARE_EQUAL ||
  776. !( pIniPrinter = FindPrinter( string, pIniSpooler ))){
  777. return ROUTER_UNKNOWN;
  778. }
  779. //
  780. // Get the Job ID ",Job xxxx"
  781. //
  782. pSecondPart += 4;
  783. JobId = Myatol( (LPWSTR)pSecondPart );
  784. pIniJob = FindJob( pIniPrinter, JobId, &Position );
  785. if( pIniJob == NULL ) {
  786. DBGMSG( DBG_WARN, ("OpenPrinter failed to find Job %d\n", JobId ));
  787. return ROUTER_UNKNOWN;
  788. }
  789. DBGMSG( DBG_TRACE, ("OpenPrinter: pIniJob->cRef = %d\n", pIniJob->cRef));
  790. if( pIniJob->Status & JOB_DIRECT ) {
  791. SplInSem();
  792. *pTypeofHandle |= PRINTER_HANDLE_JOB | PRINTER_HANDLE_DIRECT;
  793. goto Success;
  794. }
  795. //
  796. // If this job is assigned to a port
  797. // Then pick up the correct chained jobid file instead of the master
  798. // JobId.
  799. //
  800. if ( pIniJob->pCurrentIniJob != NULL ) {
  801. SPLASSERT( pIniJob->pCurrentIniJob->signature == IJ_SIGNATURE );
  802. DBGMSG( DBG_TRACE,("CheckPrinterJobToken pIniJob %x JobId %d using chain JobId %d\n",
  803. pIniJob, pIniJob->JobId, pIniJob->pCurrentIniJob->JobId ));
  804. pCurrentIniJob = pIniJob->pCurrentIniJob;
  805. SPLASSERT( pCurrentIniJob->signature == IJ_SIGNATURE );
  806. } else {
  807. pCurrentIniJob = pIniJob;
  808. }
  809. if ( pCurrentIniJob->hFileItem != INVALID_HANDLE_VALUE )
  810. {
  811. LeaveSplSem();
  812. hImpersonationToken = RevertToPrinterSelf();
  813. GetReaderFromHandle(pCurrentIniJob->hFileItem, phReadFile);
  814. if (hImpersonationToken && !ImpersonatePrinterClient(hImpersonationToken))
  815. {
  816. DBGMSG( DBG_WARNING,("Client impersonation failed.\n"));
  817. }
  818. else
  819. {
  820. if ( *phReadFile && (*phReadFile != INVALID_HANDLE_VALUE))
  821. {
  822. GetNameFromHandle(pCurrentIniJob->hFileItem, &pszStr, TRUE);
  823. if (BoolFromHResult(StringCchCopy(string, cchString, pszStr)))
  824. {
  825. EnterSplSem();
  826. *pTypeofHandle |= PRINTER_HANDLE_JOB;
  827. goto Success;
  828. }
  829. }
  830. }
  831. DBGMSG( DBG_WARN,("Filepools: Failed to get valid reader handle\n"));
  832. EnterSplSem();
  833. }
  834. else
  835. {
  836. GetFullNameFromId(pCurrentIniJob->pIniPrinter,
  837. pCurrentIniJob->JobId,
  838. TRUE,
  839. string,
  840. cchString,
  841. FALSE);
  842. // Bug 54845
  843. // Even a user without previledge can open a ", JOB #"
  844. // if he is physically running on the machine.
  845. LeaveSplSem();
  846. hImpersonationToken = RevertToPrinterSelf();
  847. dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
  848. if (pCurrentIniJob->Status & JOB_TYPE_OPTIMIZE) {
  849. dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
  850. } else {
  851. dwDesiredAccess = GENERIC_READ;
  852. }
  853. //
  854. // This is OK, it can only open a job file since we generate the name from
  855. // the id.
  856. //
  857. *phReadFile = CreateFile(string,
  858. dwDesiredAccess,
  859. dwShareMode,
  860. NULL,
  861. OPEN_EXISTING,
  862. FILE_ATTRIBUTE_NORMAL,
  863. NULL);
  864. EnterSplSem();
  865. if (hImpersonationToken && !ImpersonatePrinterClient(hImpersonationToken))
  866. {
  867. DBGMSG( DBG_WARNING,("Client impersonation failed.\n"));
  868. }
  869. else
  870. {
  871. if( *phReadFile != INVALID_HANDLE_VALUE ) {
  872. DBGMSG( DBG_TRACE,
  873. ( "OpenPrinter JobID %d pIniJob %x CreateFile( %ws ), hReadFile %x success",
  874. JobId, pIniJob, string, *phReadFile ));
  875. SplInSem();
  876. *pTypeofHandle |= PRINTER_HANDLE_JOB;
  877. goto Success;
  878. }
  879. }
  880. }
  881. DBGMSG( DBG_WARNING,
  882. ( "LocalOpenPrinter CreateFile(%ws) GENERIC_READ failed : %d\n",
  883. string, GetLastError()));
  884. SPLASSERT( GetLastError( ));
  885. //
  886. // Cleanup for the function.
  887. // This function does not have a common cleanup area, this should be fixed,
  888. // but it requires a overhaul of this function.
  889. //
  890. FreeSplStr(pszStr);
  891. return ROUTER_STOP_ROUTING;
  892. Success:
  893. FreeSplStr(pszStr);
  894. *ppIniJob = pIniJob;
  895. *ppIniPrinter = pIniPrinter;
  896. return ROUTER_SUCCESS;
  897. }
  898. DWORD
  899. CheckXcvPortToken(
  900. LPCWSTR pszSecondPart,
  901. PDWORD pTypeofHandle,
  902. const LPPRINTER_DEFAULTS pDefaults,
  903. const PINISPOOLER pIniSpooler,
  904. PHANDLE phXcv
  905. )
  906. {
  907. DWORD dwRet = ROUTER_SUCCESS;
  908. DWORD dwType;
  909. PCWSTR pszPort;
  910. DWORD dwTypeofHandle = *pTypeofHandle;
  911. if (!wcsncmp(pszSecondPart, SZXCVPORT, COUNTOF(SZXCVPORT) - 1)) {
  912. dwType = XCVPORT;
  913. dwTypeofHandle |= PRINTER_HANDLE_XCV_PORT;
  914. pszPort = (PCWSTR) pszSecondPart + COUNTOF(SZXCVPORT) - 1;
  915. }
  916. else if (!wcsncmp(pszSecondPart, SZXCVMONITOR, COUNTOF(SZXCVMONITOR) - 1)) {
  917. dwType = XCVMONITOR;
  918. dwTypeofHandle |= PRINTER_HANDLE_XCV_PORT;
  919. pszPort = (PCWSTR) pszSecondPart + COUNTOF(SZXCVMONITOR) - 1;
  920. }
  921. else
  922. dwRet = ROUTER_UNKNOWN;
  923. if (dwRet == ROUTER_SUCCESS) {
  924. dwRet = XcvOpen(NULL,
  925. pszPort,
  926. dwType,
  927. pDefaults,
  928. phXcv,
  929. pIniSpooler);
  930. if (dwRet == ROUTER_SUCCESS)
  931. *pTypeofHandle = dwTypeofHandle;
  932. }
  933. return dwRet;
  934. }
  935. DWORD
  936. SplOpenPrinter(
  937. LPWSTR pFullPrinterName,
  938. LPHANDLE pPrinterHandle,
  939. LPPRINTER_DEFAULTS pDefaults,
  940. PINISPOOLER pIniSpooler,
  941. LPBYTE pSplClientInfo,
  942. DWORD dwLevel
  943. )
  944. /*++
  945. Routine Description:
  946. OpenPrinter can open any of the following by specifying a string
  947. in pPrinterName:-
  948. Server
  949. \\MachineName
  950. NULL
  951. Job
  952. PrinterName, Job xxxx
  953. Port
  954. PortName, Port
  955. XcvPort
  956. \\MachineName\,XcvPort Port
  957. ,XcvPort Port
  958. XcvMonitor
  959. \\MachineName\,XcvMonitor Monitor
  960. ,XcvMonitor Monitor
  961. Printer
  962. PrinterName
  963. ShareName
  964. \\MachineName\PrinterName
  965. \\MachineName\ShareName
  966. PrinterName, LocalOnly
  967. ShareName, LocalOnly
  968. PrinterName, LocalsplOnly
  969. ShareName, LocalsplOnly
  970. Note for Printer there are two Types
  971. 1 - Regular LocalPrinter
  972. 2 - DownLevel Connection Printer
  973. For type 2 a LocalPrinter exists ( pIniPrinter ) but its port
  974. does not have a monitor associated with it. In this case
  975. we also open the port ( typically \\share\printer of a remote
  976. machine ) before we return success.
  977. GUI Applications usually use Server and Printer
  978. Type Job and Port are used by Print Processors:-
  979. A print processor will Open a Job then read the job using
  980. ReadPrinter. A print processor will output to a Port by opening
  981. the PortName, Port and using WritePrinter. Usually these strings
  982. "PrinterName, Job xxx" "PortName, Port" are passed to the print
  983. processor by the spooler and are currently not documented. We
  984. do know that some OEMs have figured out the extentions and we
  985. might break someone if we change them.
  986. Type LocalOnlyToken is used by a Printer Driver:-
  987. Used when we need to upgrade a printer's settings from an older
  988. version of the driver to a newer one (see drvupgrd.c for details).
  989. This was added in NT 3.51.
  990. Type LocasplOnlyToken is used by server:-
  991. Indicates that we should check localspl only (local or masq).
  992. Other providers will not be called.
  993. Arguments:
  994. pPrinterName - PrinterName ( see above for different types of
  995. PrinterName )
  996. pPrinterHandle - Address to put hPrinter on Success
  997. pDefaults - Optional, allows user to specify Datatype,
  998. DevMode, DesiredAccess.
  999. pIniSpooler - This spooler "owns" the printer. We will only check
  1000. against this spooler, and we assume that the callee
  1001. has already checked that "\\server\printer" lives
  1002. on this pIniSpooler (i.e., we are \\server).
  1003. ( see SDK Online Help for full explanation )
  1004. Return Value:
  1005. TRUE - *pPrinterHandle will have a PrinterHandle
  1006. FALSE - use GetLastError
  1007. --*/
  1008. {
  1009. PINIPRINTER pIniPrinter = NULL;
  1010. PINIPORT pIniPort = NULL;
  1011. PINIPORT pIniNetPort = NULL;
  1012. DWORD LastError = 0;
  1013. LPWSTR pPrinterName = pFullPrinterName;
  1014. WCHAR string[MAX_UNC_PRINTER_NAME + PRINTER_NAME_SUFFIX_MAX];
  1015. PINIJOB pIniJob = NULL;
  1016. HANDLE hReadFile = INVALID_HANDLE_VALUE;
  1017. DWORD TypeofHandle = 0;
  1018. LPWSTR pSecondPart = NULL;
  1019. HANDLE hPort = INVALID_PORT_HANDLE;
  1020. DWORD OpenPortError = NO_ERROR;
  1021. BOOL bRemoteUserPrinterNotShared = FALSE;
  1022. DWORD MachineNameLength;
  1023. DWORD RouterReturnValue = ROUTER_UNKNOWN;
  1024. DWORD DesiredAccess;
  1025. LPTSTR pcMark;
  1026. BOOL bRemoteNameRequest = FALSE;
  1027. BOOL bLocalCall = FALSE;
  1028. #if DBG
  1029. //
  1030. // On DBG builds, force last error to zero so we can catch people
  1031. // that don't set it when they should.
  1032. //
  1033. SetLastError( ERROR_SUCCESS );
  1034. #endif
  1035. //
  1036. // Reject "" - pointer to a NULL string.
  1037. //
  1038. if (pFullPrinterName && !pFullPrinterName[0]) {
  1039. SetLastError(ERROR_INVALID_NAME);
  1040. return ROUTER_UNKNOWN;
  1041. }
  1042. if (!pFullPrinterName) {
  1043. return CreateServerHandle( pFullPrinterName,
  1044. pPrinterHandle,
  1045. pDefaults,
  1046. pIniSpooler,
  1047. PRINTER_HANDLE_SERVER );
  1048. }
  1049. if( pFullPrinterName[0] == TEXT( '\\' ) && pFullPrinterName[1] == TEXT( '\\' )) {
  1050. //
  1051. // If this is truncated, MyName will just fail a little later.
  1052. //
  1053. StringCchCopy(string, COUNTOF(string), pFullPrinterName);
  1054. if(pcMark = wcschr(string + 2, TEXT( '\\' ))) {
  1055. *pcMark = TEXT('\0');
  1056. }
  1057. if (MyName(string, pIniSpooler)) { // \\Server\Printer or \\Server
  1058. if (!pcMark) { // \\Server
  1059. return CreateServerHandle( pFullPrinterName,
  1060. pPrinterHandle,
  1061. pDefaults,
  1062. pIniSpooler,
  1063. PRINTER_HANDLE_SERVER );
  1064. }
  1065. // Have \\Server\Printer, Set pPrinterName = Printer
  1066. pPrinterName = pFullPrinterName + (pcMark - string) + 1;
  1067. bRemoteNameRequest = TRUE;
  1068. }
  1069. }
  1070. DBGMSG( DBG_TRACE, ( "OpenPrinter(%ws, %ws)\n", pFullPrinterName, pPrinterName ));
  1071. {
  1072. HRESULT hRes = CheckLocalCall();
  1073. if (hRes == S_OK)
  1074. {
  1075. bLocalCall = TRUE;
  1076. }
  1077. else if (hRes == S_FALSE)
  1078. {
  1079. bLocalCall = FALSE;
  1080. }
  1081. else
  1082. {
  1083. SetLastError(SCODE_CODE(hRes));
  1084. return FALSE;
  1085. }
  1086. }
  1087. EnterSplSem();
  1088. //
  1089. // For the Mars folks who will come in with the same printer
  1090. // connection, do a DeletePrinterCheck; this will allow
  1091. // Mars connections that have been deleted to be proceed
  1092. // to the Mars print providor
  1093. //
  1094. if (( pIniPrinter = FindPrinter( pPrinterName, pIniSpooler )) ||
  1095. ( pIniPrinter = FindPrinterShare( pPrinterName, pIniSpooler ))) {
  1096. DeletePrinterCheck( pIniPrinter );
  1097. pIniPrinter = NULL;
  1098. }
  1099. //
  1100. // The strategy for the rest of this code is to walk through each
  1101. // different printer handle type, searching for a match.
  1102. //
  1103. // RouterReturnValue will be set to the current state of routing.
  1104. // If a section recognizes and "owns" a printer and successfully
  1105. // opens it, it sets RouterReturnValue to ROUTER_SUCCESS and
  1106. // jumps to DoneRouting which allocs the handle.
  1107. //
  1108. // If it recoginzes the printer but fails to open it, and
  1109. // guarentees that no one else (localspl code or other providers)
  1110. // will recognize it, it should set RouterReturnValue to
  1111. // ROUTER_STOP_ROUTING. We will quit at this point.
  1112. //
  1113. // If it doesn't recognize the printer, set RouterReturnValue
  1114. // to ROUTER_UNKNOWN and we will keep looking.
  1115. //
  1116. //
  1117. // Try regular printer name: "My Printer" "TestPrinter."
  1118. //
  1119. RouterReturnValue = OpenLocalPrinterName( pPrinterName,
  1120. pIniSpooler,
  1121. &TypeofHandle,
  1122. &pIniPrinter,
  1123. &pIniPort,
  1124. &pIniNetPort,
  1125. &hPort,
  1126. &OpenPortError,
  1127. pDefaults );
  1128. if( RouterReturnValue != ROUTER_UNKNOWN ){
  1129. if( bRemoteNameRequest ){
  1130. //
  1131. // On success, determine whether the user is remote or local.
  1132. // Note: we only do this for fully qualified names
  1133. // (\\server\share), since using just the share or printer
  1134. // name can only succeed locally.
  1135. //
  1136. if (bLocalCall) {
  1137. if( (pIniSpooler->SpoolerFlags & SPL_REMOTE_HANDLE_CHECK) &&
  1138. (pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) )
  1139. TypeofHandle |= PRINTER_HANDLE_REMOTE_DATA;
  1140. } else {
  1141. if( pIniSpooler->SpoolerFlags & SPL_REMOTE_HANDLE_CHECK )
  1142. TypeofHandle |= PRINTER_HANDLE_REMOTE_DATA;
  1143. TypeofHandle |= PRINTER_HANDLE_REMOTE_CALL;
  1144. }
  1145. //
  1146. // This is a remote open.
  1147. //
  1148. // If the printer is not shared, ensure the caller
  1149. // has Administer access to the printer.
  1150. //
  1151. // The following seems to belong to the inside of the above "if"
  1152. // clause. As it is, if an interactive user calls in with UNC name,
  1153. // we require him to have ADMIN access if the printer is not shared;
  1154. // but if he uses the printer friendly name, we let him go.
  1155. //
  1156. if( pIniPrinter &&
  1157. !( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED )){
  1158. bRemoteUserPrinterNotShared = TRUE;
  1159. }
  1160. }
  1161. goto DoneRouting;
  1162. }
  1163. SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort &&
  1164. !pIniNetPort && !pIniJob && !hPort );
  1165. //
  1166. // Try LocalPrinter with an extention e.g.
  1167. //
  1168. // PortName, Port
  1169. // PrinterName, Job xxxx
  1170. // PrinterName, LocalOnlyToken
  1171. // PrinterName, LocalsplOnlyToken
  1172. //
  1173. // See if the name includes a comma. Look for qualifiers:
  1174. // Port Job LocalOnly LocalsplOnly
  1175. //
  1176. StringCchCopy(string, COUNTOF(string), pPrinterName);
  1177. if( pSecondPart = wcschr( string, L',' )){
  1178. DWORD dwError;
  1179. UINT uType;
  1180. //
  1181. // Turn into 2 strings
  1182. // First PrintName
  1183. // pSecondPart points to the rest.
  1184. //
  1185. *pSecondPart++ = 0;
  1186. //
  1187. // Get rid of Leading Spaces
  1188. //
  1189. while ( *pSecondPart == L' ' && *pSecondPart != 0 ) {
  1190. pSecondPart++;
  1191. }
  1192. SPLASSERT( *pSecondPart );
  1193. //
  1194. // PrintName, {LocalOnly|LocalsplOnly}
  1195. //
  1196. RouterReturnValue = CheckPrinterTokens( string,
  1197. pSecondPart,
  1198. &TypeofHandle,
  1199. pIniSpooler,
  1200. &pIniPrinter,
  1201. &pIniPort,
  1202. &pIniNetPort,
  1203. &hPort,
  1204. &OpenPortError,
  1205. pDefaults );
  1206. if( RouterReturnValue != ROUTER_UNKNOWN ){
  1207. goto DoneRouting;
  1208. }
  1209. SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort &&
  1210. !pIniNetPort && !pIniJob && !hPort );
  1211. //
  1212. // PortName, Port
  1213. //
  1214. RouterReturnValue = CheckPrinterPortToken( string,
  1215. pSecondPart,
  1216. &TypeofHandle,
  1217. &pIniPrinter,
  1218. &pIniPort,
  1219. &pIniJob,
  1220. pDefaults,
  1221. pIniSpooler );
  1222. if( RouterReturnValue != ROUTER_UNKNOWN ){
  1223. goto DoneRouting;
  1224. }
  1225. SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort &&
  1226. !pIniNetPort && !pIniJob && !hPort );
  1227. //
  1228. // PrinterName, Job ###
  1229. //
  1230. RouterReturnValue = CheckPrinterJobToken(string,
  1231. COUNTOF(string),
  1232. pSecondPart,
  1233. &TypeofHandle,
  1234. &pIniPrinter,
  1235. &pIniJob,
  1236. &hReadFile,
  1237. pIniSpooler);
  1238. if( RouterReturnValue != ROUTER_UNKNOWN ){
  1239. goto DoneRouting;
  1240. }
  1241. SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort &&
  1242. !pIniNetPort && !pIniJob && !hPort );
  1243. //
  1244. // "\\Server\,XcvPort Object" or ",XcvPort Object"
  1245. // "\\Server\,XcvMonitor Object" or ",XcvMonitor Object"
  1246. //
  1247. // Verify that we're looking at the right server
  1248. if (bRemoteNameRequest || *pPrinterName == L',') {
  1249. RouterReturnValue = CheckXcvPortToken( pSecondPart,
  1250. &TypeofHandle,
  1251. pDefaults,
  1252. pIniSpooler,
  1253. pPrinterHandle );
  1254. } else {
  1255. RouterReturnValue = ROUTER_UNKNOWN;
  1256. }
  1257. goto WrapUp;
  1258. }
  1259. //
  1260. // We have completed all routing. Anything other than success
  1261. // should exit now.
  1262. //
  1263. DoneRouting:
  1264. if( RouterReturnValue == ROUTER_SUCCESS) {
  1265. //
  1266. // It's an error if the printer is pending deletion or pending creation.
  1267. //
  1268. SPLASSERT( pIniPrinter );
  1269. if (!pIniPrinter ||
  1270. (pIniPrinter->Status & PRINTER_PENDING_DELETION) &&
  1271. (pIniSpooler->SpoolerFlags & SPL_FAIL_OPEN_PRINTERS_PENDING_DELETION) &&
  1272. (pIniPrinter->cJobs == 0) ||
  1273. (pIniPrinter->Status & PRINTER_PENDING_CREATION)) {
  1274. RouterReturnValue = ROUTER_STOP_ROUTING;
  1275. SetLastError( ERROR_INVALID_PRINTER_NAME );
  1276. goto DoneRouting;
  1277. }
  1278. //
  1279. // When the printer is opened, access type may be specified in
  1280. // pDefaults. If no defaults are supplied (or request access
  1281. // is unspecified), we use PRINTER_ACCESS_USE.
  1282. //
  1283. // Future calls with the handle will check against both the
  1284. // current user privileges on this printer but also this initial
  1285. // access. (Even if the user is an admin of the printer, unless
  1286. // they open the printer with PRINTER_ALL_ACCESS, they can't
  1287. // administer it.)
  1288. //
  1289. // If the user requires more access, the printer must be reopened.
  1290. //
  1291. if( !pDefaults || !pDefaults->DesiredAccess ){
  1292. if( TypeofHandle & PRINTER_HANDLE_JOB ){
  1293. DesiredAccess = JOB_READ;
  1294. } else {
  1295. DesiredAccess = PRINTER_READ;
  1296. }
  1297. } else {
  1298. DesiredAccess = pDefaults->DesiredAccess;
  1299. }
  1300. //
  1301. // If the user is remote and the printer is not shared, only allow
  1302. // administrators succeed.
  1303. //
  1304. // This allows administrators to admin printers even if they
  1305. // are not shared, and prevents non-admins from opening non-shared
  1306. // printers.
  1307. //
  1308. if( bRemoteUserPrinterNotShared &&
  1309. !(DesiredAccess & PRINTER_ACCESS_ADMINISTER )) {
  1310. PSPOOL pSpool;
  1311. // Get a quick and dirty pSpool to pass in
  1312. pSpool = (PSPOOL)AllocSplMem( SPOOL_SIZE );
  1313. if( pSpool == NULL ) {
  1314. DBGMSG( DBG_WARNING, ("SplOpenPrinter failed to allocate memory %d\n", GetLastError() ));
  1315. RouterReturnValue = ROUTER_STOP_ROUTING;
  1316. goto WrapUp;
  1317. }
  1318. pSpool->signature = SJ_SIGNATURE;
  1319. pSpool->pIniPrinter = pIniPrinter;
  1320. // Add admin request, and see if user has the right.
  1321. DesiredAccess |= PRINTER_ACCESS_ADMINISTER;
  1322. if( !ValidateObjectAccess( SPOOLER_OBJECT_PRINTER,
  1323. DesiredAccess,
  1324. pSpool,
  1325. &pSpool->GrantedAccess,
  1326. pIniSpooler )) {
  1327. SetLastError(ERROR_ACCESS_DENIED);
  1328. RouterReturnValue = ROUTER_STOP_ROUTING;
  1329. }
  1330. DesiredAccess &= ~PRINTER_ACCESS_ADMINISTER;
  1331. // clean up
  1332. FreeSplMem( pSpool );
  1333. // If the user had no ADMIN privilege, fail the open call.
  1334. if( RouterReturnValue == ROUTER_STOP_ROUTING )
  1335. goto WrapUp;
  1336. }
  1337. //
  1338. // Create the printer handle that we will return to the user.
  1339. //
  1340. if( pFullPrinterName != pPrinterName) {
  1341. SIZE_T cchMaxString = 0;
  1342. cchMaxString = min(COUNTOF(string), (size_t) (pPrinterName - pFullPrinterName));
  1343. StringCchCopy(string, cchMaxString, pFullPrinterName);
  1344. } else {
  1345. StringCchCopy(string, COUNTOF(string), pIniSpooler->pMachineName);
  1346. }
  1347. *pPrinterHandle = CreatePrinterHandle( pFullPrinterName,
  1348. string,
  1349. pIniPrinter,
  1350. pIniPort,
  1351. pIniNetPort,
  1352. pIniJob,
  1353. TypeofHandle,
  1354. hPort,
  1355. pDefaults,
  1356. pIniSpooler,
  1357. DesiredAccess,
  1358. pSplClientInfo,
  1359. dwLevel,
  1360. hReadFile );
  1361. if( *pPrinterHandle ){
  1362. //
  1363. // Update the OpenPortError.
  1364. //
  1365. ((PSPOOL)*pPrinterHandle)->OpenPortError = OpenPortError;
  1366. } else {
  1367. SPLASSERT( GetLastError( ));
  1368. RouterReturnValue = ROUTER_STOP_ROUTING;
  1369. }
  1370. }
  1371. WrapUp:
  1372. LeaveSplSem();
  1373. //
  1374. // Don't have an SplOutSem as we could be called recursively.
  1375. //
  1376. switch( RouterReturnValue ){
  1377. case ROUTER_SUCCESS:
  1378. DBGMSG( DBG_TRACE, ("OpenPrinter returned handle %x\n", *pPrinterHandle));
  1379. SPLASSERT( *pPrinterHandle );
  1380. break;
  1381. case ROUTER_UNKNOWN:
  1382. SPLASSERT( !TypeofHandle && !pIniPrinter && !pIniPort &&
  1383. !pIniNetPort && !pIniJob && !hPort );
  1384. //
  1385. // hPort should not be valid. If it is, we have leaked a handle.
  1386. //
  1387. SPLASSERT( !hPort );
  1388. SPLASSERT( hReadFile == INVALID_HANDLE_VALUE );
  1389. DBGMSG( DBG_TRACE, ( "OpenPrinter failed, invalid name "TSTR"\n",
  1390. pFullPrinterName ));
  1391. SetLastError( ERROR_INVALID_NAME );
  1392. break;
  1393. case ROUTER_STOP_ROUTING:
  1394. LastError = GetLastError();
  1395. SPLASSERT( LastError );
  1396. //
  1397. // On failure, we may have opened a port or file handle. We need
  1398. // to close it since we won't return a valid handle, and
  1399. // so ClosePrinter will never get called.
  1400. //
  1401. if( hPort != INVALID_PORT_HANDLE ) {
  1402. ClosePrinter( hPort );
  1403. }
  1404. if ( pIniJob && (pIniJob->hFileItem == INVALID_HANDLE_VALUE) )
  1405. {
  1406. if ( hReadFile != INVALID_HANDLE_VALUE ) {
  1407. CloseHandle( hReadFile );
  1408. hReadFile = INVALID_HANDLE_VALUE;
  1409. }
  1410. }
  1411. DBGMSG( DBG_TRACE, ("OpenPrinter "TSTR" failed: Error %d\n",
  1412. pFullPrinterName, GetLastError()));
  1413. SetLastError( LastError );
  1414. break;
  1415. }
  1416. return RouterReturnValue;
  1417. }
  1418. BOOL
  1419. SplClosePrinter(
  1420. HANDLE hPrinter
  1421. )
  1422. {
  1423. PSPOOL pSpool=(PSPOOL)hPrinter;
  1424. PSPOOL *ppIniSpool = NULL;
  1425. PINISPOOLER pIniSpoolerDecRef = NULL;
  1426. PSPLMAPVIEW pSplMapView;
  1427. PMAPPED_JOB pMappedJob;
  1428. BOOL bValid;
  1429. DWORD Position;
  1430. //
  1431. // Allow us to close zombied handles.
  1432. //
  1433. EnterSplSem();
  1434. pSpool->Status &= ~SPOOL_STATUS_ZOMBIE;
  1435. if (pSpool->TypeofHandle & PRINTER_HANDLE_XCV_PORT) {
  1436. bValid = ValidateXcvHandle(pSpool->pIniXcv);
  1437. } else {
  1438. bValid = ValidateSpoolHandle(pSpool, 0);
  1439. }
  1440. LeaveSplSem();
  1441. if( !bValid ){
  1442. return FALSE;
  1443. }
  1444. if (pSpool->Status & SPOOL_STATUS_STARTDOC) {
  1445. // it looks as though this might cause a double
  1446. // decrement of pIniJob->cRef once inside LocalEndDocPrinter
  1447. // and the other later in this routine.
  1448. LocalEndDocPrinter(hPrinter);
  1449. }
  1450. if ((pSpool->TypeofHandle & PRINTER_HANDLE_JOB) &&
  1451. (pSpool->TypeofHandle & PRINTER_HANDLE_DIRECT)) {
  1452. //
  1453. // If EndDoc is still waiting for a final ReadPrinter
  1454. //
  1455. if (pSpool->pIniJob->cbBuffer) { // Amount last transmitted
  1456. //
  1457. // Wake up the EndDoc Thread
  1458. //
  1459. SetEvent(pSpool->pIniJob->WaitForRead);
  1460. SplOutSem();
  1461. //
  1462. // Wait until he is finished
  1463. //
  1464. WaitForSingleObject(pSpool->pIniJob->WaitForWrite, INFINITE);
  1465. EnterSplSem();
  1466. //
  1467. // Now it is ok to close the handles
  1468. //
  1469. if (!CloseHandle(pSpool->pIniJob->WaitForWrite)) {
  1470. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n",
  1471. pSpool->pIniJob->WaitForWrite, GetLastError()));
  1472. }
  1473. if (!CloseHandle(pSpool->pIniJob->WaitForRead)) {
  1474. DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n",
  1475. pSpool->pIniJob->WaitForRead, GetLastError()));
  1476. }
  1477. pSpool->pIniJob->WaitForRead = NULL;
  1478. pSpool->pIniJob->WaitForWrite = NULL;
  1479. LeaveSplSem();
  1480. }
  1481. DBGMSG(DBG_TRACE, ("ClosePrinter(DIRECT):cRef = %d\n", pSpool->pIniJob->cRef));
  1482. }
  1483. //
  1484. // Unmap all views of the spool file and close file mapping handles
  1485. //
  1486. while (pSplMapView = pSpool->pSplMapView) {
  1487. pSpool->pSplMapView = pSplMapView->pNext;
  1488. if (pSplMapView->pStartMapView) {
  1489. UnmapViewOfFile( (LPVOID) pSplMapView->pStartMapView);
  1490. }
  1491. //
  1492. // CreateFileMapping returns NULL (not INVALID_HANDLE_VALUE) for failure
  1493. //
  1494. if (pSplMapView->hMapSpoolFile) {
  1495. CloseHandle(pSplMapView->hMapSpoolFile);
  1496. }
  1497. FreeSplMem(pSplMapView);
  1498. }
  1499. //
  1500. // Delete all mapped spool files that are not required
  1501. //
  1502. EnterSplSem();
  1503. //
  1504. // Mark the handle as being in a closing state, this is to prevent the
  1505. // mapped files being deleted in DeleteJob
  1506. //
  1507. pSpool->eStatus |= STATUS_CLOSING;
  1508. while (pMappedJob = pSpool->pMappedJob)
  1509. {
  1510. PMAPPED_JOB pNextMappedJob = NULL;
  1511. pNextMappedJob = pMappedJob->pNext;
  1512. //
  1513. // Since we can have multiple addjobs on any one handle, we run through
  1514. // all of the mapped jobs, check to see if the mapped job is marked
  1515. // as being added through AddJob and then we schedule it. We need to
  1516. // call this before we remove the job from the handle list or
  1517. // LocalScheduleJob will not recognize the job.
  1518. //
  1519. if (!(pSpool->TypeofHandle & PRINTER_HANDLE_JOB) && (pMappedJob->fStatus & kMappedJobAddJob)) {
  1520. LeaveSplSem();
  1521. LocalScheduleJob(hPrinter, pMappedJob->JobId);
  1522. EnterSplSem();
  1523. }
  1524. //
  1525. // We rely on serialization of the pSpool handle here at the RPC level.
  1526. //
  1527. pSpool->pMappedJob = pNextMappedJob;
  1528. if (!pSpool->pIniPrinter ||
  1529. !FindJob(pSpool->pIniPrinter, pMappedJob->JobId, &Position))
  1530. {
  1531. //
  1532. // The job is gone and we have to delete the spool file
  1533. //
  1534. LeaveSplSem();
  1535. //
  1536. // This may need looking at for File Pooling
  1537. //
  1538. DeleteFile(pMappedJob->pszSpoolFile);
  1539. EnterSplSem();
  1540. if (pSpool->pIniPrinter)
  1541. {
  1542. vMarkOff( pSpool->pIniPrinter->pIniSpooler->hJobIdMap,
  1543. pMappedJob->JobId );
  1544. }
  1545. }
  1546. FreeSplMem(pMappedJob->pszSpoolFile);
  1547. FreeSplMem(pMappedJob);
  1548. }
  1549. LeaveSplSem();
  1550. if ( pSpool->hReadFile != INVALID_HANDLE_VALUE ) {
  1551. //
  1552. // Move the file pointer to the number of bytes committed and set the end of
  1553. // file.
  1554. //
  1555. if ((pSpool->pIniJob->Status & JOB_TYPE_OPTIMIZE) &&
  1556. SetFilePointer(pSpool->hReadFile, pSpool->pIniJob->dwValidSize,
  1557. NULL, FILE_BEGIN) != 0xffffffff) {
  1558. SetEndOfFile(pSpool->hReadFile);
  1559. }
  1560. //
  1561. // File pooling Change, we close the file handle if we aren't file
  1562. // pooling and we reset the seek pointer if we are file pooling.
  1563. //
  1564. if (pSpool->pIniJob)
  1565. {
  1566. if (pSpool->pIniJob->hFileItem == INVALID_HANDLE_VALUE)
  1567. {
  1568. if ( !CloseHandle( pSpool->hReadFile ) ) {
  1569. DBGMSG(DBG_WARNING, ("ClosePrinter CloseHandle(%d) failed %d\n", pSpool->hReadFile, GetLastError()));
  1570. }
  1571. }
  1572. else
  1573. {
  1574. //
  1575. // People call ClosePrinter / OpenPrinter in sequence to be able
  1576. // to read from the beginning of the spool file again. To get the
  1577. // same effect, we need to set the seek pointer back to the
  1578. // beginning of the hReadFile.
  1579. //
  1580. DWORD rc = ERROR_SUCCESS;
  1581. rc = SetFilePointer(pSpool->hReadFile, 0, NULL, FILE_BEGIN);
  1582. if (rc != ERROR_SUCCESS)
  1583. {
  1584. DBGMSG(DBG_WARNING, ("ClosePrinter SetFilePointer(%p) failed %d\n", pSpool->hReadFile, rc));
  1585. }
  1586. }
  1587. }
  1588. }
  1589. //
  1590. // Close the handle that was opened via OpenPrinterPort:
  1591. //
  1592. if (pSpool->hPort) {
  1593. if (pSpool->hPort != INVALID_PORT_HANDLE) {
  1594. ClosePrinter(pSpool->hPort);
  1595. } else {
  1596. DBGMSG(DBG_WARNING, ("ClosePrinter ignoring bad port handle.\n"));
  1597. }
  1598. }
  1599. EnterSplSem();
  1600. //
  1601. // Right at the end remove our reference to the job if this is a job handle.
  1602. //
  1603. if (pSpool->TypeofHandle & PRINTER_HANDLE_JOB) {
  1604. DBGMSG(DBG_TRACE, ("ClosePrinter:cRef = %d\n", pSpool->pIniJob->cRef));
  1605. DECJOBREF(pSpool->pIniJob);
  1606. DeleteJobCheck(pSpool->pIniJob);
  1607. }
  1608. //
  1609. // Remove us from the linked list of handles:
  1610. //
  1611. if (pSpool->TypeofHandle & PRINTER_HANDLE_PRINTER) {
  1612. SPLASSERT( pSpool->pIniPrinter->signature == IP_SIGNATURE );
  1613. ppIniSpool = &pSpool->pIniPrinter->pSpool;
  1614. }
  1615. else if ((pSpool->TypeofHandle & PRINTER_HANDLE_SERVER) ||
  1616. (pSpool->TypeofHandle & PRINTER_HANDLE_XCV_PORT)) {
  1617. SPLASSERT( pSpool->pIniSpooler->signature == ISP_SIGNATURE );
  1618. if (pSpool->TypeofHandle & PRINTER_HANDLE_XCV_PORT)
  1619. XcvClose(pSpool->pIniXcv);
  1620. pIniSpoolerDecRef = pSpool->pIniSpooler;
  1621. ppIniSpool = &pSpool->pIniSpooler->pSpool;
  1622. }
  1623. if (ppIniSpool) {
  1624. while (*ppIniSpool && *ppIniSpool != pSpool)
  1625. ppIniSpool = &(*ppIniSpool)->pNext;
  1626. if (*ppIniSpool)
  1627. *ppIniSpool = pSpool->pNext;
  1628. else {
  1629. DBGMSG( DBG_WARNING, ( "Didn't find pSpool %08x in linked list\n", pSpool ) );
  1630. }
  1631. }
  1632. if (pSpool->pIniPrinter) {
  1633. DECPRINTERREF( pSpool->pIniPrinter );
  1634. DeletePrinterCheck(pSpool->pIniPrinter);
  1635. }
  1636. DeletePrinterHandle(pSpool);
  1637. if (pIniSpoolerDecRef) {
  1638. DECSPOOLERREF( pIniSpoolerDecRef );
  1639. }
  1640. LeaveSplSem();
  1641. //
  1642. // Don't call SplOutSem() since SplAddPrinter calls
  1643. // use from inside the critical section.
  1644. //
  1645. return TRUE;
  1646. }
  1647. /*++
  1648. Routine Name:
  1649. GetClientSessionData
  1650. Routine Description:
  1651. This returns the session ID and the token handle for the current user. If the
  1652. token handle is not requested we will only return the session id. As long as
  1653. we can get a token, we will return a session ID of 0.
  1654. Arguments:
  1655. plSessionId - The returned session id.
  1656. Return Value:
  1657. TRUE if the session ID and token could be retrieved.
  1658. --*/
  1659. BOOL
  1660. GetClientSessionData(
  1661. OUT ULONG *plSessionId
  1662. )
  1663. {
  1664. BOOL Result;
  1665. HANDLE TokenHandle = NULL;
  1666. ULONG SessionId = 0;
  1667. ULONG ReturnLength;
  1668. //
  1669. // We should be impersonating the client, so we will get the
  1670. // SessionId from out token.
  1671. //
  1672. // We may not have a valid one if this is a remote network
  1673. // connection.
  1674. Result = plSessionId != NULL;
  1675. if (!Result)
  1676. {
  1677. SetLastError(ERROR_INVALID_PARAMETER);
  1678. }
  1679. //
  1680. // Get the thread token handle, failing that the process handle.
  1681. //
  1682. if (Result)
  1683. {
  1684. Result = GetTokenHandle(&TokenHandle);
  1685. }
  1686. if(Result)
  1687. {
  1688. //
  1689. // Query the SessionID from the token added by HYDRA
  1690. //
  1691. Result = GetTokenInformation(
  1692. TokenHandle,
  1693. (TOKEN_INFORMATION_CLASS)TokenSessionId,
  1694. &SessionId,
  1695. sizeof(SessionId),
  1696. &ReturnLength);
  1697. if (!Result)
  1698. {
  1699. Result = TRUE;
  1700. SessionId = 0;
  1701. }
  1702. }
  1703. if (TokenHandle)
  1704. {
  1705. CloseHandle(TokenHandle);
  1706. }
  1707. if (plSessionId)
  1708. {
  1709. *plSessionId = SessionId;
  1710. }
  1711. return Result;
  1712. }