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.

2626 lines
68 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spool.c
  5. Abstract:
  6. This module contains the Netware print provider.
  7. Author:
  8. Yi-Hsin Sung (yihsins) 15-May-1993
  9. Revision History:
  10. --*/
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <nw.h>
  14. #include <nwreg.h>
  15. #include <nwpkstr.h>
  16. #include <splutil.h>
  17. #include <queue.h>
  18. #include <nwmisc.h>
  19. #include <Accctrl.h>
  20. #include <Aclapi.h>
  21. //------------------------------------------------------------------
  22. //
  23. // Local Definitions
  24. //
  25. //------------------------------------------------------------------
  26. #define NW_SIGNATURE 0x574E /* "NW" is the signature */
  27. #define SPOOL_STATUS_STARTDOC 0x00000001
  28. #define SPOOL_STATUS_ADDJOB 0x00000002
  29. #define SPOOL_STATUS_ABORT 0x00000003
  30. #define PRINTER_CHANGE_VALID 0x55770F07
  31. #define PRINTER_CHANGE_DEFAULT_TIMEOUT_VALUE 10000
  32. #define PRINTER_CHANGE_MINIMUM_TIMEOUT_VALUE 1000
  33. #define REG_TIMEOUT_PATH L"System\\CurrentControlSet\\Services\\NWCWorkstation\\Parameters"
  34. #define REG_TIMEOUT_VALUE_NAME L"PrintNotifyTimeout"
  35. #define NDS_MAX_NAME_CHARS 256
  36. #define NDS_MAX_NAME_SIZE ( NDS_MAX_NAME_CHARS * 2 )
  37. //
  38. // Printer structure
  39. //
  40. typedef struct _NWPRINTER {
  41. LPWSTR pszServer; // Server Name
  42. LPWSTR pszQueue; // Queue Name
  43. LPWSTR pszUncConnection; // UNC Connection Name
  44. // (only present if NDS print queue
  45. DWORD nQueueId; // Queue Id
  46. struct _NWPRINTER *pNextPrinter; // Points to the next printer
  47. struct _NWSPOOL *pSpoolList; // Points to the list of open handles
  48. } NWPRINTER, *PNWPRINTER;
  49. //
  50. // Handle structure
  51. //
  52. typedef struct _NWSPOOL {
  53. DWORD nSignature; // Signature
  54. DWORD errOpenPrinter; // OpenPrinter API will always return
  55. // success on known printers. This will
  56. // contain the error that we get
  57. // if something went wrong in the API.
  58. PNWPRINTER pPrinter; // Points to the corresponding printer
  59. HANDLE hServer; // Opened handle to the server
  60. struct _NWSPOOL *pNextSpool; // Points to the next handle
  61. DWORD nStatus; // Status
  62. DWORD nJobNumber; // StartDocPrinter/AddJob: Job Number
  63. HANDLE hChangeEvent; // WaitForPrinterChange: event to wait on
  64. DWORD nWaitFlags; // WaitForPrinterChange: flags to wait on
  65. DWORD nChangeFlags; // Changes that occurred to the printer
  66. } NWSPOOL, *PNWSPOOL;
  67. //------------------------------------------------------------------
  68. //
  69. // Global Variables
  70. //
  71. //------------------------------------------------------------------
  72. // Stores the timeout value used in WaitForPrinterChange ( in milliseconds )
  73. STATIC DWORD NwTimeOutValue = PRINTER_CHANGE_DEFAULT_TIMEOUT_VALUE;
  74. // Points to the link list of printers
  75. STATIC PNWPRINTER NwPrinterList = NULL;
  76. //------------------------------------------------------------------
  77. //
  78. // Local Function Prototypes
  79. //
  80. //------------------------------------------------------------------
  81. VOID
  82. NwSetPrinterChange(
  83. IN PNWSPOOL pSpool,
  84. IN DWORD nFlags
  85. );
  86. PNWPRINTER
  87. NwFindPrinterEntry(
  88. IN LPWSTR pszServer,
  89. IN LPWSTR pszQueue
  90. );
  91. DWORD
  92. NwCreatePrinterEntry(
  93. IN LPWSTR pszServer,
  94. IN LPWSTR pszQueue,
  95. OUT PNWPRINTER *ppPrinter,
  96. OUT PHANDLE phServer
  97. );
  98. VOID
  99. NwRemovePrinterEntry(
  100. IN PNWPRINTER pPrinter
  101. );
  102. LPWSTR
  103. NwGetUncObjectName(
  104. IN LPWSTR ContainerName
  105. );
  106. VOID
  107. NwInitializePrintProvider(
  108. VOID
  109. )
  110. /*++
  111. Routine Description:
  112. This routine initializes the server side print provider when
  113. the workstation service starts up.
  114. Arguments:
  115. None.
  116. Return Value:
  117. --*/
  118. {
  119. DWORD err;
  120. HKEY hkey;
  121. DWORD dwTemp;
  122. DWORD dwSize = sizeof( dwTemp );
  123. //
  124. // Read the time out value from the registry.
  125. // We will ignore all errors since we can always have a default time out.
  126. // The default will be used if the key does not exist.
  127. //
  128. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  129. REG_TIMEOUT_PATH,
  130. 0,
  131. KEY_READ,
  132. &hkey );
  133. if ( !err )
  134. {
  135. err = RegQueryValueExW( hkey,
  136. REG_TIMEOUT_VALUE_NAME,
  137. NULL,
  138. NULL,
  139. (LPBYTE) &dwTemp,
  140. &dwSize );
  141. if ( !err )
  142. {
  143. NwTimeOutValue = dwTemp;
  144. //
  145. // tommye - bug 139469 - removed
  146. // if (NwTimeOutValue >= 0) because NwtimeOutValue is a DWORD
  147. //
  148. // Use the minimum timeout value if the
  149. // value set in the registry is too small.
  150. //
  151. if (NwTimeOutValue <= PRINTER_CHANGE_MINIMUM_TIMEOUT_VALUE)
  152. {
  153. NwTimeOutValue = PRINTER_CHANGE_MINIMUM_TIMEOUT_VALUE;
  154. }
  155. }
  156. RegCloseKey( hkey );
  157. }
  158. }
  159. VOID
  160. NwTerminatePrintProvider(
  161. VOID
  162. )
  163. /*++
  164. Routine Description:
  165. This routine cleans up the server side print provider when
  166. the workstation service shut downs.
  167. Arguments:
  168. None.
  169. Return Value:
  170. --*/
  171. {
  172. PNWPRINTER pPrinter, pNext;
  173. PNWSPOOL pSpool, pNextSpool;
  174. for ( pPrinter = NwPrinterList; pPrinter; pPrinter = pNext )
  175. {
  176. pNext = pPrinter->pNextPrinter;
  177. pPrinter->pNextPrinter = NULL;
  178. for ( pSpool = pPrinter->pSpoolList; pSpool; pSpool = pNextSpool )
  179. {
  180. pNextSpool = pSpool->pNextSpool;
  181. if ( pSpool->hChangeEvent )
  182. CloseHandle( pSpool->hChangeEvent );
  183. (VOID) NtClose( pSpool->hServer );
  184. //
  185. // Free all memory associated with the context handle
  186. //
  187. FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
  188. }
  189. pPrinter->pSpoolList = NULL;
  190. FreeNwSplStr( pPrinter->pszServer );
  191. FreeNwSplStr( pPrinter->pszQueue );
  192. if ( pPrinter->pszUncConnection )
  193. {
  194. (void) NwrDeleteConnection( NULL,
  195. pPrinter->pszUncConnection,
  196. FALSE );
  197. FreeNwSplStr( pPrinter->pszUncConnection );
  198. }
  199. FreeNwSplMem( pPrinter, sizeof( NWPRINTER));
  200. }
  201. NwPrinterList = NULL;
  202. NwTimeOutValue = PRINTER_CHANGE_DEFAULT_TIMEOUT_VALUE;
  203. }
  204. DWORD
  205. NwrOpenPrinter(
  206. IN LPWSTR Reserved,
  207. IN LPWSTR pszPrinterName,
  208. IN DWORD fKnownPrinter,
  209. OUT LPNWWKSTA_PRINTER_CONTEXT phPrinter
  210. )
  211. /*++
  212. Routine Description:
  213. This routine retrieves a handle identifying the specified printer.
  214. Arguments:
  215. Reserved - Unused
  216. pszPrinterName - Name of the printer
  217. fKnownPrinter - TRUE if we have successfully opened the printer before,
  218. FALSE otherwise.
  219. phPrinter - Receives the handle that identifies the given printer
  220. Return Value:
  221. --*/
  222. {
  223. DWORD err;
  224. PNWSPOOL pSpool = NULL;
  225. LPWSTR pszServer = NULL;
  226. LPWSTR pszQueue = NULL;
  227. PNWPRINTER pPrinter = NULL;
  228. BOOL fImpersonate = FALSE ;
  229. HANDLE hServer;
  230. BOOL isPrinterNameValid;
  231. UNREFERENCED_PARAMETER( Reserved );
  232. if ( pszPrinterName[0] == L' ' &&
  233. pszPrinterName[1] == L'\\' &&
  234. pszPrinterName[2] == L'\\' )
  235. {
  236. if ( (pszServer = AllocNwSplStr( pszPrinterName + 1 )) == NULL )
  237. return ERROR_NOT_ENOUGH_MEMORY;
  238. isPrinterNameValid = ValidateUNCName( pszPrinterName + 1 );
  239. }
  240. else
  241. {
  242. if ( (pszServer = AllocNwSplStr( pszPrinterName )) == NULL )
  243. return ERROR_NOT_ENOUGH_MEMORY;
  244. isPrinterNameValid = ValidateUNCName( pszPrinterName );
  245. }
  246. CharUpperW( pszServer ); // convert in place
  247. //
  248. // ValidatePrinterName
  249. //
  250. if ( ( !isPrinterNameValid )
  251. || ( (pszQueue = wcschr( pszServer + 2, L'\\')) == NULL )
  252. || ( pszQueue == (pszServer + 2) )
  253. || ( *(pszQueue + 1) == L'\0' )
  254. )
  255. {
  256. FreeNwSplStr( pszServer );
  257. return ERROR_INVALID_NAME;
  258. }
  259. *pszQueue = L'\0'; // put a '\0' in place of '\\'
  260. pszQueue++; // Get past the '\0'
  261. if ( !(pSpool = AllocNwSplMem( LMEM_ZEROINIT, sizeof( NWSPOOL))))
  262. {
  263. err = ERROR_NOT_ENOUGH_MEMORY;
  264. goto ErrorExit;
  265. }
  266. //
  267. // Impersonate the client
  268. //
  269. if ((err = NwImpersonateClient()) != NO_ERROR)
  270. {
  271. goto ErrorExit;
  272. }
  273. fImpersonate = TRUE ;
  274. EnterCriticalSection( &NwPrintCritSec );
  275. if ((err = NwCreatePrinterEntry( pszServer, pszQueue, &pPrinter, &hServer)))
  276. {
  277. if ( !fKnownPrinter )
  278. {
  279. LeaveCriticalSection( &NwPrintCritSec );
  280. goto ErrorExit;
  281. }
  282. }
  283. //
  284. // Construct the print queue context handle to give back to the caller
  285. //
  286. pSpool->nSignature = NW_SIGNATURE;
  287. pSpool->errOpenPrinter = err;
  288. pSpool->hServer = hServer;
  289. pSpool->nStatus = 0;
  290. pSpool->nJobNumber = 0;
  291. pSpool->hChangeEvent= NULL;
  292. pSpool->nWaitFlags = 0;
  293. pSpool->nChangeFlags= 0;
  294. if ( !err )
  295. {
  296. pSpool->pPrinter = pPrinter;
  297. pSpool->pNextSpool = pPrinter->pSpoolList;
  298. pPrinter->pSpoolList= pSpool;
  299. }
  300. else
  301. {
  302. pSpool->pPrinter = NULL;
  303. pSpool->pNextSpool = NULL;
  304. }
  305. // We know about this printer before but failed to retrieve
  306. // it this time. Clean up the error and return successfully.
  307. // The error code is stored in the handle above which
  308. // will be returned on subsequent calls using this
  309. // dummy handle.
  310. err = NO_ERROR;
  311. LeaveCriticalSection( &NwPrintCritSec );
  312. ErrorExit:
  313. if (fImpersonate)
  314. (void) NwRevertToSelf() ;
  315. if ( err )
  316. {
  317. if ( pSpool )
  318. FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
  319. }
  320. else
  321. {
  322. *phPrinter = (NWWKSTA_PRINTER_CONTEXT) pSpool;
  323. }
  324. //
  325. // Free up all allocated memories
  326. //
  327. *(pszServer + wcslen( pszServer)) = L'\\';
  328. FreeNwSplStr( pszServer );
  329. return err;
  330. }
  331. DWORD
  332. NwrClosePrinter(
  333. IN OUT LPNWWKSTA_PRINTER_CONTEXT phPrinter
  334. )
  335. /*++
  336. Routine Description:
  337. This routine closes the given printer object.
  338. Arguments:
  339. phPrinter - Handle of the printer object
  340. Return Value:
  341. --*/
  342. {
  343. PNWSPOOL pSpool = (PNWSPOOL) *phPrinter;
  344. PNWPRINTER pPrinter;
  345. PNWSPOOL pCur, pPrev = NULL;
  346. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
  347. return ERROR_INVALID_HANDLE;
  348. //
  349. // If OpenPrinter failed, then this is a dummy handle.
  350. // We just need to free up the memory.
  351. //
  352. if ( pSpool->errOpenPrinter )
  353. {
  354. //
  355. // invalidate the signature, but leave a recognizable value
  356. //
  357. pSpool->nSignature += 1 ;
  358. FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
  359. *phPrinter = NULL;
  360. return NO_ERROR;
  361. }
  362. pPrinter = pSpool->pPrinter;
  363. ASSERT( pPrinter );
  364. //
  365. // Call EndDocPrinter if the user has not already done so
  366. //
  367. if ( pSpool->nStatus == SPOOL_STATUS_STARTDOC )
  368. {
  369. (void) NwrEndDocPrinter( *phPrinter );
  370. }
  371. else if ( pSpool->nStatus == SPOOL_STATUS_ADDJOB )
  372. {
  373. (void) NwrScheduleJob( *phPrinter, pSpool->nJobNumber );
  374. }
  375. if ( pSpool->hChangeEvent )
  376. CloseHandle( pSpool->hChangeEvent );
  377. pSpool->hChangeEvent = NULL;
  378. pSpool->nChangeFlags = 0;
  379. (VOID) NtClose( pSpool->hServer );
  380. EnterCriticalSection( &NwPrintCritSec );
  381. for ( pCur = pPrinter->pSpoolList; pCur;
  382. pPrev = pCur, pCur = pCur->pNextSpool )
  383. {
  384. if ( pCur == pSpool )
  385. {
  386. if ( pPrev )
  387. pPrev->pNextSpool = pCur->pNextSpool;
  388. else
  389. pPrinter->pSpoolList = pCur->pNextSpool;
  390. break;
  391. }
  392. }
  393. ASSERT( pCur );
  394. if ( pPrinter->pSpoolList == NULL )
  395. {
  396. #if DBG
  397. IF_DEBUG(PRINT)
  398. {
  399. KdPrint(("*************DELETED PRINTER ENTRY: %ws\\%ws\n\n",
  400. pPrinter->pszServer, pPrinter->pszQueue ));
  401. }
  402. #endif
  403. NwRemovePrinterEntry( pPrinter );
  404. }
  405. LeaveCriticalSection( &NwPrintCritSec );
  406. //
  407. // invalidate the signature, but leave a recognizable value
  408. //
  409. pSpool->nSignature += 1 ;
  410. pSpool->pNextSpool = NULL;
  411. pSpool->pPrinter = NULL;
  412. //
  413. // Free all memory associated with the context handle
  414. //
  415. FreeNwSplMem( pSpool, sizeof( NWSPOOL) );
  416. //
  417. // indicate to RPC we are done
  418. //
  419. *phPrinter = NULL;
  420. return NO_ERROR;
  421. }
  422. DWORD
  423. NwrGetPrinter(
  424. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  425. IN DWORD dwLevel,
  426. IN OUT LPBYTE pbPrinter,
  427. IN DWORD cbBuf,
  428. OUT LPDWORD pcbNeeded
  429. )
  430. /*++
  431. Routine Description:
  432. The routine retrieves information about the given printer.
  433. Arguments:
  434. hPrinter - Handle of the printer
  435. dwLevel - Specifies the level of the structure to which pbPrinter points.
  436. pbPrinter - Points to a buffer that receives the PRINTER_INFO object.
  437. cbBuf - Size, in bytes of the array pbPrinter points to.
  438. pcbNeeded - Points to a value which specifies the number of bytes copied
  439. if the function succeeds or the number of bytes required if
  440. cbBuf was too small.
  441. Return Value:
  442. --*/
  443. {
  444. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  445. PNWPRINTER pPrinter;
  446. LPBYTE pbEnd = pbPrinter + cbBuf;
  447. BOOL fFitInBuffer;
  448. DWORD_PTR *pOffsets;
  449. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  450. {
  451. return ERROR_INVALID_HANDLE;
  452. }
  453. else if ( pSpool->errOpenPrinter )
  454. {
  455. return pSpool->errOpenPrinter;
  456. }
  457. else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) && ( dwLevel != 3 ))
  458. {
  459. return ERROR_INVALID_LEVEL;
  460. }
  461. if ( !pbPrinter )
  462. {
  463. if ( cbBuf == 0 )
  464. {
  465. //
  466. // Calculate size needed
  467. //
  468. pPrinter = pSpool->pPrinter;
  469. ASSERT( pPrinter );
  470. if ( dwLevel == 1 )
  471. {
  472. *pcbNeeded = sizeof( PRINTER_INFO_1W ) +
  473. ( wcslen( pPrinter->pszServer )
  474. + wcslen( pPrinter->pszQueue ) + 2 ) * sizeof( WCHAR );
  475. }
  476. else if ( dwLevel == 2 )
  477. {
  478. *pcbNeeded = sizeof( PRINTER_INFO_2W ) +
  479. ( 2*wcslen( pPrinter->pszServer ) +
  480. 2*wcslen( pPrinter->pszQueue ) + 4 ) * sizeof( WCHAR );
  481. }
  482. else // Level == 3
  483. {
  484. PRINTER_INFO_3 *pPrinterInfo3 = (PRINTER_INFO_3 *) pbPrinter;
  485. *pcbNeeded = sizeof( PRINTER_INFO_3 );
  486. }
  487. return ERROR_INSUFFICIENT_BUFFER;
  488. }
  489. else
  490. return ERROR_INVALID_PARAMETER;
  491. }
  492. pPrinter = pSpool->pPrinter;
  493. ASSERT( pPrinter );
  494. if ( dwLevel == 1 )
  495. {
  496. PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) pbPrinter;
  497. LPBYTE pbFixedEnd = pbPrinter + sizeof( PRINTER_INFO_1W );
  498. //
  499. // Calculate size needed
  500. //
  501. *pcbNeeded = sizeof( PRINTER_INFO_1W ) +
  502. ( wcslen( pPrinter->pszServer )
  503. + wcslen( pPrinter->pszQueue ) + 2 ) * sizeof( WCHAR );
  504. if ( cbBuf < *pcbNeeded )
  505. return ERROR_INSUFFICIENT_BUFFER;
  506. pOffsets = PrinterInfo1Offsets;
  507. //
  508. // Fill in the structure
  509. //
  510. pPrinterInfo1->Flags = PRINTER_ENUM_REMOTE | PRINTER_ENUM_NAME;
  511. pPrinterInfo1->pComment = NULL;
  512. fFitInBuffer = NwlibCopyStringToBuffer(
  513. pPrinter->pszServer,
  514. wcslen( pPrinter->pszServer ),
  515. (LPWSTR) pbFixedEnd,
  516. (LPWSTR *) &pbEnd,
  517. &pPrinterInfo1->pDescription );
  518. ASSERT( fFitInBuffer );
  519. fFitInBuffer = NwlibCopyStringToBuffer(
  520. pPrinter->pszQueue,
  521. wcslen( pPrinter->pszQueue ),
  522. (LPWSTR) pbFixedEnd,
  523. (LPWSTR *) &pbEnd,
  524. &pPrinterInfo1->pName );
  525. ASSERT( fFitInBuffer );
  526. }
  527. else if ( dwLevel == 2 )
  528. {
  529. DWORD err;
  530. BYTE nQueueStatus;
  531. BYTE nNumJobs;
  532. PRINTER_INFO_2W *pPrinterInfo2 = (PRINTER_INFO_2W *) pbPrinter;
  533. LPBYTE pbFixedEnd = pbPrinter + sizeof( PRINTER_INFO_2W );
  534. //
  535. // Check if the buffer is big enough to hold all the data
  536. //
  537. *pcbNeeded = sizeof( PRINTER_INFO_2W ) +
  538. ( 2*wcslen( pPrinter->pszServer ) +
  539. 2*wcslen( pPrinter->pszQueue ) + 4 ) * sizeof( WCHAR );
  540. if ( cbBuf < *pcbNeeded )
  541. return ERROR_INSUFFICIENT_BUFFER;
  542. pOffsets = PrinterInfo2Offsets;
  543. err = NwReadQueueCurrentStatus( pSpool->hServer,
  544. pPrinter->nQueueId,
  545. &nQueueStatus,
  546. &nNumJobs );
  547. if ( err )
  548. return err;
  549. pPrinterInfo2->Status = (nQueueStatus & 0x05)? PRINTER_STATUS_PAUSED
  550. : 0;
  551. pPrinterInfo2->cJobs = nNumJobs;
  552. fFitInBuffer = NwlibCopyStringToBuffer(
  553. pPrinter->pszServer,
  554. wcslen( pPrinter->pszServer ),
  555. (LPCWSTR) pbFixedEnd,
  556. (LPWSTR *) &pbEnd,
  557. &pPrinterInfo2->pServerName );
  558. ASSERT( fFitInBuffer );
  559. pbEnd -= ( wcslen( pPrinter->pszQueue) + 1 ) * sizeof( WCHAR );
  560. wcscpy( (LPWSTR) pbEnd, pPrinter->pszQueue );
  561. pbEnd -= ( wcslen( pPrinter->pszServer) + 1 ) * sizeof( WCHAR );
  562. wcscpy( (LPWSTR) pbEnd, pPrinter->pszServer );
  563. *(pbEnd + wcslen( pPrinter->pszServer )*sizeof(WCHAR))= L'\\';
  564. pPrinterInfo2->pPrinterName = (LPWSTR) pbEnd;
  565. fFitInBuffer = NwlibCopyStringToBuffer(
  566. pPrinter->pszQueue,
  567. wcslen( pPrinter->pszQueue ),
  568. (LPCWSTR) pbFixedEnd,
  569. (LPWSTR *) &pbEnd,
  570. &pPrinterInfo2->pShareName );
  571. ASSERT( fFitInBuffer );
  572. pPrinterInfo2->pPortName = NULL;
  573. pPrinterInfo2->pDriverName = NULL;
  574. pPrinterInfo2->pComment = NULL;
  575. pPrinterInfo2->pLocation = NULL;
  576. pPrinterInfo2->pDevMode = NULL;
  577. pPrinterInfo2->pSepFile = NULL;
  578. pPrinterInfo2->pPrintProcessor = NULL;
  579. pPrinterInfo2->pDatatype = NULL;
  580. pPrinterInfo2->pParameters = NULL;
  581. pPrinterInfo2->pSecurityDescriptor = NULL;
  582. pPrinterInfo2->Attributes = PRINTER_ATTRIBUTE_QUEUED;
  583. pPrinterInfo2->Priority = 0;
  584. pPrinterInfo2->DefaultPriority = 0;
  585. pPrinterInfo2->StartTime = 0;
  586. pPrinterInfo2->UntilTime = 0;
  587. pPrinterInfo2->AveragePPM = 0;
  588. }
  589. else // Level == 3
  590. {
  591. PRINTER_INFO_3 *pPrinterInfo3 = (PRINTER_INFO_3 *) pbPrinter;
  592. *pcbNeeded = sizeof( PRINTER_INFO_3 );
  593. if ( cbBuf < *pcbNeeded )
  594. return ERROR_INSUFFICIENT_BUFFER;
  595. pOffsets = PrinterInfo3Offsets;
  596. pPrinterInfo3->pSecurityDescriptor = NULL;
  597. }
  598. MarshallDownStructure( pbPrinter, pOffsets, pbPrinter );
  599. return NO_ERROR;
  600. }
  601. DWORD
  602. NwrSetPrinter(
  603. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  604. IN DWORD dwCommand
  605. )
  606. /*++
  607. Routine Description:
  608. The routine sets information about the given printer.
  609. Arguments:
  610. hPrinter - Handle of the printer
  611. dwCommand - Specifies the new printer state
  612. Return Value:
  613. --*/
  614. {
  615. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  616. DWORD err = NO_ERROR;
  617. PNWPRINTER pPrinter;
  618. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  619. {
  620. return ERROR_INVALID_HANDLE;
  621. }
  622. else if ( pSpool->errOpenPrinter )
  623. {
  624. return pSpool->errOpenPrinter;
  625. }
  626. pPrinter = pSpool->pPrinter;
  627. ASSERT( pPrinter );
  628. switch ( dwCommand )
  629. {
  630. case PRINTER_CONTROL_PAUSE:
  631. case PRINTER_CONTROL_RESUME:
  632. {
  633. BYTE nQueueStatus = 0;
  634. BYTE nNumJobs;
  635. //
  636. // Get the original queue status so that we don't overwrite
  637. // some of the bits.
  638. //
  639. err = NwReadQueueCurrentStatus( pSpool->hServer,
  640. pPrinter->nQueueId,
  641. &nQueueStatus,
  642. &nNumJobs );
  643. if ( !err )
  644. {
  645. //
  646. // Clear the pause bits, and leave the rest alone.
  647. //
  648. nQueueStatus &= ~0x05;
  649. }
  650. if ( dwCommand == PRINTER_CONTROL_PAUSE )
  651. {
  652. nQueueStatus |= 0x04;
  653. }
  654. err = NwSetQueueCurrentStatus( pSpool->hServer,
  655. pPrinter->nQueueId,
  656. nQueueStatus );
  657. if ( !err )
  658. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_PRINTER );
  659. break;
  660. }
  661. case PRINTER_CONTROL_PURGE:
  662. err = NwRemoveAllJobsFromQueue( pSpool->hServer,
  663. pPrinter->nQueueId );
  664. if ( !err )
  665. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_PRINTER |
  666. PRINTER_CHANGE_DELETE_JOB );
  667. break;
  668. default:
  669. //
  670. // dwCommand is 0 so that means
  671. // some properties of the printer has changed.
  672. // We will ignore the properties that
  673. // are being modified since most properties
  674. // are stored in the registry by spooler.
  675. // All we need to do is to signal WaitForPrinterChange to
  676. // return so that print manager will refresh its data.
  677. //
  678. ASSERT( dwCommand == 0 );
  679. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_PRINTER );
  680. break;
  681. }
  682. return err;
  683. }
  684. DWORD
  685. NwrEnumPrinters(
  686. IN LPWSTR Reserved,
  687. IN LPWSTR pszName,
  688. IN OUT LPBYTE pbPrinter,
  689. IN DWORD cbBuf,
  690. OUT LPDWORD pcbNeeded,
  691. OUT LPDWORD pcReturned
  692. )
  693. /*++
  694. Routine Description:
  695. This routine enumerates the available providers, servers, printers
  696. depending on the given pszName.
  697. Arguments:
  698. Reserved - Unused
  699. pszName - The name of the container object
  700. pbPrinter - Points to the array to receive the PRINTER_INFO objects
  701. cbBuf - Size, in bytes of pbPrinter
  702. pcbNeeded - Count of bytes needed
  703. pcReturned - Count of PRINTER_INFO objects
  704. Return Value:
  705. --*/
  706. {
  707. PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) pbPrinter;
  708. *pcbNeeded = 0;
  709. *pcReturned = 0;
  710. if ( ( cbBuf != 0 ) && !pbPrinter )
  711. {
  712. return ERROR_INVALID_PARAMETER;
  713. }
  714. if ( !pszName ) // Enumerate the provider name
  715. {
  716. BOOL fFitInBuffer;
  717. LPBYTE pbFixedEnd = pbPrinter + sizeof( PRINTER_INFO_1W );
  718. LPBYTE pbEnd = pbPrinter + cbBuf;
  719. *pcbNeeded = sizeof( PRINTER_INFO_1W ) +
  720. ( 2 * wcslen( NwProviderName ) +
  721. + 2) * sizeof(WCHAR);
  722. if ( *pcbNeeded > cbBuf )
  723. return ERROR_INSUFFICIENT_BUFFER;
  724. pPrinterInfo1->Flags = PRINTER_ENUM_ICON1 |
  725. PRINTER_ENUM_CONTAINER |
  726. PRINTER_ENUM_EXPAND;
  727. pPrinterInfo1->pComment = NULL;
  728. fFitInBuffer = NwlibCopyStringToBuffer(
  729. NwProviderName,
  730. wcslen( NwProviderName ),
  731. (LPWSTR) pbFixedEnd,
  732. (LPWSTR *) &pbEnd,
  733. &pPrinterInfo1->pDescription );
  734. ASSERT( fFitInBuffer );
  735. fFitInBuffer = NwlibCopyStringToBuffer(
  736. NwProviderName,
  737. wcslen( NwProviderName ),
  738. (LPWSTR) pbFixedEnd,
  739. (LPWSTR *) &pbEnd,
  740. &pPrinterInfo1->pName );
  741. ASSERT( fFitInBuffer );
  742. MarshallDownStructure( pbPrinter, PrinterInfo1Offsets, pbPrinter );
  743. *pcReturned = 1;
  744. }
  745. else if ( pszName && *pszName )
  746. {
  747. DWORD err;
  748. LPWSTR pszFullName;
  749. LPWSTR pszServer;
  750. NWWKSTA_CONTEXT_HANDLE handle;
  751. BYTE bTemp = 0;
  752. LPBYTE pbTempBuf = pbPrinter ? pbPrinter : &bTemp;
  753. if ( (pszFullName = LocalAlloc( 0, (wcslen( pszName ) + 1) *
  754. sizeof(WCHAR) ) ) == NULL )
  755. return ERROR_NOT_ENOUGH_MEMORY;
  756. wcscpy( pszFullName, pszName );
  757. pszServer = wcschr( pszFullName, L'!');
  758. if ( pszServer )
  759. *pszServer++ = 0;
  760. if ( lstrcmpiW( pszFullName, NwProviderName ) )
  761. {
  762. LocalFree( pszFullName );
  763. return ERROR_INVALID_NAME;
  764. }
  765. if ( !pszServer ) // Enumerate servers
  766. {
  767. LocalFree( pszFullName );
  768. err = NwOpenEnumPrintServers( &handle );
  769. if ( err != NO_ERROR )
  770. {
  771. return err;
  772. }
  773. err = NwrEnum( handle,
  774. (DWORD_PTR) -1,
  775. pbTempBuf,
  776. cbBuf,
  777. pcbNeeded,
  778. pcReturned );
  779. if ( err != NO_ERROR )
  780. {
  781. NwrCloseEnum( &handle );
  782. return err;
  783. }
  784. err = NwrCloseEnum( &handle );
  785. if ( err != NO_ERROR )
  786. {
  787. return err;
  788. }
  789. }
  790. else // Enumerate NDS sub-trees or print queues
  791. {
  792. LPWSTR tempStrPtr = pszServer;
  793. DWORD dwClassType = 0;
  794. if ( tempStrPtr[0] == L'\\' &&
  795. tempStrPtr[1] == L'\\' &&
  796. tempStrPtr[2] == L' ' )
  797. tempStrPtr = &tempStrPtr[1];
  798. err = NwrOpenEnumNdsSubTrees_Print( NULL, tempStrPtr, &dwClassType, &handle );
  799. if ( err == ERROR_NETWORK_ACCESS_DENIED && dwClassType == CLASS_TYPE_NCP_SERVER )
  800. {
  801. // An error code from the above NwOpenEnumNdsSubTrees could have
  802. // failed because the object was a server, which cannot be enumerated
  803. // with the NDS tree APIs. If so we try to get the print queues with the
  804. // regular NW APIs.
  805. tempStrPtr = NwGetUncObjectName( tempStrPtr );
  806. err = NwOpenEnumPrintQueues( tempStrPtr, &handle );
  807. if ( err != NO_ERROR )
  808. {
  809. LocalFree( pszFullName );
  810. return err;
  811. }
  812. }
  813. if ( err != NO_ERROR )
  814. {
  815. // An error code from the above NwOpenEnumNdsSubTrees could have
  816. // failed because the object was not a part of an NDS tree.
  817. // So we try to get the print queues with the regular NW APIs.
  818. err = NwOpenEnumPrintQueues( tempStrPtr, &handle );
  819. if ( err != NO_ERROR )
  820. {
  821. LocalFree( pszFullName );
  822. return err;
  823. }
  824. }
  825. //
  826. // Get rid of the allocated temp buffer that we've been using
  827. // indirectly through tempStrPtr and pszServer.
  828. //
  829. LocalFree( pszFullName );
  830. err = NwrEnum( handle,
  831. 0xFFFFFFFF,
  832. pbTempBuf,
  833. cbBuf,
  834. pcbNeeded,
  835. pcReturned );
  836. if ( err != NO_ERROR )
  837. {
  838. NwrCloseEnum( &handle );
  839. return err;
  840. }
  841. err = NwrCloseEnum( &handle );
  842. if ( err != NO_ERROR )
  843. {
  844. return err;
  845. }
  846. }
  847. }
  848. return NO_ERROR;
  849. }
  850. DWORD
  851. NwrStartDocPrinter(
  852. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  853. IN LPWSTR pszDocument,
  854. IN LPWSTR pszUser,
  855. IN DWORD PrintOptions //Multi-User Addition
  856. )
  857. /*++
  858. Routine Description:
  859. This routine informs the print spooler that a document is to be spooled
  860. for printing.
  861. Arguments:
  862. hPrinter - Handle of the printer
  863. pszDocument - Name of the document to be printed
  864. pszUser - Name of the user submitting the print job
  865. Return Value:
  866. --*/
  867. {
  868. DWORD err;
  869. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  870. if ( !pSpool || (pSpool->nSignature != NW_SIGNATURE) )
  871. {
  872. err = ERROR_INVALID_HANDLE;
  873. }
  874. else if ( pSpool->errOpenPrinter )
  875. {
  876. err = pSpool->errOpenPrinter;
  877. }
  878. else if ( pSpool->nStatus != 0 )
  879. {
  880. err = ERROR_INVALID_PARAMETER;
  881. }
  882. else
  883. {
  884. //
  885. // Get pSpool->nJobNumber from CreateQueueJobAndFile
  886. //
  887. PNWPRINTER pPrinter = pSpool->pPrinter;
  888. WORD nJobNumber = 0;
  889. ASSERT( pPrinter );
  890. err = NwCreateQueueJobAndFile( pSpool->hServer,
  891. pPrinter->nQueueId,
  892. pszDocument,
  893. pszUser,
  894. PrintOptions, //Multi-User addition
  895. pPrinter->pszQueue,
  896. &nJobNumber );
  897. if ( !err )
  898. {
  899. pSpool->nJobNumber = nJobNumber;
  900. pSpool->nStatus = SPOOL_STATUS_STARTDOC;
  901. NwSetPrinterChange( pSpool, PRINTER_CHANGE_ADD_JOB |
  902. PRINTER_CHANGE_SET_PRINTER );
  903. }
  904. }
  905. return err;
  906. }
  907. DWORD
  908. NwrWritePrinter(
  909. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  910. IN LPBYTE pBuf,
  911. IN DWORD cbBuf,
  912. OUT LPDWORD pcbWritten
  913. )
  914. /*++
  915. Routine Description:
  916. This routine informs the print spooler that the specified data should be
  917. written to the given printer.
  918. Arguments:
  919. hPrinter - Handle of the printer object
  920. pBuf - Address of array that contains printer data
  921. cbBuf - Size, in bytes of pBuf
  922. pcbWritten - Receives the number of bytes actually written to the printer
  923. Return Value:
  924. --*/
  925. {
  926. DWORD err = NO_ERROR;
  927. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  928. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE))
  929. {
  930. err = ERROR_INVALID_HANDLE;
  931. }
  932. else if ( pSpool->errOpenPrinter )
  933. {
  934. err = pSpool->errOpenPrinter;
  935. }
  936. else if ( pSpool->nStatus != SPOOL_STATUS_STARTDOC )
  937. {
  938. err = ERROR_INVALID_PARAMETER;
  939. }
  940. else
  941. {
  942. NTSTATUS ntstatus;
  943. IO_STATUS_BLOCK IoStatusBlock;
  944. PNWPRINTER pPrinter = pSpool->pPrinter;
  945. ASSERT( pPrinter );
  946. ntstatus = NtWriteFile( pSpool->hServer,
  947. NULL,
  948. NULL,
  949. NULL,
  950. &IoStatusBlock,
  951. pBuf,
  952. cbBuf,
  953. NULL,
  954. NULL );
  955. if ( NT_SUCCESS(ntstatus))
  956. ntstatus = IoStatusBlock.Status;
  957. if ( NT_SUCCESS(ntstatus) )
  958. {
  959. *pcbWritten = (DWORD) IoStatusBlock.Information;
  960. NwSetPrinterChange( pSpool, PRINTER_CHANGE_WRITE_JOB );
  961. }
  962. else
  963. {
  964. KdPrint(("NWWORKSTATION: NtWriteFile failed 0x%08lx\n", ntstatus));
  965. *pcbWritten = 0;
  966. err = RtlNtStatusToDosError( ntstatus );
  967. }
  968. }
  969. return err;
  970. }
  971. DWORD
  972. NwrAbortPrinter(
  973. IN NWWKSTA_PRINTER_CONTEXT hPrinter
  974. )
  975. /*++
  976. Routine Description:
  977. This routine deletes a printer's spool file if the printer is configured
  978. for spooling.
  979. Arguments:
  980. hPrinter - Handle of the printer object
  981. Return Value:
  982. --*/
  983. {
  984. DWORD err;
  985. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  986. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
  987. {
  988. err = ERROR_INVALID_HANDLE;
  989. }
  990. else if ( pSpool->errOpenPrinter )
  991. {
  992. err = pSpool->errOpenPrinter;
  993. }
  994. else if ( pSpool->nStatus != SPOOL_STATUS_STARTDOC )
  995. {
  996. err = ERROR_INVALID_PARAMETER;
  997. }
  998. else
  999. {
  1000. PNWPRINTER pPrinter = pSpool->pPrinter;
  1001. ASSERT( pPrinter );
  1002. err = NwRemoveJobFromQueue( pSpool->hServer,
  1003. pPrinter->nQueueId,
  1004. (WORD) pSpool->nJobNumber );
  1005. if ( !err )
  1006. {
  1007. pSpool->nJobNumber = 0;
  1008. pSpool->nStatus = SPOOL_STATUS_ABORT;
  1009. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
  1010. }
  1011. }
  1012. return err;
  1013. }
  1014. DWORD
  1015. NwrEndDocPrinter(
  1016. IN NWWKSTA_PRINTER_CONTEXT hPrinter
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. This routine ends the print job for the given printer.
  1021. Arguments:
  1022. hPrinter - Handle of the printer object
  1023. Return Value:
  1024. --*/
  1025. {
  1026. DWORD err = NO_ERROR;
  1027. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1028. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
  1029. {
  1030. err = ERROR_INVALID_HANDLE;
  1031. }
  1032. else if ( pSpool->errOpenPrinter )
  1033. {
  1034. err = pSpool->errOpenPrinter;
  1035. }
  1036. else if ( ( pSpool->nStatus != SPOOL_STATUS_STARTDOC )
  1037. && ( pSpool->nStatus != SPOOL_STATUS_ABORT )
  1038. )
  1039. {
  1040. err = ERROR_INVALID_PARAMETER;
  1041. }
  1042. else
  1043. {
  1044. PNWPRINTER pPrinter = pSpool->pPrinter;
  1045. ASSERT( pPrinter );
  1046. if ( pSpool->nStatus == SPOOL_STATUS_STARTDOC )
  1047. {
  1048. err = NwCloseFileAndStartQueueJob( pSpool->hServer,
  1049. pPrinter->nQueueId,
  1050. (WORD) pSpool->nJobNumber );
  1051. if ( !err )
  1052. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
  1053. }
  1054. if ( !err )
  1055. {
  1056. pSpool->nJobNumber = 0;
  1057. pSpool->nStatus = 0;
  1058. }
  1059. }
  1060. return err;
  1061. }
  1062. DWORD
  1063. NwrGetJob(
  1064. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1065. IN DWORD dwJobId,
  1066. IN DWORD dwLevel,
  1067. IN OUT LPBYTE pbJob,
  1068. IN DWORD cbBuf,
  1069. OUT LPDWORD pcbNeeded
  1070. )
  1071. /*++
  1072. Routine Description:
  1073. Arguments:
  1074. hPrinter - Handle of the printer
  1075. dwJobId -
  1076. dwLevel -
  1077. pbJob -
  1078. cbBuf -
  1079. pcbNeeded -
  1080. Return Value:
  1081. --*/
  1082. {
  1083. DWORD err;
  1084. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1085. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  1086. {
  1087. err = ERROR_INVALID_HANDLE;
  1088. }
  1089. // allow NULL for bpJob if cbBuf is 0.
  1090. // Relies on NwGetQueueJobInfo to properly handle NULL pointer in request to fill pcbNeeded
  1091. else if ( (cbBuf != 0) && ( !pbJob ) )
  1092. {
  1093. err = ERROR_INVALID_PARAMETER;
  1094. }
  1095. else if ( pSpool->errOpenPrinter )
  1096. {
  1097. err = pSpool->errOpenPrinter;
  1098. }
  1099. else if (( dwLevel != 1 ) && ( dwLevel != 2 ))
  1100. {
  1101. err = ERROR_INVALID_LEVEL;
  1102. }
  1103. else
  1104. {
  1105. DWORD nPrinterLen;
  1106. LPWSTR pszPrinter;
  1107. LPBYTE FixedPortion = pbJob;
  1108. LPWSTR EndOfVariableData = (LPWSTR) (pbJob + cbBuf);
  1109. PNWPRINTER pPrinter = pSpool->pPrinter;
  1110. ASSERT( pPrinter );
  1111. pszPrinter = AllocNwSplMem( LMEM_ZEROINIT,
  1112. nPrinterLen = ( wcslen( pPrinter->pszServer) +
  1113. wcslen( pPrinter->pszQueue) + 2) * sizeof(WCHAR));
  1114. if ( pszPrinter == NULL )
  1115. return ERROR_NOT_ENOUGH_MEMORY;
  1116. wcscpy( pszPrinter, pPrinter->pszServer );
  1117. wcscat( pszPrinter, L"\\" );
  1118. wcscat( pszPrinter, pPrinter->pszQueue );
  1119. *pcbNeeded = 0;
  1120. err = NwGetQueueJobInfo( pSpool->hServer,
  1121. pPrinter->nQueueId,
  1122. (WORD) dwJobId,
  1123. pszPrinter,
  1124. dwLevel,
  1125. &FixedPortion,
  1126. &EndOfVariableData,
  1127. pcbNeeded );
  1128. FreeNwSplMem( pszPrinter, nPrinterLen );
  1129. if ( !err )
  1130. {
  1131. switch( dwLevel )
  1132. {
  1133. case 1:
  1134. MarshallDownStructure( pbJob, JobInfo1Offsets, pbJob );
  1135. break;
  1136. case 2:
  1137. MarshallDownStructure( pbJob, JobInfo2Offsets, pbJob );
  1138. break;
  1139. default:
  1140. ASSERT( FALSE );
  1141. break;
  1142. }
  1143. }
  1144. }
  1145. return err;
  1146. }
  1147. DWORD
  1148. NwrEnumJobs(
  1149. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1150. IN DWORD dwFirstJob,
  1151. IN DWORD dwNoJobs,
  1152. IN DWORD dwLevel,
  1153. IN OUT LPBYTE pbJob,
  1154. IN DWORD cbBuf,
  1155. OUT LPDWORD pcbNeeded,
  1156. OUT LPDWORD pcReturned
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. Arguments:
  1161. hPrinter - Handle of the printer
  1162. dwFirstJob -
  1163. dwNoJobs -
  1164. dwLevel -
  1165. pbJob -
  1166. cbBuf -
  1167. pcbNeeded -
  1168. pcReturned -
  1169. Return Value:
  1170. --*/
  1171. {
  1172. DWORD err;
  1173. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1174. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  1175. {
  1176. err = ERROR_INVALID_HANDLE;
  1177. }
  1178. // allow NULL for bpJob if cbBuf is 0.
  1179. // Relies on NwGetQueueJobInfo to properly handle NULL pointer in request to fill pcbNeeded
  1180. else if ( (cbBuf != 0) && ( !pbJob ) )
  1181. {
  1182. err = ERROR_INVALID_PARAMETER;
  1183. }
  1184. else if ( pSpool->errOpenPrinter )
  1185. {
  1186. err = pSpool->errOpenPrinter;
  1187. }
  1188. else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) )
  1189. {
  1190. err = ERROR_INVALID_LEVEL;
  1191. }
  1192. else
  1193. {
  1194. PNWPRINTER pPrinter = pSpool->pPrinter;
  1195. LPWSTR pszPrinter;
  1196. DWORD nPrinterLen;
  1197. ASSERT( pPrinter );
  1198. pszPrinter = AllocNwSplMem( LMEM_ZEROINIT,
  1199. nPrinterLen = ( wcslen( pPrinter->pszServer ) +
  1200. wcslen( pPrinter->pszQueue) + 2) * sizeof(WCHAR));
  1201. if ( pszPrinter == NULL )
  1202. return ERROR_NOT_ENOUGH_MEMORY;
  1203. wcscpy( pszPrinter, pPrinter->pszServer );
  1204. wcscat( pszPrinter, L"\\" );
  1205. wcscat( pszPrinter, pPrinter->pszQueue );
  1206. err = NwGetQueueJobs( pSpool->hServer,
  1207. pPrinter->nQueueId,
  1208. pszPrinter,
  1209. dwFirstJob,
  1210. dwNoJobs,
  1211. dwLevel,
  1212. pbJob,
  1213. cbBuf,
  1214. pcbNeeded,
  1215. pcReturned );
  1216. FreeNwSplMem( pszPrinter, nPrinterLen );
  1217. if ( !err )
  1218. {
  1219. DWORD_PTR *pOffsets;
  1220. DWORD cbStruct;
  1221. DWORD cReturned = *pcReturned;
  1222. LPBYTE pbBuffer = pbJob;
  1223. switch( dwLevel )
  1224. {
  1225. case 1:
  1226. pOffsets = JobInfo1Offsets;
  1227. cbStruct = sizeof( JOB_INFO_1W );
  1228. break;
  1229. case 2:
  1230. pOffsets = JobInfo2Offsets;
  1231. cbStruct = sizeof( JOB_INFO_2W );
  1232. break;
  1233. default:
  1234. ASSERT( FALSE );
  1235. break;
  1236. }
  1237. while ( cReturned-- )
  1238. {
  1239. MarshallDownStructure( pbBuffer, pOffsets, pbJob );
  1240. pbBuffer += cbStruct;
  1241. }
  1242. }
  1243. }
  1244. return err;
  1245. }
  1246. DWORD
  1247. NwrSetJob(
  1248. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1249. IN DWORD dwJobId,
  1250. IN DWORD dwLevel,
  1251. IN PNW_JOB_INFO pNwJobInfo,
  1252. IN DWORD dwCommand
  1253. )
  1254. /*++
  1255. Routine Description:
  1256. Arguments:
  1257. hPrinter - Handle of the printer
  1258. dwJobId -
  1259. dwLevel -
  1260. pNwJobInfo-
  1261. dwCommand -
  1262. Return Value:
  1263. --*/
  1264. {
  1265. DWORD err = NO_ERROR;
  1266. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1267. PNWPRINTER pPrinter;
  1268. if ( !pSpool || pSpool->nSignature != NW_SIGNATURE )
  1269. {
  1270. err = ERROR_INVALID_HANDLE;
  1271. }
  1272. else if ( ( dwLevel != 0 ) && ( !pNwJobInfo ) )
  1273. {
  1274. err = ERROR_INVALID_PARAMETER;
  1275. }
  1276. else if ( pSpool->errOpenPrinter )
  1277. {
  1278. err = pSpool->errOpenPrinter;
  1279. }
  1280. else if ( ( dwLevel != 0 ) && ( dwLevel != 1 ) && ( dwLevel != 2 ) )
  1281. {
  1282. err = ERROR_INVALID_LEVEL;
  1283. }
  1284. if ( err )
  1285. return err;
  1286. pPrinter = pSpool->pPrinter;
  1287. ASSERT( pPrinter );
  1288. if ( ( dwCommand == JOB_CONTROL_CANCEL ) ||
  1289. ( dwCommand == JOB_CONTROL_DELETE ) )
  1290. {
  1291. err = NwRemoveJobFromQueue( pSpool->hServer,
  1292. pPrinter->nQueueId,
  1293. (WORD) dwJobId );
  1294. if ( !err )
  1295. NwSetPrinterChange( pSpool, PRINTER_CHANGE_DELETE_JOB |
  1296. PRINTER_CHANGE_SET_PRINTER );
  1297. // Since the job is removed, we don't need to change other
  1298. // information about it.
  1299. }
  1300. else
  1301. {
  1302. if ( dwLevel != 0 )
  1303. {
  1304. if ( pNwJobInfo->nPosition != JOB_POSITION_UNSPECIFIED )
  1305. {
  1306. err = NwChangeQueueJobPosition( pSpool->hServer,
  1307. pPrinter->nQueueId,
  1308. (WORD) dwJobId,
  1309. (BYTE) pNwJobInfo->nPosition );
  1310. }
  1311. }
  1312. if ( ( !err ) && ( dwCommand == JOB_CONTROL_RESTART ))
  1313. {
  1314. err = ERROR_NOT_SUPPORTED;
  1315. }
  1316. else if ( !err )
  1317. {
  1318. err = NwChangeQueueJobEntry( pSpool->hServer,
  1319. pPrinter->nQueueId,
  1320. (WORD) dwJobId,
  1321. dwCommand,
  1322. pNwJobInfo );
  1323. }
  1324. if ( !err )
  1325. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
  1326. }
  1327. return err;
  1328. }
  1329. DWORD
  1330. NwrAddJob(
  1331. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1332. OUT LPADDJOB_INFO_1W pAddInfo1,
  1333. IN DWORD cbBuf,
  1334. OUT LPDWORD pcbNeeded
  1335. )
  1336. /*++
  1337. Routine Description:
  1338. Arguments:
  1339. hPrinter - Handle of the printer.
  1340. pAddInfo1 - Output buffer to hold ADDJOB_INFO_1W structure.
  1341. cbBuf - Output buffer size in bytes.
  1342. pcbNeeded - Required output buffer size in bytes.
  1343. Return Value:
  1344. --*/
  1345. {
  1346. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1347. PNWPRINTER pPrinter;
  1348. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE )) {
  1349. return ERROR_INVALID_HANDLE;
  1350. }
  1351. if ( pSpool->errOpenPrinter ) {
  1352. return pSpool->errOpenPrinter;
  1353. }
  1354. if ( pSpool->nStatus != 0 ) {
  1355. return ERROR_INVALID_PARAMETER;
  1356. }
  1357. pPrinter = pSpool->pPrinter;
  1358. ASSERT( pPrinter );
  1359. *pcbNeeded = sizeof(ADDJOB_INFO_1W) +
  1360. (wcslen(pPrinter->pszServer) +
  1361. wcslen(pPrinter->pszQueue) + 2) * sizeof(WCHAR);
  1362. if (cbBuf < *pcbNeeded) {
  1363. return ERROR_INSUFFICIENT_BUFFER;
  1364. }
  1365. //
  1366. // Write UNC path name into the output buffer.
  1367. //
  1368. // dfergus 19 Apr 2001 - 348006
  1369. // DWORD cast
  1370. pAddInfo1->Path = (LPWSTR) ((DWORD) pAddInfo1 + sizeof(ADDJOB_INFO_1W));
  1371. //
  1372. wcscpy(pAddInfo1->Path, pPrinter->pszServer);
  1373. wcscat(pAddInfo1->Path, L"\\" );
  1374. wcscat(pAddInfo1->Path, pPrinter->pszQueue);
  1375. //
  1376. // Return special job id value which the client (winspool.drv) looks
  1377. // for and does an FSCTL call to our redirector to get the real
  1378. // job id. We cannot return a real job id at this point because
  1379. // the CreateQueueJobAndFile NCP is not issue until the client opens
  1380. // the UNC name we return in this API.
  1381. //
  1382. pAddInfo1->JobId = (DWORD) -1;
  1383. //
  1384. // Save context information
  1385. //
  1386. pSpool->nJobNumber = pAddInfo1->JobId;
  1387. pSpool->nStatus = SPOOL_STATUS_ADDJOB;
  1388. #if DBG
  1389. IF_DEBUG(PRINT) {
  1390. KdPrint(("NWWORKSTATION: NwrAddJob Path=%ws, JobId=%lu, BytesNeeded=%lu\n",
  1391. pAddInfo1->Path, pAddInfo1->JobId, *pcbNeeded));
  1392. }
  1393. #endif
  1394. NwSetPrinterChange( pSpool, PRINTER_CHANGE_ADD_JOB |
  1395. PRINTER_CHANGE_SET_PRINTER );
  1396. return NO_ERROR;
  1397. }
  1398. DWORD
  1399. NwrScheduleJob(
  1400. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1401. IN DWORD dwJobId
  1402. )
  1403. /*++
  1404. Routine Description:
  1405. Arguments:
  1406. hPrinter - Handle of the printer
  1407. dwJobId - Job identification number
  1408. Return Value:
  1409. --*/
  1410. {
  1411. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1412. PNWPRINTER pPrinter;
  1413. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE )) {
  1414. return ERROR_INVALID_HANDLE;
  1415. }
  1416. if ( pSpool->errOpenPrinter ) {
  1417. return pSpool->errOpenPrinter;
  1418. }
  1419. if (pSpool->nStatus != SPOOL_STATUS_ADDJOB) {
  1420. return ERROR_INVALID_PARAMETER;
  1421. }
  1422. pPrinter = pSpool->pPrinter;
  1423. ASSERT( pPrinter );
  1424. pSpool->nJobNumber = 0;
  1425. pSpool->nStatus = 0;
  1426. NwSetPrinterChange( pSpool, PRINTER_CHANGE_SET_JOB );
  1427. return NO_ERROR;
  1428. }
  1429. DWORD
  1430. NwrWaitForPrinterChange(
  1431. IN NWWKSTA_PRINTER_CONTEXT hPrinter,
  1432. IN OUT LPDWORD pdwFlags
  1433. )
  1434. /*++
  1435. Routine Description:
  1436. Arguments:
  1437. hPrinter - Handle of the printer
  1438. pdwFlags -
  1439. Return Value:
  1440. --*/
  1441. {
  1442. PNWSPOOL pSpool = (PNWSPOOL) hPrinter;
  1443. HANDLE hChangeEvent = NULL;
  1444. DWORD nRetVal;
  1445. HANDLE ahWaitEvents[2];
  1446. DWORD err = NO_ERROR;
  1447. if ( !pSpool || ( pSpool->nSignature != NW_SIGNATURE ))
  1448. {
  1449. return ERROR_INVALID_HANDLE;
  1450. }
  1451. else if ( pSpool->errOpenPrinter )
  1452. {
  1453. return pSpool->errOpenPrinter;
  1454. }
  1455. else if ( pSpool->hChangeEvent )
  1456. {
  1457. return ERROR_ALREADY_WAITING;
  1458. }
  1459. else if ( !(*pdwFlags & PRINTER_CHANGE_VALID ))
  1460. {
  1461. return ERROR_INVALID_PARAMETER;
  1462. }
  1463. if ( pSpool->nChangeFlags & *pdwFlags )
  1464. {
  1465. //
  1466. // There is a change since we last called
  1467. //
  1468. *pdwFlags &= pSpool->nChangeFlags;
  1469. EnterCriticalSection( &NwPrintCritSec );
  1470. pSpool->nChangeFlags = 0;
  1471. LeaveCriticalSection( &NwPrintCritSec );
  1472. return NO_ERROR;
  1473. }
  1474. hChangeEvent = CreateEvent( NULL,
  1475. FALSE, // automatic reset
  1476. FALSE, // initial state not signalled
  1477. NULL );
  1478. if ( !hChangeEvent )
  1479. {
  1480. KdPrint(("WaitForPrinterChange: CreateEvent failed with error %d\n",
  1481. GetLastError() ));
  1482. return GetLastError();
  1483. }
  1484. pSpool->nWaitFlags = *pdwFlags;
  1485. EnterCriticalSection( &NwPrintCritSec );
  1486. pSpool->hChangeEvent = hChangeEvent;
  1487. pSpool->nChangeFlags = 0;
  1488. LeaveCriticalSection( &NwPrintCritSec );
  1489. ahWaitEvents[0] = pSpool->hChangeEvent;
  1490. ahWaitEvents[1] = NwDoneEvent;
  1491. nRetVal = WaitForMultipleObjects( 2, // Two events to wait for
  1492. ahWaitEvents,
  1493. FALSE, // Wait for one to signal
  1494. NwTimeOutValue );
  1495. switch ( nRetVal )
  1496. {
  1497. case WAIT_FAILED:
  1498. err = GetLastError();
  1499. break;
  1500. case WAIT_TIMEOUT:
  1501. case WAIT_OBJECT_0 + 1: // treats service stopping as timeout
  1502. *pdwFlags |= PRINTER_CHANGE_TIMEOUT;
  1503. break;
  1504. case WAIT_OBJECT_0:
  1505. *pdwFlags &= pSpool->nChangeFlags;
  1506. break;
  1507. default:
  1508. KdPrint(("WaitForPrinterChange: WaitForMultipleObjects returned with %d\n", nRetVal ));
  1509. *pdwFlags |= PRINTER_CHANGE_TIMEOUT;
  1510. break;
  1511. }
  1512. if ( ( !err ) && ( nRetVal != WAIT_OBJECT_0 + 1 ) )
  1513. {
  1514. pSpool->nWaitFlags = 0;
  1515. EnterCriticalSection( &NwPrintCritSec );
  1516. pSpool->nChangeFlags = 0;
  1517. pSpool->hChangeEvent = NULL;
  1518. LeaveCriticalSection( &NwPrintCritSec );
  1519. }
  1520. if ( !CloseHandle( hChangeEvent ) )
  1521. {
  1522. KdPrint(("WaitForPrinterChange: CloseHandle failed with error %d\n",
  1523. GetLastError()));
  1524. }
  1525. return err;
  1526. }
  1527. typedef DWORD (*PRINTPROC)(HWND, HINSTANCE, LPCTSTR, UINT);
  1528. DWORD
  1529. NwrAddPrinterConnection(
  1530. IN LPWSTR Reserved,
  1531. IN LPWSTR pszPrinterName,
  1532. IN LPWSTR pszDriverName
  1533. )
  1534. /*++
  1535. Routine Description: Implements workaround to allow CSNW to support Point and Print
  1536. If PnP is enabled in registry, NwrAddPrinterConnection is called with driver
  1537. name read from NDS Queue object Description attribute in format:
  1538. "PnP Driver:Driver Friendly Name[@\\server\share\driver.inf]".
  1539. If driver inf file is specified it must be a Logo'd PnP driver, and must not
  1540. invoke UI. If not specified, driver name must be from %windir%\inf\ntprint.inf.
  1541. Thie routine purposely runs in the system context, not impersonating the user
  1542. in order to load the printer driver. To maintain administrative control
  1543. the feature requires a registry setting to enable PnP configuration, and
  1544. another key can be set to restrict PnP configuration to using only drivers
  1545. listed in ntprint.inf.
  1546. \\HKLM\System\CurrentControlSet\Control\Print\Providers\NetWare or Conpatible Network
  1547. DWORD Value: EnableUserAddPrinter = 1 enables PnP loading of printer drivers
  1548. ( Default: 0 )
  1549. DWORD Value: RestrictToInboxDrivers = 1 forces loading from ntprint.inf only
  1550. ( Default: 0 )
  1551. Arguments:
  1552. Reserved - RPC Handle not used
  1553. pszPrinterName - NDS Queue object
  1554. pszDriverName - Friendly name of printer driver, with optional driver location
  1555. Return Value:
  1556. --*/
  1557. {
  1558. DWORD err = 0;
  1559. PRINTER_INFO_2W * pPrinterInfo = NULL;
  1560. HANDLE hPrinter = NULL;
  1561. PSECURITY_DESCRIPTOR pSecDesc = NULL;
  1562. PACL pDacl = NULL;
  1563. LPTSTR pszProcessor = L"winprint";
  1564. NWWKSTA_PRINTER_CONTEXT phPrinter = NULL;
  1565. LPBYTE pDest = NULL;
  1566. DWORD dwBytesNeeded = 0;
  1567. BOOL bRet = FALSE;
  1568. LPWSTR pszInfPath = NULL;
  1569. PSID pEveryoneSID = NULL;
  1570. EXPLICIT_ACCESS ea[1];
  1571. SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
  1572. WCHAR szPrintInf[MAX_PATH];
  1573. if (!pszPrinterName || (*pszPrinterName == 0))
  1574. return ERROR_INVALID_PARAMETER;
  1575. if (!pszDriverName || (*pszDriverName == 0))
  1576. return ERROR_INVALID_PARAMETER;
  1577. pszInfPath = wcschr(pszDriverName, L'@');
  1578. if (pszInfPath)
  1579. {
  1580. *pszInfPath = 0;
  1581. pszInfPath++;
  1582. }
  1583. else
  1584. {
  1585. szPrintInf[0] = 0;
  1586. err = GetSystemWindowsDirectory(szPrintInf, MAX_PATH);
  1587. lstrcat(szPrintInf, L"\\inf\\ntprint.inf");
  1588. pszInfPath = szPrintInf;
  1589. }
  1590. #if DBG
  1591. IF_DEBUG(PRINT)
  1592. {
  1593. KdPrint(("NWWKS:AddPrinterConnection - Printer=%ws, driver=%ws from %ws\n", pszPrinterName, pszDriverName, szPrintInf));
  1594. }
  1595. #endif
  1596. // Create a well-known SID for the Everyone group.
  1597. if(! AllocateAndInitializeSid( &SIDAuthWorld, 1,
  1598. SECURITY_WORLD_RID,
  1599. 0, 0, 0, 0, 0, 0, 0,
  1600. &pEveryoneSID) )
  1601. {
  1602. goto Cleanup;
  1603. }
  1604. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  1605. // The ACE will allow Everyone read access to the key.
  1606. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
  1607. ea[0].grfAccessPermissions = PRINTER_ALL_ACCESS;
  1608. ea[0].grfAccessMode = SET_ACCESS;
  1609. ea[0].grfInheritance= OBJECT_INHERIT_ACE;
  1610. ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  1611. ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  1612. ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID;
  1613. // Create a new ACL that contains the new ACE.
  1614. err = SetEntriesInAcl(1, ea, NULL, &pDacl);
  1615. if (ERROR_SUCCESS != err) {
  1616. goto Cleanup;
  1617. }
  1618. // Initialize a security descriptor.
  1619. pSecDesc = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
  1620. SECURITY_DESCRIPTOR_MIN_LENGTH);
  1621. if (pSecDesc == NULL) {
  1622. goto Cleanup;
  1623. }
  1624. if (!InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION)) {
  1625. goto Cleanup;
  1626. }
  1627. // Add the ACL to the security descriptor.
  1628. if (!SetSecurityDescriptorDacl(pSecDesc,
  1629. TRUE, // fDaclPresent flag
  1630. pDacl,
  1631. FALSE)) // not a default DACL
  1632. {
  1633. goto Cleanup;
  1634. }
  1635. dwBytesNeeded = sizeof(PRINTER_INFO_2);
  1636. pPrinterInfo = (PRINTER_INFO_2 *) LocalAlloc(LPTR, dwBytesNeeded);
  1637. if (pPrinterInfo)
  1638. {
  1639. pPrinterInfo->pPrinterName = pszPrinterName;
  1640. pPrinterInfo->pPortName = pPrinterInfo->pPrinterName;
  1641. pPrinterInfo->pDriverName = pszDriverName;
  1642. pPrinterInfo->pPrintProcessor = pszProcessor;
  1643. pPrinterInfo->Attributes = PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL;
  1644. pPrinterInfo->pServerName = NULL;
  1645. pPrinterInfo->pShareName = NULL;
  1646. pPrinterInfo->Status = 0;
  1647. pPrinterInfo->cJobs = 0;
  1648. if (IsValidSecurityDescriptor(pSecDesc))
  1649. {
  1650. pPrinterInfo->pSecurityDescriptor = pSecDesc;
  1651. }
  1652. hPrinter = AddPrinter(NULL, 2, (LPBYTE) pPrinterInfo);
  1653. if (hPrinter == NULL)
  1654. {
  1655. if ( GetLastError() == ERROR_UNKNOWN_PRINTER_DRIVER )
  1656. {
  1657. WCHAR szCmdLine[1024];
  1658. _snwprintf(szCmdLine, sizeof(szCmdLine) / sizeof(WCHAR),
  1659. L"/ia /q /m \"%.200ws\" /h \"Intel\" /v \"Windows 2000 or XP\" /f \"%.768ws\"",
  1660. pPrinterInfo->pDriverName, pszInfPath);
  1661. #if DBG
  1662. IF_DEBUG(PRINT)
  1663. {
  1664. KdPrint(("AddPrinterConnection - attempting to load driver from cab with command\n %ws\n", szCmdLine));
  1665. }
  1666. #endif
  1667. {
  1668. HINSTANCE hPrintDll = LoadLibrary(L"printui.dll");
  1669. PRINTPROC pPrintFunc = NULL;
  1670. if (hPrintDll)
  1671. {
  1672. pPrintFunc = (PRINTPROC) GetProcAddress((HMODULE)hPrintDll, "PrintUIEntryW");
  1673. if (pPrintFunc)
  1674. {
  1675. HINSTANCE hInst = (HINSTANCE) GetModuleHandle(NULL);
  1676. HWND hParentWnd = GetDesktopWindow();
  1677. DWORD nRet = 0;
  1678. nRet = (pPrintFunc) (hParentWnd, hInst, szCmdLine, TRUE);
  1679. hPrinter = AddPrinter(NULL, 2, (LPBYTE) pPrinterInfo);
  1680. }
  1681. FreeLibrary(hPrintDll);
  1682. }
  1683. }
  1684. }
  1685. }
  1686. #if DBG
  1687. IF_DEBUG(PRINT)
  1688. {
  1689. KdPrint(("AddPrinter returned 0x%8.8X\n", hPrinter ));
  1690. }
  1691. #endif
  1692. }
  1693. Cleanup:
  1694. if (pEveryoneSID)
  1695. FreeSid(pEveryoneSID);
  1696. if (pDacl)
  1697. LocalFree(pDacl);
  1698. if (pSecDesc)
  1699. LocalFree(pSecDesc);
  1700. if (hPrinter)
  1701. ClosePrinter(hPrinter);
  1702. if (phPrinter)
  1703. ClosePrinter(phPrinter);
  1704. if (pPrinterInfo)
  1705. LocalFree(pPrinterInfo);
  1706. return (hPrinter) ? ERROR_SUCCESS : ERROR_ACCESS_DENIED;
  1707. }
  1708. VOID
  1709. NwSetPrinterChange(
  1710. PNWSPOOL pSpool,
  1711. DWORD nFlags
  1712. )
  1713. {
  1714. PNWPRINTER pPrinter = pSpool->pPrinter;
  1715. PNWSPOOL pCurSpool = pSpool;
  1716. EnterCriticalSection( &NwPrintCritSec );
  1717. do {
  1718. if ( pCurSpool->nWaitFlags & nFlags )
  1719. {
  1720. pCurSpool->nChangeFlags |= nFlags;
  1721. if ( pCurSpool->hChangeEvent )
  1722. {
  1723. SetEvent( pCurSpool->hChangeEvent );
  1724. pCurSpool->hChangeEvent = NULL;
  1725. }
  1726. }
  1727. pCurSpool = pCurSpool->pNextSpool;
  1728. if ( pCurSpool == NULL )
  1729. pCurSpool = pPrinter->pSpoolList;
  1730. } while ( pCurSpool && (pCurSpool != pSpool) );
  1731. LeaveCriticalSection( &NwPrintCritSec );
  1732. }
  1733. PNWPRINTER
  1734. NwFindPrinterEntry(
  1735. IN LPWSTR pszServer,
  1736. IN LPWSTR pszQueue
  1737. )
  1738. {
  1739. PNWPRINTER pPrinter = NULL;
  1740. //
  1741. // Check to see if we already have the given printer in our printer
  1742. // link list. If yes, return the printer.
  1743. //
  1744. for ( pPrinter = NwPrinterList; pPrinter; pPrinter = pPrinter->pNextPrinter)
  1745. {
  1746. if ( ( lstrcmpiW( pPrinter->pszServer, pszServer ) == 0 )
  1747. && ( lstrcmpiW( pPrinter->pszQueue, pszQueue ) == 0 )
  1748. )
  1749. {
  1750. return pPrinter;
  1751. }
  1752. }
  1753. return NULL;
  1754. }
  1755. DWORD
  1756. NwCreatePrinterEntry(
  1757. IN LPWSTR pszServer,
  1758. IN LPWSTR pszQueue,
  1759. OUT PNWPRINTER *ppPrinter,
  1760. OUT PHANDLE phServer
  1761. )
  1762. {
  1763. DWORD err = NO_ERROR;
  1764. DWORD nQueueId = 0;
  1765. HANDLE TreeHandle = NULL;
  1766. UNICODE_STRING TreeName;
  1767. PNWPRINTER pNwPrinter = NULL;
  1768. BOOL fCreatedNWConnection = FALSE;
  1769. LPWSTR lpRemoteName = NULL;
  1770. DWORD dwBufSize = ( wcslen(pszServer) + wcslen(pszQueue) + 2 )
  1771. * sizeof(WCHAR);
  1772. lpRemoteName = (LPWSTR) AllocNwSplMem( LMEM_ZEROINIT, dwBufSize );
  1773. if ( lpRemoteName == NULL )
  1774. return ERROR_NOT_ENOUGH_MEMORY;
  1775. wcscpy( lpRemoteName, pszServer );
  1776. wcscat( lpRemoteName, L"\\" );
  1777. wcscat( lpRemoteName, pszQueue );
  1778. *ppPrinter = NULL;
  1779. *phServer = NULL;
  1780. //
  1781. // See if we already know about this print queue.
  1782. //
  1783. pNwPrinter = NwFindPrinterEntry( pszServer, pszQueue );
  1784. /* Changing to get queue status to verify access to queue instead
  1785. if ( pNwPrinter == NULL )
  1786. {
  1787. // We don't know about this NetWare print queue. We need to see if
  1788. // we are authorized to use this queue. If so, then go ahead
  1789. // and continue to open printer. Otherwise, fail with not
  1790. // authorized error code.
  1791. err = NwCreateConnection( NULL,
  1792. lpRemoteName,
  1793. RESOURCETYPE_PRINT,
  1794. NULL,
  1795. NULL );
  1796. if ( err != NO_ERROR )
  1797. {
  1798. if ( ( err == ERROR_INVALID_PASSWORD ) ||
  1799. ( err == ERROR_ACCESS_DENIED ) ||
  1800. ( err == ERROR_NO_SUCH_USER ) )
  1801. {
  1802. err = ERROR_ACCESS_DENIED;
  1803. }
  1804. FreeNwSplMem( lpRemoteName, dwBufSize );
  1805. return err;
  1806. }
  1807. fCreatedNWConnection = TRUE;
  1808. }
  1809. */
  1810. //
  1811. // See if pszServer is really a NDS tree name, if so call
  1812. // NwNdsGetQueueInformation to get the QueueId and possible referred
  1813. // server for which we open handle.
  1814. //
  1815. RtlInitUnicodeString( &TreeName, pszServer + 2 );
  1816. err = NwNdsOpenTreeHandle( &TreeName, &TreeHandle );
  1817. if ( err == NO_ERROR )
  1818. {
  1819. NTSTATUS ntstatus;
  1820. WCHAR szRefServer[NDS_MAX_NAME_CHARS];
  1821. UNICODE_STRING ObjectName;
  1822. UNICODE_STRING QueuePath;
  1823. ObjectName.Buffer = szRefServer;
  1824. ObjectName.MaximumLength = NDS_MAX_NAME_CHARS;
  1825. ObjectName.Length = 0;
  1826. RtlInitUnicodeString( &QueuePath, pszQueue );
  1827. ntstatus = NwNdsGetQueueInformation( TreeHandle,
  1828. &QueuePath,
  1829. &ObjectName,
  1830. &nQueueId );
  1831. if ( TreeHandle )
  1832. {
  1833. CloseHandle( TreeHandle );
  1834. TreeHandle = NULL;
  1835. }
  1836. if ( ntstatus )
  1837. {
  1838. err = RtlNtStatusToDosError( ntstatus );
  1839. goto ErrorExit;
  1840. }
  1841. //
  1842. // If we got a referred server, it's name would look like:
  1843. // "CN=SERVER.OU=DEV.O=MICROSOFT" . . . Convert it to "C\\SERVER"
  1844. //
  1845. if ( ObjectName.Length > 0 )
  1846. {
  1847. WORD i;
  1848. LPWSTR EndOfServerName = NULL;
  1849. //
  1850. // First convert the referred server name to
  1851. // "C\\SERVER.OU=DEV.O=MICROSOFT"
  1852. //
  1853. szRefServer[1] = L'\\';
  1854. szRefServer[2] = L'\\';
  1855. //
  1856. // Put a NULL terminator at the first '.'
  1857. //
  1858. EndOfServerName = wcschr( szRefServer + 3, L'.' );
  1859. if (EndOfServerName)
  1860. *EndOfServerName = L'\0';
  1861. //
  1862. // pszServer now equals the referred server "C\\SERVER"
  1863. //
  1864. //
  1865. // Get the handle of the referred server skipping the 'C' character.
  1866. //
  1867. err = NwAttachToNetwareServer( szRefServer + 1, phServer);
  1868. }
  1869. }
  1870. else // Not an NDS tree, so get handle of server.
  1871. {
  1872. err = NwAttachToNetwareServer( pszServer, phServer);
  1873. if ( err == NO_ERROR )
  1874. {
  1875. if ( err = NwGetQueueId( *phServer, pszQueue, &nQueueId))
  1876. err = ERROR_INVALID_NAME;
  1877. }
  1878. }
  1879. if ( ( err == ERROR_INVALID_PASSWORD ) ||
  1880. ( err == ERROR_ACCESS_DENIED ) ||
  1881. ( err == ERROR_NO_SUCH_USER ) )
  1882. {
  1883. err = ERROR_ACCESS_DENIED;
  1884. goto ErrorExit;
  1885. }
  1886. else if ( err != NO_ERROR )
  1887. {
  1888. err = ERROR_INVALID_NAME;
  1889. goto ErrorExit;
  1890. }
  1891. //
  1892. // Test to see if there already was a entry for this print queue. If so,
  1893. // we can now return with NO_ERROR since pNwPrinter and phServer are
  1894. // now set.
  1895. //
  1896. if ( pNwPrinter )
  1897. {
  1898. if ( lpRemoteName )
  1899. {
  1900. FreeNwSplMem( lpRemoteName, dwBufSize );
  1901. }
  1902. *ppPrinter = pNwPrinter;
  1903. return NO_ERROR;
  1904. }
  1905. //
  1906. // The printer entry was not found in our list of printers in the
  1907. // call to NwFindPrinterEntry. So, we must create one.
  1908. //
  1909. // First, verify access rights
  1910. else
  1911. {
  1912. BYTE nQueueStatus;
  1913. BYTE nJobCount;
  1914. err = NwReadQueueCurrentStatus(*phServer, nQueueId, &nQueueStatus, &nJobCount);
  1915. if(err != NO_ERROR)
  1916. {
  1917. err = NwCreateConnection( NULL,
  1918. lpRemoteName,
  1919. RESOURCETYPE_PRINT,
  1920. NULL,
  1921. NULL );
  1922. }
  1923. if ( ( err == ERROR_INVALID_PASSWORD ) ||
  1924. ( err == ERROR_ACCESS_DENIED ) ||
  1925. ( err == ERROR_NO_SUCH_USER ) )
  1926. {
  1927. err = ERROR_ACCESS_DENIED;
  1928. goto ErrorExit;
  1929. }
  1930. else if ( err != NO_ERROR )
  1931. {
  1932. err = ERROR_INVALID_NAME;
  1933. goto ErrorExit;
  1934. }
  1935. }
  1936. if ( *ppPrinter = AllocNwSplMem( LMEM_ZEROINIT, sizeof(NWPRINTER) ))
  1937. {
  1938. if ( !( (*ppPrinter)->pszServer = AllocNwSplStr( pszServer )) )
  1939. {
  1940. err = ERROR_NOT_ENOUGH_MEMORY;
  1941. goto ErrorExit;
  1942. }
  1943. else if ( !( (*ppPrinter)->pszQueue = AllocNwSplStr( pszQueue )))
  1944. {
  1945. err = ERROR_NOT_ENOUGH_MEMORY;
  1946. goto ErrorExit;
  1947. }
  1948. if ( fCreatedNWConnection )
  1949. {
  1950. if ( !( (*ppPrinter)->pszUncConnection =
  1951. AllocNwSplStr( lpRemoteName )) )
  1952. {
  1953. err = ERROR_NOT_ENOUGH_MEMORY;
  1954. goto ErrorExit;
  1955. }
  1956. FreeNwSplMem( lpRemoteName, dwBufSize );
  1957. lpRemoteName = NULL;
  1958. }
  1959. else
  1960. {
  1961. (*ppPrinter)->pszUncConnection = NULL;
  1962. }
  1963. #if DBG
  1964. IF_DEBUG(PRINT)
  1965. {
  1966. KdPrint(("*************CREATED PRINTER ENTRY: %ws\\%ws\n\n",
  1967. (*ppPrinter)->pszServer, (*ppPrinter)->pszQueue ));
  1968. }
  1969. #endif
  1970. (*ppPrinter)->nQueueId = nQueueId;
  1971. (*ppPrinter)->pSpoolList = NULL;
  1972. (*ppPrinter)->pNextPrinter = NwPrinterList;
  1973. NwPrinterList = *ppPrinter;
  1974. err = NO_ERROR;
  1975. }
  1976. else
  1977. {
  1978. err = ERROR_NOT_ENOUGH_MEMORY;
  1979. }
  1980. if ( err == NO_ERROR )
  1981. return err;
  1982. ErrorExit:
  1983. if ( *phServer )
  1984. {
  1985. (VOID) NtClose( *phServer );
  1986. *phServer = NULL;
  1987. }
  1988. if ( *ppPrinter )
  1989. {
  1990. if ( (*ppPrinter)->pszServer )
  1991. {
  1992. FreeNwSplStr( (*ppPrinter)->pszServer );
  1993. }
  1994. if ( (*ppPrinter)->pszQueue )
  1995. {
  1996. FreeNwSplStr( (*ppPrinter)->pszQueue );
  1997. }
  1998. if ( (*ppPrinter)->pszUncConnection )
  1999. {
  2000. (void) NwrDeleteConnection( NULL,
  2001. (*ppPrinter)->pszUncConnection,
  2002. FALSE );
  2003. FreeNwSplStr( (*ppPrinter)->pszUncConnection );
  2004. }
  2005. FreeNwSplMem( *ppPrinter, sizeof( NWPRINTER));
  2006. *ppPrinter = NULL;
  2007. }
  2008. if ( lpRemoteName )
  2009. {
  2010. FreeNwSplMem( lpRemoteName, dwBufSize );
  2011. }
  2012. return err;
  2013. }
  2014. VOID
  2015. NwRemovePrinterEntry(
  2016. IN PNWPRINTER pPrinter
  2017. )
  2018. {
  2019. PNWPRINTER pCur, pPrev = NULL;
  2020. ASSERT( pPrinter->pSpoolList == NULL );
  2021. pPrinter->pSpoolList = NULL;
  2022. for ( pCur = NwPrinterList; pCur; pPrev = pCur, pCur = pCur->pNextPrinter )
  2023. {
  2024. if ( pCur == pPrinter )
  2025. {
  2026. if ( pPrev )
  2027. pPrev->pNextPrinter = pCur->pNextPrinter;
  2028. else
  2029. NwPrinterList = pCur->pNextPrinter;
  2030. break;
  2031. }
  2032. }
  2033. ASSERT( pCur );
  2034. pPrinter->pNextPrinter = NULL;
  2035. FreeNwSplStr( pPrinter->pszServer );
  2036. FreeNwSplStr( pPrinter->pszQueue );
  2037. if ( pPrinter->pszUncConnection )
  2038. {
  2039. (void) NwrDeleteConnection( NULL,
  2040. pPrinter->pszUncConnection,
  2041. FALSE );
  2042. FreeNwSplStr( pPrinter->pszUncConnection );
  2043. }
  2044. FreeNwSplMem( pPrinter, sizeof( NWPRINTER));
  2045. }
  2046. VOID
  2047. NWWKSTA_PRINTER_CONTEXT_rundown(
  2048. IN NWWKSTA_PRINTER_CONTEXT hPrinter
  2049. )
  2050. /*++
  2051. Routine Description:
  2052. This function is called by RPC when a client terminates with an
  2053. opened handle. This allows us to clean up and deallocate any context
  2054. data associated with the handle.
  2055. Arguments:
  2056. hPrinter - Supplies the opened handle
  2057. Return Value:
  2058. None.
  2059. --*/
  2060. {
  2061. (void) NwrClosePrinter(&hPrinter);
  2062. }
  2063. LPWSTR
  2064. NwGetUncObjectName(
  2065. IN LPWSTR ContainerName
  2066. )
  2067. {
  2068. WORD length = 2;
  2069. WORD totalLength = (WORD) wcslen( ContainerName );
  2070. if ( totalLength < 2 )
  2071. return 0;
  2072. while ( length < totalLength )
  2073. {
  2074. if ( ContainerName[length] == L'.' )
  2075. ContainerName[length] = L'\0';
  2076. length++;
  2077. }
  2078. length = 2;
  2079. while ( length < totalLength && ContainerName[length] != L'\\' )
  2080. {
  2081. length++;
  2082. }
  2083. ContainerName[length + 2] = L'\\';
  2084. ContainerName[length + 3] = L'\\';
  2085. return (ContainerName + length + 2);
  2086. }