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.

3441 lines
80 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. nwspl.c
  5. Abstract:
  6. This module contains the Netware print provider.
  7. Author:
  8. Yi-Hsin Sung (yihsins) 15-Apr-1993
  9. Revision History:
  10. Yi-Hsin Sung (yihsins) 15-May-1993
  11. Moved most of the functionality to the server side
  12. Ram Viswanathan (ramv) 09-Aug-1995
  13. Added functionality to Add and Delete Printer.
  14. --*/
  15. #include <stdio.h>
  16. #include <nwclient.h>
  17. #include <winspool.h>
  18. #include <winsplp.h>
  19. #include <ntlsa.h>
  20. #include <nwpkstr.h>
  21. #include <splutil.h>
  22. #include <nwreg.h>
  23. #include <nwspl.h>
  24. #include <nwmisc.h>
  25. #include <winsta.h>
  26. #include <nds.h>
  27. #include <ndsapi32.h>
  28. #include "nwutil.h"
  29. #include <overflow.h>
  30. //------------------------------------------------------------------
  31. //
  32. // Local Functions
  33. //
  34. //------------------------------------------------------------------
  35. // now all SKUs have TerminalServer flag. If App Server is enabled, SingleUserTS flag is cleared
  36. #define IsTerminalServer() (BOOLEAN)(!(USER_SHARED_DATA->SuiteMask & (1 << SingleUserTS))) //user mode
  37. DWORD
  38. InitializePortNames(
  39. VOID
  40. );
  41. VOID
  42. NwpGetUserInfo(
  43. LPWSTR *ppszUser
  44. );
  45. DWORD
  46. NwpGetThreadUserInfo(
  47. LPWSTR *ppszUser,
  48. LPWSTR *ppszUserSid
  49. );
  50. DWORD
  51. NwpGetUserNameFromSid(
  52. PSID pUserSid,
  53. LPWSTR *ppszUserName
  54. );
  55. DWORD
  56. NwpGetLogonUserInfo(
  57. LPWSTR *ppszUserSid
  58. );
  59. DWORD
  60. ThreadIsInteractive(
  61. VOID
  62. );
  63. VOID
  64. pFreeAllContexts();
  65. //------------------------------------------------------------------
  66. //
  67. // Global Variables
  68. //
  69. //------------------------------------------------------------------
  70. HMODULE hmodNW = NULL;
  71. BOOL fIsWinnt = FALSE ;
  72. BOOL bEnableAddPrinterConnection = FALSE;
  73. BOOL bRestrictToInboxDrivers = FALSE;
  74. BOOL bNeedAddPrinterConnCleanup = FALSE;
  75. WCHAR *pszRegistryPath = NULL;
  76. WCHAR *pszRegistryPortNames=L"PortNames";
  77. WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH + 3];
  78. PNWPORT pNwFirstPort = NULL;
  79. CRITICAL_SECTION NwSplSem;
  80. CRITICAL_SECTION NwServiceListCriticalSection; // Used to protect linked
  81. // list of registered services
  82. HANDLE NwServiceListDoneEvent = NULL;// Used to stop local advertise
  83. // threads.
  84. STATIC HANDLE handleDummy; // This is a dummy handle used to
  85. // return to the clients if we have previously
  86. // opened the given printer successfully
  87. // and the netware workstation service is not
  88. // currently available.
  89. STATIC
  90. PRINTPROVIDOR PrintProvidor = { OpenPrinter,
  91. SetJob,
  92. GetJob,
  93. EnumJobs,
  94. AddPrinter, // NOT SUPPORTED
  95. DeletePrinter, // NOT SUPPORTED
  96. SetPrinter,
  97. GetPrinter,
  98. EnumPrinters,
  99. AddPrinterDriver, // NOT SUPPORTED
  100. EnumPrinterDrivers, // NOT SUPPORTED
  101. GetPrinterDriverW, // NOT SUPPORTED
  102. GetPrinterDriverDirectory, // NOT SUPPORTED
  103. DeletePrinterDriver, // NOT SUPPORTED
  104. AddPrintProcessor, // NOT SUPPORTED
  105. EnumPrintProcessors, // NOT SUPPORTED
  106. GetPrintProcessorDirectory, // NOT SUPPORTED
  107. DeletePrintProcessor, // NOT SUPPORTED
  108. EnumPrintProcessorDatatypes,// NOT SUPPORTED
  109. StartDocPrinter,
  110. StartPagePrinter, // NOT SUPPORTED
  111. WritePrinter,
  112. EndPagePrinter, // NOT SUPPORTED
  113. AbortPrinter,
  114. ReadPrinter, // NOT SUPPORTED
  115. EndDocPrinter,
  116. AddJob,
  117. ScheduleJob,
  118. GetPrinterData, // NOT SUPPORTED
  119. SetPrinterData, // NOT SUPPORTED
  120. WaitForPrinterChange,
  121. ClosePrinter,
  122. AddForm, // NOT SUPPORTED
  123. DeleteForm, // NOT SUPPORTED
  124. GetForm, // NOT SUPPORTED
  125. SetForm, // NOT SUPPORTED
  126. EnumForms, // NOT SUPPORTED
  127. EnumMonitors, // NOT SUPPORTED
  128. EnumPorts,
  129. AddPort, // NOT SUPPORTED
  130. ConfigurePort,
  131. DeletePort,
  132. CreatePrinterIC, // NOT SUPPORTED
  133. PlayGdiScriptOnPrinterIC, // NOT SUPPORTED
  134. DeletePrinterIC, // NOT SUPPORTED
  135. AddPrinterConnection,
  136. DeletePrinterConnection, // NOT SUPPORTED
  137. PrinterMessageBox, // NOT SUPPORTED
  138. AddMonitor, // NOT SUPPORTED
  139. DeleteMonitor // NOT SUPPORTED
  140. };
  141. //------------------------------------------------------------------
  142. //
  143. // Initialization Functions
  144. //
  145. //------------------------------------------------------------------
  146. BOOL InitializeDll(
  147. HINSTANCE hdll,
  148. DWORD dwReason,
  149. LPVOID lpReserved
  150. )
  151. {
  152. NT_PRODUCT_TYPE ProductType ;
  153. UNREFERENCED_PARAMETER( lpReserved );
  154. if ( dwReason == DLL_PROCESS_ATTACH )
  155. {
  156. DisableThreadLibraryCalls( hdll );
  157. hmodNW = hdll;
  158. //
  159. // are we a winnt machine?
  160. //
  161. fIsWinnt = RtlGetNtProductType(&ProductType) ?
  162. (ProductType == NtProductWinNt) :
  163. FALSE ;
  164. //
  165. // Initialize the critical section for maintaining the registered
  166. // service list
  167. //
  168. InitializeCriticalSection( &NwServiceListCriticalSection );
  169. NwServiceListDoneEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
  170. }
  171. else if ( dwReason == DLL_PROCESS_DETACH )
  172. {
  173. //
  174. // Free up memories used by the port link list
  175. //
  176. DeleteAllPortEntries();
  177. //
  178. // Get rid of Service List and Shutdown SAP library
  179. //
  180. NwTerminateServiceProvider();
  181. #ifndef NT1057
  182. //
  183. // Clean up shell extensions
  184. //
  185. NwCleanupShellExtensions();
  186. #endif
  187. pFreeAllContexts(); // clean up RNR stuff
  188. DeleteCriticalSection( &NwServiceListCriticalSection );
  189. if ( NwServiceListDoneEvent )
  190. {
  191. CloseHandle( NwServiceListDoneEvent );
  192. NwServiceListDoneEvent = NULL;
  193. }
  194. }
  195. return TRUE;
  196. }
  197. DWORD
  198. InitializePortNames(
  199. VOID
  200. )
  201. /*++
  202. Routine Description:
  203. This is called by the InitializePrintProvidor to initialize the ports
  204. names used in this providor.
  205. Arguments:
  206. None.
  207. Return Value:
  208. Returns NO_ERROR or the error that occurred.
  209. --*/
  210. {
  211. DWORD err;
  212. HKEY hkeyPath;
  213. HKEY hkeyPortNames;
  214. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  215. pszRegistryPath,
  216. 0,
  217. KEY_READ,
  218. &hkeyPath );
  219. if ( !err )
  220. {
  221. DWORD BytesNeeded = sizeof( BOOL );
  222. err = RegQueryValueExW( hkeyPath,
  223. L"EnableUserAddPrinter",
  224. NULL,
  225. NULL,
  226. (LPBYTE) &bEnableAddPrinterConnection,
  227. &BytesNeeded );
  228. if ( err ) // just default to not allowed
  229. bEnableAddPrinterConnection = FALSE;
  230. err = RegQueryValueExW( hkeyPath,
  231. L"RestrictToInboxDrivers",
  232. NULL,
  233. NULL,
  234. (LPBYTE) &bRestrictToInboxDrivers,
  235. &BytesNeeded );
  236. if ( err ) // just default to not restricted
  237. bRestrictToInboxDrivers = FALSE;
  238. err = RegOpenKeyEx( hkeyPath,
  239. pszRegistryPortNames,
  240. 0,
  241. KEY_READ,
  242. &hkeyPortNames );
  243. if ( !err )
  244. {
  245. DWORD i = 0;
  246. WCHAR Buffer[MAX_PATH];
  247. DWORD BufferSize;
  248. while ( !err )
  249. {
  250. BufferSize = sizeof(Buffer) / sizeof(WCHAR);
  251. err = RegEnumValue( hkeyPortNames,
  252. i,
  253. Buffer,
  254. &BufferSize,
  255. NULL,
  256. NULL,
  257. NULL,
  258. NULL );
  259. if ( !err )
  260. CreatePortEntry( Buffer );
  261. i++;
  262. }
  263. /* We expect RegEnumKeyEx to return ERROR_NO_MORE_ITEMS
  264. * when it gets to the end of the keys, so reset the status:
  265. */
  266. if( err == ERROR_NO_MORE_ITEMS )
  267. err = NO_ERROR;
  268. RegCloseKey( hkeyPortNames );
  269. }
  270. #if DBG
  271. else
  272. {
  273. IF_DEBUG(PRINT)
  274. KdPrint(("NWSPL [RegOpenKeyEx] (%ws) failed: Error = %d\n",
  275. pszRegistryPortNames, err ));
  276. }
  277. #endif
  278. RegCloseKey( hkeyPath );
  279. }
  280. #if DBG
  281. else
  282. {
  283. IF_DEBUG(PRINT)
  284. KdPrint(("NWSPL [RegOpenKeyEx] (%ws) failed: Error = %d\n",
  285. pszRegistryPath, err ));
  286. }
  287. #endif
  288. return err;
  289. }
  290. //------------------------------------------------------------------
  291. //
  292. // Print Provider Functions supported by NetWare provider
  293. //
  294. //------------------------------------------------------------------
  295. BOOL
  296. InitializePrintProvidor(
  297. LPPRINTPROVIDOR pPrintProvidor,
  298. DWORD cbPrintProvidor,
  299. LPWSTR pszFullRegistryPath
  300. )
  301. /*++
  302. Routine Description:
  303. This is called by the spooler subsystem to initialize the print
  304. providor.
  305. Arguments:
  306. pPrintProvidor - Pointer to the print providor structure to be
  307. filled in by this function
  308. cbPrintProvidor - Count of bytes of the print providor structure
  309. pszFullRegistryPath - Full path to the registry key of this print providor
  310. Return Value:
  311. Always TRUE.
  312. --*/
  313. {
  314. //
  315. // dfergus 20 Apr 2001 #323700
  316. // Prevent Multiple CS Initialization
  317. //
  318. static int iCSInit = 0;
  319. DWORD dwLen;
  320. if ( !pPrintProvidor || !pszFullRegistryPath || !*pszFullRegistryPath )
  321. {
  322. SetLastError( ERROR_INVALID_PARAMETER );
  323. return FALSE;
  324. }
  325. memcpy( pPrintProvidor,
  326. &PrintProvidor,
  327. min( sizeof(PRINTPROVIDOR), cbPrintProvidor) );
  328. //
  329. // Store the registry path for this print providor
  330. //
  331. if ( !(pszRegistryPath = AllocNwSplStr(pszFullRegistryPath)) )
  332. return FALSE;
  333. //
  334. // Store the local machine name
  335. //
  336. szMachineName[0] = szMachineName[1] = L'\\';
  337. dwLen = MAX_COMPUTERNAME_LENGTH;
  338. GetComputerName( szMachineName + 2, &dwLen );
  339. #if DBG
  340. IF_DEBUG(PRINT)
  341. {
  342. KdPrint(("NWSPL [InitializePrintProvidor] "));
  343. KdPrint(("RegistryPath = %ws, ComputerName = %ws\n",
  344. pszRegistryPath, szMachineName ));
  345. }
  346. #endif
  347. //
  348. // dfergus 20 Apr 2001 #323700
  349. // Prevent Multiple CS Initialization
  350. //
  351. if( !iCSInit )
  352. {
  353. InitializeCriticalSection( &NwSplSem );
  354. iCSInit = 1;
  355. }
  356. //
  357. // Ignore the error returned from InitializePortNames.
  358. // The provider can still function if we cannot get all the port
  359. // names.
  360. //
  361. InitializePortNames();
  362. return TRUE;
  363. }
  364. BOOL
  365. OpenPrinterW(
  366. LPWSTR pszPrinterName,
  367. LPHANDLE phPrinter,
  368. LPPRINTER_DEFAULTS pDefault
  369. )
  370. /*++
  371. Routine Description:
  372. This routine retrieves a handle identifying the specified printer.
  373. Arguments:
  374. pszPrinterName - Name of the printer
  375. phPrinter - Receives the handle that identifies the given printer
  376. pDefault - Points to a PRINTER_DEFAULTS structure. Can be NULL.
  377. Return Value:
  378. TRUE if the function succeeds, FALSE otherwise. Use GetLastError() for
  379. extended error information.
  380. --*/
  381. {
  382. DWORD err;
  383. #if DBG
  384. IF_DEBUG(PRINT)
  385. KdPrint(( "NWSPL [OpenPrinter] Name = %ws\n", pszPrinterName ));
  386. #endif
  387. UNREFERENCED_PARAMETER( pDefault );
  388. if ( !pszPrinterName )
  389. {
  390. SetLastError( ERROR_INVALID_NAME );
  391. return FALSE;
  392. }
  393. RpcTryExcept
  394. {
  395. err = NwrOpenPrinter( NULL,
  396. pszPrinterName,
  397. PortKnown( pszPrinterName ),
  398. (LPNWWKSTA_PRINTER_CONTEXT) phPrinter );
  399. //
  400. // Make sure there is a port of this name so that
  401. // EnumPorts will return it.
  402. //
  403. if ( !err )
  404. {
  405. if ( !PortExists( pszPrinterName, &err ) && !err )
  406. {
  407. //
  408. // We will ignore the errors since it is
  409. // still OK if we can't add the port.
  410. // Cannot delete once created, don't create
  411. // We should not create port entry and registry entry
  412. if ( CreatePortEntry( pszPrinterName ) )
  413. CreateRegistryEntry( pszPrinterName );
  414. }
  415. }
  416. }
  417. RpcExcept(1)
  418. {
  419. DWORD code = RpcExceptionCode();
  420. if ( code == RPC_S_SERVER_UNAVAILABLE )
  421. {
  422. if ( PortKnown( pszPrinterName ))
  423. {
  424. *phPrinter = &handleDummy;
  425. err = NO_ERROR;
  426. }
  427. else
  428. {
  429. err = ERROR_INVALID_NAME;
  430. }
  431. }
  432. else
  433. {
  434. err = NwpMapRpcError( code );
  435. }
  436. }
  437. RpcEndExcept
  438. if ( err )
  439. {
  440. SetLastError( err );
  441. #if DBG
  442. IF_DEBUG(PRINT)
  443. KdPrint(("NWSPL [OpenPrinter] err = %d\n", err));
  444. #endif
  445. }
  446. return ( err == NO_ERROR );
  447. }
  448. BOOL
  449. ClosePrinter(
  450. HANDLE hPrinter
  451. )
  452. /*++
  453. Routine Description:
  454. This routine closes the given printer object.
  455. Arguments:
  456. hPrinter - Handle of the printer object
  457. Return Value:
  458. TRUE if the function succeeds, FALSE otherwise. Use GetLastError() for
  459. extended error information.
  460. --*/
  461. {
  462. DWORD err;
  463. #if DBG
  464. IF_DEBUG(PRINT)
  465. KdPrint(( "NWSPL [ClosePrinter]\n"));
  466. #endif
  467. //
  468. // Just return success if the handle is a dummy one
  469. //
  470. if ( hPrinter == &handleDummy )
  471. return TRUE;
  472. // Clean up any registry stuff left behind by AddPrinterConnection
  473. if ( bEnableAddPrinterConnection
  474. && bNeedAddPrinterConnCleanup )
  475. {
  476. DWORD err;
  477. HKEY hkey;
  478. HKEY hSubKey;
  479. WCHAR * szConnKey = L"Printers\\Connections";
  480. #if DBG
  481. IF_DEBUG(PRINT)
  482. {
  483. KdPrint(("Cleaning up registry key %ws ...\n", szConnKey ));
  484. }
  485. #endif
  486. err = RegOpenCurrentUser( KEY_ALL_ACCESS, &hkey );
  487. if ( err == ERROR_SUCCESS )
  488. {
  489. err = RegOpenKeyExW( hkey, szConnKey, 0, KEY_ALL_ACCESS, &hSubKey );
  490. if ( err == ERROR_SUCCESS )
  491. {
  492. WCHAR szKeyName[256];
  493. DWORD dwIndex = 0;
  494. DWORD dwSize;
  495. FILETIME keyModTime;
  496. HKEY hConnKey;
  497. WCHAR szProvider[64];
  498. dwSize = 256;
  499. err = RegEnumKeyEx(hSubKey, dwIndex,
  500. szKeyName, &dwSize, NULL, NULL, NULL, &keyModTime);
  501. while (!err)
  502. {
  503. dwIndex++;
  504. err = RegOpenKeyExW( hSubKey, szKeyName,
  505. 0, KEY_ALL_ACCESS, &hConnKey);
  506. if (err)
  507. break;
  508. dwSize = 64 * sizeof(WCHAR);
  509. err = RegQueryValueExW(hConnKey, L"Provider", NULL,
  510. NULL, (LPBYTE) szProvider, &dwSize);
  511. if (err)
  512. szProvider[0] = 0;
  513. if (lstrcmpi(szProvider, L"nwprovau.dll") == 0)
  514. {
  515. RegDeleteValueW( hConnKey, L"Provider" );
  516. RegDeleteValueW( hConnKey, L"Server" );
  517. RegCloseKey(hConnKey);
  518. err = RegDeleteKeyW(hSubKey, szKeyName);
  519. if (err == ERROR_SUCCESS)
  520. bNeedAddPrinterConnCleanup = FALSE;
  521. #if DBG
  522. IF_DEBUG(PRINT)
  523. {
  524. if (err == ERROR_SUCCESS)
  525. KdPrint((" Deleted %ws\n", szKeyName));
  526. }
  527. #endif
  528. }
  529. else
  530. RegCloseKey(hConnKey);
  531. dwSize = 256;
  532. err = RegEnumKeyEx(hSubKey, dwIndex,
  533. szKeyName, &dwSize, NULL, NULL, NULL, &keyModTime);
  534. }
  535. RegCloseKey( hSubKey );
  536. }
  537. RegCloseKey( hkey );
  538. }
  539. }
  540. RpcTryExcept
  541. {
  542. err = NwrClosePrinter( (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter );
  543. }
  544. RpcExcept(1)
  545. {
  546. DWORD code = RpcExceptionCode();
  547. if ( code == RPC_S_SERVER_UNAVAILABLE )
  548. err = ERROR_INVALID_HANDLE;
  549. else
  550. err = NwpMapRpcError( code );
  551. }
  552. RpcEndExcept
  553. if ( err )
  554. SetLastError( err );
  555. return err == NO_ERROR;
  556. }
  557. BOOL
  558. GetPrinter(
  559. HANDLE hPrinter,
  560. DWORD dwLevel,
  561. LPBYTE pbPrinter,
  562. DWORD cbBuf,
  563. LPDWORD pcbNeeded
  564. )
  565. /*++
  566. Routine Description:
  567. The routine retrieves information about the given printer.
  568. Arguments:
  569. hPrinter - Handle of the printer
  570. dwLevel - Specifies the level of the structure to which pbPrinter points.
  571. pbPrinter - Points to a buffer that receives the PRINTER_INFO object.
  572. cbBuf - Size, in bytes of the array pbPrinter points to.
  573. pcbNeeded - Points to a value which specifies the number of bytes copied
  574. if the function succeeds or the number of bytes required if
  575. cbBuf was too small.
  576. Return Value:
  577. TRUE if the function succeeds and FALSE otherwise. GetLastError() can be
  578. used to retrieve extended error information.
  579. --*/
  580. {
  581. DWORD err;
  582. #if DBG
  583. IF_DEBUG(PRINT)
  584. KdPrint(( "NWSPL [GetPrinter] Level = %d\n", dwLevel ));
  585. #endif
  586. if ( hPrinter == &handleDummy )
  587. {
  588. SetLastError( ERROR_NO_NETWORK );
  589. return FALSE;
  590. }
  591. else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) && (dwLevel != 3 ))
  592. {
  593. SetLastError( ERROR_INVALID_LEVEL );
  594. return FALSE;
  595. }
  596. RpcTryExcept
  597. {
  598. err = NwrGetPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  599. dwLevel,
  600. pbPrinter,
  601. cbBuf,
  602. pcbNeeded );
  603. if ( !err )
  604. {
  605. if ( dwLevel == 1 )
  606. MarshallUpStructure( pbPrinter, PrinterInfo1Offsets, pbPrinter);
  607. else
  608. MarshallUpStructure( pbPrinter, PrinterInfo2Offsets, pbPrinter);
  609. }
  610. }
  611. RpcExcept(1)
  612. {
  613. DWORD code = RpcExceptionCode();
  614. if ( code == RPC_S_SERVER_UNAVAILABLE )
  615. err = ERROR_INVALID_HANDLE;
  616. else
  617. err = NwpMapRpcError( code );
  618. }
  619. RpcEndExcept
  620. if ( err )
  621. SetLastError( err );
  622. return err == NO_ERROR;
  623. }
  624. BOOL
  625. SetPrinter(
  626. HANDLE hPrinter,
  627. DWORD dwLevel,
  628. LPBYTE pbPrinter,
  629. DWORD dwCommand
  630. )
  631. /*++
  632. Routine Description:
  633. The routine sets the specified by pausing printing, resuming printing, or
  634. clearing all print jobs.
  635. Arguments:
  636. hPrinter - Handle of the printer
  637. dwLevel - Specifies the level of the structure to which pbPrinter points.
  638. pbPrinter - Points to a buffer that supplies the PRINTER_INFO object.
  639. dwCommand - Specifies the new printer state.
  640. Return Value:
  641. TRUE if the function succeeds and FALSE otherwise. GetLastError() can be
  642. used to retrieve extended error information.
  643. --*/
  644. {
  645. DWORD err = NO_ERROR;
  646. UNREFERENCED_PARAMETER( pbPrinter );
  647. #if DBG
  648. IF_DEBUG(PRINT)
  649. {
  650. KdPrint(( "NWSPL [SetPrinter] Level = %d Command = %d\n",
  651. dwLevel, dwCommand ));
  652. }
  653. #endif
  654. if ( hPrinter == &handleDummy )
  655. {
  656. SetLastError( ERROR_NO_NETWORK );
  657. return FALSE;
  658. }
  659. switch ( dwLevel )
  660. {
  661. case 0:
  662. case 1:
  663. case 2:
  664. case 3:
  665. break;
  666. default:
  667. SetLastError( ERROR_INVALID_LEVEL );
  668. return FALSE;
  669. }
  670. RpcTryExcept
  671. {
  672. err = NwrSetPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  673. dwCommand );
  674. }
  675. RpcExcept(1)
  676. {
  677. DWORD code = RpcExceptionCode();
  678. if ( code == RPC_S_SERVER_UNAVAILABLE )
  679. err = ERROR_INVALID_HANDLE;
  680. else
  681. err = NwpMapRpcError( code );
  682. }
  683. RpcEndExcept
  684. if ( err )
  685. SetLastError( err );
  686. return err == NO_ERROR;
  687. }
  688. BOOL
  689. EnumPrintersW(
  690. DWORD dwFlags,
  691. LPWSTR pszName,
  692. DWORD dwLevel,
  693. LPBYTE pbPrinter,
  694. DWORD cbBuf,
  695. LPDWORD pcbNeeded,
  696. LPDWORD pcReturned
  697. )
  698. /*++
  699. Routine Description:
  700. This routine enumerates the available providers, servers, printers
  701. depending on the given pszName.
  702. Arguments:
  703. dwFlags - Printer type requested
  704. pszName - The name of the container object
  705. dwLevel - The structure level requested
  706. pbPrinter - Points to the array to receive the PRINTER_INFO objects
  707. cbBuf - Size, in bytes of pbPrinter
  708. pcbNeeded - Count of bytes needed
  709. pcReturned - Count of PRINTER_INFO objects
  710. Return Value:
  711. TRUE if the function succeeds, FALSE otherwise.
  712. --*/
  713. {
  714. DWORD err = NO_ERROR;
  715. #if DBG
  716. IF_DEBUG(PRINT)
  717. {
  718. KdPrint(("NWSPL [EnumPrinters] Flags = %d Level = %d",dwFlags,dwLevel));
  719. if ( pszName )
  720. KdPrint((" PrinterName = %ws\n", pszName ));
  721. else
  722. KdPrint(("\n"));
  723. }
  724. #endif
  725. if ( (dwLevel != 1) && (dwLevel != 2) )
  726. {
  727. SetLastError( ERROR_INVALID_NAME ); // should be level, but winspool
  728. // is silly.
  729. return FALSE;
  730. }
  731. else if ( !pcbNeeded || !pcReturned )
  732. {
  733. SetLastError( ERROR_INVALID_PARAMETER );
  734. return FALSE;
  735. }
  736. RpcTryExcept
  737. {
  738. *pcReturned = 0;
  739. *pcbNeeded = 0;
  740. if ( ( dwFlags & PRINTER_ENUM_NAME )
  741. && ( dwLevel == 1 )
  742. )
  743. {
  744. err = NwrEnumPrinters( NULL,
  745. pszName,
  746. pbPrinter,
  747. cbBuf,
  748. pcbNeeded,
  749. pcReturned );
  750. if ( !err )
  751. {
  752. DWORD i;
  753. for ( i = 0; i < *pcReturned; i++ )
  754. MarshallUpStructure( pbPrinter + i*sizeof(PRINTER_INFO_1W),
  755. PrinterInfo1Offsets,
  756. pbPrinter );
  757. }
  758. }
  759. else
  760. {
  761. err = ERROR_INVALID_NAME;
  762. }
  763. }
  764. RpcExcept(1)
  765. {
  766. DWORD code = RpcExceptionCode();
  767. if ( code == RPC_S_SERVER_UNAVAILABLE )
  768. err = ERROR_INVALID_NAME;
  769. else
  770. err = NwpMapRpcError( code );
  771. }
  772. RpcEndExcept
  773. if ( err )
  774. SetLastError( err );
  775. return err == NO_ERROR;
  776. }
  777. //
  778. // Handle structure
  779. // This structure was copied from \nw\svcdlls\nwwks\server\spool.c
  780. // to fix NT bug # 366632.
  781. //
  782. typedef struct _NWSPOOL {
  783. DWORD nSignature; // Signature
  784. DWORD errOpenPrinter; // OpenPrinter API will always return
  785. // success on known printers. This will
  786. // contain the error that we get
  787. // if something went wrong in the API.
  788. PVOID pPrinter; // Points to the corresponding printer
  789. HANDLE hServer; // Opened handle to the server
  790. struct _NWSPOOL *pNextSpool; // Points to the next handle
  791. DWORD nStatus; // Status
  792. DWORD nJobNumber; // StartDocPrinter/AddJob: Job Number
  793. HANDLE hChangeEvent; // WaitForPrinterChange: event to wait on
  794. DWORD nWaitFlags; // WaitForPrinterChange: flags to wait on
  795. DWORD nChangeFlags; // Changes that occurred to the printer
  796. } NWSPOOL, *PNWSPOOL;
  797. DWORD
  798. StartDocPrinter(
  799. HANDLE hPrinter,
  800. DWORD dwLevel,
  801. LPBYTE lpbDocInfo
  802. )
  803. /*++
  804. Routine Description:
  805. This routine informs the print spooler that a document is to be spooled
  806. for printing.
  807. Arguments:
  808. hPrinter - Handle of the printer
  809. dwLevel - Level of the structure pointed to by lpbDocInfo. Must be 1.
  810. lpbDocInfo - Points to the DOC_INFO_1 object
  811. Return Value:
  812. TRUE if the function succeeds, FALSE otherwise. The extended error
  813. can be retrieved through GetLastError().
  814. --*/
  815. {
  816. DWORD err;
  817. DOC_INFO_1 *pDocInfo1 = (DOC_INFO_1 *) lpbDocInfo;
  818. LPWSTR pszUser = NULL;
  819. DWORD PrintOption = NW_PRINT_OPTION_DEFAULT;
  820. LPWSTR pszPreferredSrv = NULL;
  821. #if DBG
  822. IF_DEBUG(PRINT)
  823. {
  824. KdPrint(( "NWSPL [StartDocPrinter] " ));
  825. if ( pDocInfo1 )
  826. {
  827. if ( pDocInfo1->pDocName )
  828. KdPrint(("Document %ws", pDocInfo1->pDocName ));
  829. if ( pDocInfo1->pOutputFile )
  830. KdPrint(("OutputFile %ws", pDocInfo1->pOutputFile ));
  831. if ( pDocInfo1->pDatatype )
  832. KdPrint(("Datatype %ws", pDocInfo1->pDatatype ));
  833. }
  834. KdPrint(("\n"));
  835. }
  836. #endif
  837. if ( hPrinter == &handleDummy )
  838. {
  839. SetLastError( ERROR_NO_NETWORK );
  840. return FALSE;
  841. }
  842. else if ( dwLevel != 1 )
  843. {
  844. SetLastError( ERROR_INVALID_PARAMETER );
  845. return FALSE;
  846. }
  847. // ignore the error, just use default value
  848. NwpGetUserInfo( &pszUser );
  849. NwQueryInfo( &PrintOption, &pszPreferredSrv );
  850. if (pszPreferredSrv) {
  851. LocalFree( pszPreferredSrv );
  852. }
  853. RpcTryExcept
  854. {
  855. err = NwrStartDocPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  856. pDocInfo1? pDocInfo1->pDocName : NULL,
  857. pszUser, PrintOption);
  858. }
  859. RpcExcept(1)
  860. {
  861. DWORD code = RpcExceptionCode();
  862. if ( code == RPC_S_SERVER_UNAVAILABLE )
  863. err = ERROR_INVALID_HANDLE;
  864. else
  865. err = NwpMapRpcError( code );
  866. }
  867. RpcEndExcept
  868. LocalFree( pszUser );
  869. if ( err )
  870. SetLastError( err );
  871. //
  872. // Can't do this, seems to break GSWN printing on multi-homed machines
  873. // Commenting out code change that tries to return the job id.
  874. //
  875. // else
  876. // return ((PNWSPOOL) hPrinter)->nJobNumber;
  877. return err == NO_ERROR;
  878. }
  879. BOOL
  880. WritePrinter(
  881. HANDLE hPrinter,
  882. LPVOID pBuf,
  883. DWORD cbBuf,
  884. LPDWORD pcbWritten
  885. )
  886. /*++
  887. Routine Description:
  888. This routine informs the print spooler that the specified data should be
  889. written to the given printer.
  890. Arguments:
  891. hPrinter - Handle of the printer object
  892. pBuf - Address of array that contains printer data
  893. cbBuf - Size, in bytes of pBuf
  894. pcbWritten - Receives the number of bytes actually written to the printer
  895. Return Value:
  896. TRUE if it succeeds, FALSE otherwise. Use GetLastError() to get extended
  897. error.
  898. --*/
  899. {
  900. DWORD err;
  901. #if DBG
  902. IF_DEBUG(PRINT)
  903. KdPrint(( "NWSPL [WritePrinter]\n"));
  904. if ( hPrinter == &handleDummy )
  905. {
  906. SetLastError( ERROR_NO_NETWORK );
  907. return FALSE;
  908. }
  909. #endif
  910. RpcTryExcept
  911. {
  912. err = NwrWritePrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  913. pBuf,
  914. cbBuf,
  915. pcbWritten );
  916. }
  917. RpcExcept(1)
  918. {
  919. DWORD code = RpcExceptionCode();
  920. if ( code == RPC_S_SERVER_UNAVAILABLE )
  921. err = ERROR_INVALID_HANDLE;
  922. else
  923. err = NwpMapRpcError( code );
  924. }
  925. RpcEndExcept
  926. if ( err )
  927. SetLastError( err );
  928. return err == NO_ERROR;
  929. }
  930. BOOL
  931. AbortPrinter(
  932. HANDLE hPrinter
  933. )
  934. /*++
  935. Routine Description:
  936. This routine deletes a printer's spool file if the printer is configured
  937. for spooling.
  938. Arguments:
  939. hPrinter - Handle of the printer object
  940. Return Value:
  941. TRUE if the function succeeds, FALSE otherwise.
  942. --*/
  943. {
  944. DWORD err;
  945. #if DBG
  946. IF_DEBUG(PRINT)
  947. KdPrint(( "NWSPL [AbortPrinter]\n"));
  948. if ( hPrinter == &handleDummy )
  949. {
  950. SetLastError( ERROR_NO_NETWORK );
  951. return FALSE;
  952. }
  953. #endif
  954. RpcTryExcept
  955. {
  956. err = NwrAbortPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter );
  957. }
  958. RpcExcept(1)
  959. {
  960. DWORD code = RpcExceptionCode();
  961. if ( code == RPC_S_SERVER_UNAVAILABLE )
  962. err = ERROR_INVALID_HANDLE;
  963. else
  964. err = NwpMapRpcError( code );
  965. }
  966. RpcEndExcept
  967. if ( err )
  968. SetLastError( err );
  969. return err == NO_ERROR;
  970. }
  971. BOOL
  972. EndDocPrinter(
  973. HANDLE hPrinter
  974. )
  975. /*++
  976. Routine Description:
  977. This routine ends the print job for the given printer.
  978. Arguments:
  979. hPrinter - Handle of the printer object
  980. Return Value:
  981. TRUE if the function succeeds, FALSE otherwise.
  982. --*/
  983. {
  984. DWORD err;
  985. #if DBG
  986. IF_DEBUG(PRINT)
  987. KdPrint(( "NWSPL [EndDocPrinter]\n"));
  988. #endif
  989. if ( hPrinter == &handleDummy )
  990. {
  991. SetLastError( ERROR_NO_NETWORK );
  992. return FALSE;
  993. }
  994. RpcTryExcept
  995. {
  996. err = NwrEndDocPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter );
  997. }
  998. RpcExcept(1)
  999. {
  1000. DWORD code = RpcExceptionCode();
  1001. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1002. err = ERROR_INVALID_HANDLE;
  1003. else
  1004. err = NwpMapRpcError( code );
  1005. }
  1006. RpcEndExcept
  1007. if ( err )
  1008. SetLastError( err );
  1009. return err == NO_ERROR;
  1010. }
  1011. BOOL
  1012. GetJob(
  1013. HANDLE hPrinter,
  1014. DWORD dwJobId,
  1015. DWORD dwLevel,
  1016. LPBYTE pbJob,
  1017. DWORD cbBuf,
  1018. LPDWORD pcbNeeded
  1019. )
  1020. /*++
  1021. Routine Description:
  1022. This routine retrieves print-job data for the given printer.
  1023. Arguments:
  1024. hPrinter - Handle of the printer
  1025. dwJobId - Job identifition number
  1026. dwLevel - Data structure level of pbJob
  1027. pbJob - Address of data-structure array
  1028. cbBuf - Count of bytes in array
  1029. pcbNeeded - Count of bytes retrieved or required
  1030. Return Value:
  1031. TRUE if the function succeeds, FALSE otherwise.
  1032. --*/
  1033. {
  1034. DWORD err;
  1035. #if DBG
  1036. IF_DEBUG(PRINT)
  1037. KdPrint(("NWSPL [GetJob] JobId = %d Level = %d\n", dwJobId, dwLevel));
  1038. #endif
  1039. if ( hPrinter == &handleDummy )
  1040. {
  1041. SetLastError( ERROR_NO_NETWORK );
  1042. return FALSE;
  1043. }
  1044. else if (( dwLevel != 1 ) && ( dwLevel != 2 ))
  1045. {
  1046. SetLastError( ERROR_INVALID_LEVEL );
  1047. return FALSE;
  1048. }
  1049. RpcTryExcept
  1050. {
  1051. err = NwrGetJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1052. dwJobId,
  1053. dwLevel,
  1054. pbJob,
  1055. cbBuf,
  1056. pcbNeeded );
  1057. if ( !err )
  1058. {
  1059. if ( dwLevel == 1 )
  1060. MarshallUpStructure( pbJob, JobInfo1Offsets, pbJob );
  1061. else
  1062. MarshallUpStructure( pbJob, JobInfo2Offsets, pbJob );
  1063. }
  1064. }
  1065. RpcExcept(1)
  1066. {
  1067. DWORD code = RpcExceptionCode();
  1068. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1069. err = ERROR_INVALID_HANDLE;
  1070. else
  1071. err = NwpMapRpcError( code );
  1072. }
  1073. RpcEndExcept
  1074. if ( err )
  1075. SetLastError( err );
  1076. return err == NO_ERROR;
  1077. }
  1078. BOOL
  1079. EnumJobs(
  1080. HANDLE hPrinter,
  1081. DWORD dwFirstJob,
  1082. DWORD dwNoJobs,
  1083. DWORD dwLevel,
  1084. LPBYTE pbJob,
  1085. DWORD cbBuf,
  1086. LPDWORD pcbNeeded,
  1087. LPDWORD pcReturned
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. This routine initializes the array of JOB_INFO_1 or JOB_INFO_2 structures
  1092. with data describing the specified print jobs for the given printer.
  1093. Arguments:
  1094. hPrinter - Handle of the printer
  1095. dwFirstJob - Location of first job in the printer
  1096. dwNoJobs - Number of jobs to enumerate
  1097. dwLevel - Data structure level
  1098. pbJob - Address of structure array
  1099. cbBuf - Size of pbJob, in bytes
  1100. pcbNeeded - Receives the number of bytes copied or required
  1101. pcReturned - Receives the number of jobs copied
  1102. Return Value:
  1103. TRUE if the function succeeds, FALSE otherwise.
  1104. --*/
  1105. {
  1106. DWORD err;
  1107. #if DBG
  1108. IF_DEBUG(PRINT)
  1109. KdPrint(("NWSPL [EnumJobs] Level = %d FirstJob = %d NoJobs = %d\n",
  1110. dwLevel, dwFirstJob, dwNoJobs));
  1111. #endif
  1112. if ( hPrinter == &handleDummy )
  1113. {
  1114. SetLastError( ERROR_NO_NETWORK );
  1115. return FALSE;
  1116. }
  1117. else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) )
  1118. {
  1119. SetLastError( ERROR_INVALID_LEVEL );
  1120. return FALSE;
  1121. }
  1122. RpcTryExcept
  1123. {
  1124. *pcReturned = 0;
  1125. *pcbNeeded = 0;
  1126. err = NwrEnumJobs( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1127. dwFirstJob,
  1128. dwNoJobs,
  1129. dwLevel,
  1130. pbJob,
  1131. cbBuf,
  1132. pcbNeeded,
  1133. pcReturned );
  1134. if ( !err )
  1135. {
  1136. DWORD i;
  1137. DWORD cbStruct;
  1138. DWORD_PTR *pOffsets;
  1139. if ( dwLevel == 1 )
  1140. {
  1141. cbStruct = sizeof( JOB_INFO_1W );
  1142. pOffsets = JobInfo1Offsets;
  1143. }
  1144. else // dwLevel == 2
  1145. {
  1146. cbStruct = sizeof( JOB_INFO_2W );
  1147. pOffsets = JobInfo2Offsets;
  1148. }
  1149. for ( i = 0; i < *pcReturned; i++ )
  1150. MarshallUpStructure( pbJob + i * cbStruct, pOffsets, pbJob );
  1151. }
  1152. }
  1153. RpcExcept(1)
  1154. {
  1155. DWORD code = RpcExceptionCode();
  1156. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1157. err = ERROR_INVALID_HANDLE;
  1158. else
  1159. err = NwpMapRpcError( code );
  1160. }
  1161. RpcEndExcept
  1162. if ( err )
  1163. SetLastError( err );
  1164. return err == NO_ERROR;
  1165. }
  1166. BOOL
  1167. SetJob(
  1168. HANDLE hPrinter,
  1169. DWORD dwJobId,
  1170. DWORD dwLevel,
  1171. LPBYTE pbJob,
  1172. DWORD dwCommand
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. This routine pauses, cancels, resumes, restarts the specified print job
  1177. in the given printer. The function can also be used to set print job
  1178. parameters such as job position, and so on.
  1179. Arguments:
  1180. hPrinter - Handle of the printer
  1181. dwJobId - Job indentification number
  1182. dwLevel - Data structure level
  1183. pbJob - Address of data structure
  1184. dwCommand - Specify the operation to be performed
  1185. Return Value:
  1186. TRUE if the function succeeds, FALSE otherwise.
  1187. --*/
  1188. {
  1189. DWORD err;
  1190. #if DBG
  1191. IF_DEBUG(PRINT)
  1192. {
  1193. KdPrint(("NWSPL [SetJob] Level = %d JobId = %d Command = %d\n",
  1194. dwLevel, dwJobId, dwCommand));
  1195. }
  1196. #endif
  1197. if ( hPrinter == &handleDummy )
  1198. {
  1199. SetLastError( ERROR_NO_NETWORK );
  1200. return FALSE;
  1201. }
  1202. else if ( ( dwLevel != 0 ) && ( dwLevel != 1 ) && ( dwLevel != 2 ) )
  1203. {
  1204. SetLastError( ERROR_INVALID_LEVEL );
  1205. return FALSE;
  1206. }
  1207. else if ( ( dwLevel == 0 ) && ( pbJob != NULL ) )
  1208. {
  1209. SetLastError( ERROR_INVALID_PARAMETER );
  1210. return FALSE;
  1211. }
  1212. RpcTryExcept
  1213. {
  1214. NW_JOB_INFO NwJobInfo;
  1215. if ( dwLevel == 1 )
  1216. {
  1217. NwJobInfo.nPosition = ((LPJOB_INFO_1W) pbJob)->Position;
  1218. NwJobInfo.pUserName = ((LPJOB_INFO_1W) pbJob)->pUserName;
  1219. NwJobInfo.pDocument = ((LPJOB_INFO_1W) pbJob)->pDocument;
  1220. }
  1221. else if ( dwLevel == 2 )
  1222. {
  1223. NwJobInfo.nPosition = ((LPJOB_INFO_2W) pbJob)->Position;
  1224. NwJobInfo.pUserName = ((LPJOB_INFO_2W) pbJob)->pUserName;
  1225. NwJobInfo.pDocument = ((LPJOB_INFO_2W) pbJob)->pDocument;
  1226. }
  1227. err = NwrSetJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1228. dwJobId,
  1229. dwLevel,
  1230. dwLevel == 0 ? NULL : &NwJobInfo,
  1231. dwCommand );
  1232. }
  1233. RpcExcept(1)
  1234. {
  1235. DWORD code = RpcExceptionCode();
  1236. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1237. err = ERROR_INVALID_HANDLE;
  1238. else
  1239. err = NwpMapRpcError( code );
  1240. }
  1241. RpcEndExcept
  1242. if ( err )
  1243. SetLastError( err );
  1244. return err == NO_ERROR;
  1245. }
  1246. BOOL
  1247. AddJob(
  1248. HANDLE hPrinter,
  1249. DWORD dwLevel,
  1250. LPBYTE pbAddJob,
  1251. DWORD cbBuf,
  1252. LPDWORD pcbNeeded
  1253. )
  1254. /*++
  1255. Routine Description:
  1256. This routine returns a full path and filename of a file that can be used
  1257. to store a print job.
  1258. Arguments:
  1259. hPrinter - Handle of the printer
  1260. dwLevel - Data structure level
  1261. pbAddJob - Points to a ADD_INFO_1 structure
  1262. cbBuf - Size of pbAddJob, in bytes
  1263. pcbNeeded - Receives the bytes copied or required
  1264. Return Value:
  1265. TRUE if the function succeeds, FALSE otherwise.
  1266. --*/
  1267. {
  1268. DWORD err;
  1269. ADDJOB_INFO_1W TempBuffer;
  1270. PADDJOB_INFO_1W OutputBuffer;
  1271. DWORD OutputBufferSize;
  1272. #if DBG
  1273. IF_DEBUG(PRINT)
  1274. KdPrint(( "NWSPL [AddJob]\n"));
  1275. #endif
  1276. if ( hPrinter == &handleDummy )
  1277. {
  1278. SetLastError( ERROR_NO_NETWORK );
  1279. return FALSE;
  1280. }
  1281. else if ( dwLevel != 1 )
  1282. {
  1283. SetLastError( ERROR_INVALID_PARAMETER );
  1284. return FALSE;
  1285. }
  1286. //
  1287. // The output buffer size must be at least the size of the fixed
  1288. // portion of the structure marshalled by RPC or RPC will not
  1289. // call the server-side to get the pcbNeeded. Use our own temporary
  1290. // buffer to force RPC to call the server-side if output buffer
  1291. // specified by the caller is too small.
  1292. //
  1293. if (cbBuf < sizeof(ADDJOB_INFO_1W)) {
  1294. OutputBuffer = &TempBuffer;
  1295. OutputBufferSize = sizeof(ADDJOB_INFO_1W);
  1296. }
  1297. else {
  1298. OutputBuffer = (LPADDJOB_INFO_1W) pbAddJob;
  1299. OutputBufferSize = cbBuf;
  1300. }
  1301. RpcTryExcept
  1302. {
  1303. err = NwrAddJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1304. OutputBuffer,
  1305. OutputBufferSize,
  1306. pcbNeeded );
  1307. }
  1308. RpcExcept(1)
  1309. {
  1310. DWORD code = RpcExceptionCode();
  1311. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1312. err = ERROR_INVALID_HANDLE;
  1313. else
  1314. err = NwpMapRpcError( code );
  1315. }
  1316. RpcEndExcept
  1317. if ( err )
  1318. SetLastError( err );
  1319. return err == NO_ERROR;
  1320. }
  1321. BOOL
  1322. ScheduleJob(
  1323. HANDLE hPrinter,
  1324. DWORD dwJobId
  1325. )
  1326. /*++
  1327. Routine Description:
  1328. This routine informs the print spooler that the specified job can be
  1329. scheduled for spooling.
  1330. Arguments:
  1331. hPrinter - Handle of the printer
  1332. dwJobId - Job number that can be scheduled
  1333. Return Value:
  1334. TRUE if the function succeeds, FALSE otherwise.
  1335. --*/
  1336. {
  1337. DWORD err;
  1338. #if DBG
  1339. IF_DEBUG(PRINT)
  1340. KdPrint(( "NWSPL [ScheduleJob] JobId = %d\n", dwJobId ));
  1341. #endif
  1342. if ( hPrinter == &handleDummy )
  1343. {
  1344. SetLastError( ERROR_NO_NETWORK );
  1345. return FALSE;
  1346. }
  1347. RpcTryExcept
  1348. {
  1349. err = NwrScheduleJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1350. dwJobId );
  1351. }
  1352. RpcExcept(1)
  1353. {
  1354. DWORD code = RpcExceptionCode();
  1355. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1356. err = ERROR_INVALID_HANDLE;
  1357. else
  1358. err = NwpMapRpcError( code );
  1359. }
  1360. RpcEndExcept
  1361. if ( err )
  1362. SetLastError( err );
  1363. return err == NO_ERROR;
  1364. }
  1365. DWORD
  1366. WaitForPrinterChange(
  1367. HANDLE hPrinter,
  1368. DWORD dwFlags
  1369. )
  1370. /*++
  1371. Routine Description:
  1372. This function returns when one or more requested changes occur on a
  1373. print server or if the function times out.
  1374. Arguments:
  1375. hPrinter - Handle of the printer to wait on
  1376. dwFlags - A bitmask that specifies the changes that the application
  1377. wishes to be notified of.
  1378. Return Value:
  1379. Return a bitmask that indicates the changes that occurred.
  1380. --*/
  1381. {
  1382. DWORD err;
  1383. #if DBG
  1384. IF_DEBUG(PRINT)
  1385. KdPrint(("NWSPL [WaitForPrinterChange] Flags = %d\n", dwFlags));
  1386. #endif
  1387. if ( hPrinter == &handleDummy )
  1388. {
  1389. SetLastError( ERROR_NO_NETWORK );
  1390. return 0;
  1391. }
  1392. RpcTryExcept
  1393. {
  1394. err = NwrWaitForPrinterChange( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1395. &dwFlags );
  1396. }
  1397. RpcExcept(1)
  1398. {
  1399. DWORD code = RpcExceptionCode();
  1400. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1401. err = ERROR_INVALID_HANDLE;
  1402. else
  1403. err = NwpMapRpcError( code );
  1404. }
  1405. RpcEndExcept
  1406. if ( err )
  1407. {
  1408. SetLastError( err );
  1409. return 0;
  1410. }
  1411. return dwFlags;
  1412. }
  1413. BOOL
  1414. EnumPortsW(
  1415. LPWSTR pszName,
  1416. DWORD dwLevel,
  1417. LPBYTE pbPort,
  1418. DWORD cbBuf,
  1419. LPDWORD pcbNeeded,
  1420. LPDWORD pcReturned
  1421. )
  1422. /*++
  1423. Routine Description:
  1424. This function enumerates the ports available for printing on a
  1425. specified server.
  1426. Arguments:
  1427. pszName - Name of the server to enumerate on
  1428. dwLevel - Structure level
  1429. pbPort - Address of array to receive the port information
  1430. cbBuf - Size, in bytes, of pbPort
  1431. pcbNeeded - Address to store the number of bytes needed or copied
  1432. pcReturned - Address to store the number of entries copied
  1433. Return Value:
  1434. TRUE if the function succeeds, FALSE otherwise.
  1435. --*/
  1436. {
  1437. DWORD err = NO_ERROR;
  1438. DWORD cb = 0;
  1439. PNWPORT pNwPort;
  1440. LPPORT_INFO_1W pPortInfo1;
  1441. LPBYTE pEnd = pbPort + cbBuf;
  1442. LPBYTE pFixedDataEnd = pbPort;
  1443. BOOL FitInBuffer;
  1444. #if DBG
  1445. IF_DEBUG(PRINT)
  1446. KdPrint(("NWSPL [EnumPorts]\n"));
  1447. #endif
  1448. if ( dwLevel != 1 )
  1449. {
  1450. SetLastError( ERROR_INVALID_NAME );
  1451. return FALSE;
  1452. }
  1453. else if ( !IsLocalMachine( pszName ) )
  1454. {
  1455. SetLastError( ERROR_INVALID_NAME );
  1456. return FALSE;
  1457. }
  1458. EnterCriticalSection( &NwSplSem );
  1459. pNwPort = pNwFirstPort;
  1460. while ( pNwPort )
  1461. {
  1462. cb += sizeof(PORT_INFO_1W) + ( wcslen( pNwPort->pName)+1)*sizeof(WCHAR);
  1463. pNwPort = pNwPort->pNext;
  1464. }
  1465. *pcbNeeded = cb;
  1466. *pcReturned = 0;
  1467. if ( cb <= cbBuf )
  1468. {
  1469. pEnd = pbPort + cbBuf;
  1470. pNwPort = pNwFirstPort;
  1471. while ( pNwPort )
  1472. {
  1473. pPortInfo1 = (LPPORT_INFO_1W) pFixedDataEnd;
  1474. pFixedDataEnd += sizeof( PORT_INFO_1W );
  1475. FitInBuffer = NwlibCopyStringToBuffer( pNwPort->pName,
  1476. wcslen( pNwPort->pName),
  1477. (LPCWSTR) pFixedDataEnd,
  1478. (LPWSTR *) &pEnd,
  1479. &pPortInfo1->pName );
  1480. ASSERT( FitInBuffer );
  1481. pNwPort = pNwPort->pNext;
  1482. (*pcReturned)++;
  1483. }
  1484. }
  1485. else
  1486. {
  1487. err = ERROR_INSUFFICIENT_BUFFER;
  1488. }
  1489. LeaveCriticalSection( &NwSplSem );
  1490. if ( err )
  1491. SetLastError( err );
  1492. return err == NO_ERROR;
  1493. }
  1494. BOOL
  1495. DeletePortW(
  1496. LPWSTR pszName,
  1497. HWND hWnd,
  1498. LPWSTR pszPortName
  1499. )
  1500. /*++
  1501. Routine Description:
  1502. This routine deletes the port given on the server. A dialog can
  1503. be displayed if needed.
  1504. Arguments:
  1505. pszName - Name of the server for which the port should be deleted
  1506. hWnd - Parent window
  1507. pszPortName - The name of the port to delete
  1508. Return Value:
  1509. TRUE if the function succeeds, FALSE otherwise.
  1510. --*/
  1511. {
  1512. DWORD err;
  1513. BOOL fPortDeleted;
  1514. #if DBG
  1515. IF_DEBUG(PRINT)
  1516. KdPrint(("NWSPL [DeletePort]\n"));
  1517. #endif
  1518. if ( !IsLocalMachine( pszName ) )
  1519. {
  1520. SetLastError( ERROR_NOT_SUPPORTED );
  1521. return FALSE;
  1522. }
  1523. fPortDeleted = DeletePortEntry( pszPortName );
  1524. if ( fPortDeleted )
  1525. {
  1526. err = DeleteRegistryEntry( pszPortName );
  1527. }
  1528. else
  1529. {
  1530. err = ERROR_UNKNOWN_PORT;
  1531. }
  1532. if ( err )
  1533. SetLastError( err );
  1534. return err == NO_ERROR;
  1535. }
  1536. BOOL
  1537. ConfigurePortW(
  1538. LPWSTR pszName,
  1539. HWND hWnd,
  1540. LPWSTR pszPortName
  1541. )
  1542. /*++
  1543. Routine Description:
  1544. This routine displays the port configuration dialog box
  1545. for the given port on the given server.
  1546. Arguments:
  1547. pszName - Name of the server on which the given port exist
  1548. hWnd - Parent window
  1549. pszPortName - The name of the port to be configured
  1550. Return Value:
  1551. TRUE if the function succeeds, FALSE otherwise.
  1552. --*/
  1553. {
  1554. DWORD nCurrentThreadId;
  1555. DWORD nWindowThreadId;
  1556. WCHAR szCaption[MAX_PATH];
  1557. WCHAR szMessage[MAX_PATH];
  1558. #if DBG
  1559. IF_DEBUG(PRINT)
  1560. KdPrint(("NWSPL [ConfigurePort] PortName = %ws\n", pszPortName));
  1561. #endif
  1562. if ( !IsLocalMachine( pszName ) )
  1563. {
  1564. SetLastError( ERROR_NOT_SUPPORTED );
  1565. return FALSE;
  1566. }
  1567. else if ( !PortKnown( pszPortName ) )
  1568. {
  1569. SetLastError( ERROR_UNKNOWN_PORT );
  1570. return FALSE;
  1571. }
  1572. nCurrentThreadId = GetCurrentThreadId();
  1573. nWindowThreadId = GetWindowThreadProcessId( hWnd, NULL );
  1574. if ( !AttachThreadInput( nCurrentThreadId, nWindowThreadId, TRUE ))
  1575. KdPrint(("[NWSPL] AttachThreadInput failed with %d.\n",GetLastError()));
  1576. if ( LoadStringW( hmodNW,
  1577. IDS_NETWARE_PRINT_CAPTION,
  1578. szCaption,
  1579. sizeof( szCaption ) / sizeof( WCHAR )))
  1580. {
  1581. if ( LoadStringW( hmodNW,
  1582. IDS_NOTHING_TO_CONFIGURE,
  1583. szMessage,
  1584. sizeof( szMessage ) / sizeof( WCHAR )))
  1585. {
  1586. MessageBox( hWnd, szMessage, szCaption,
  1587. MB_OK | MB_ICONINFORMATION );
  1588. }
  1589. else
  1590. {
  1591. KdPrint(("[NWSPL] LoadString failed with %d.\n",GetLastError()));
  1592. }
  1593. }
  1594. else
  1595. {
  1596. KdPrint(("[NWSPL] LoadString failed with %d.\n",GetLastError()));
  1597. }
  1598. if ( !AttachThreadInput( nCurrentThreadId, nWindowThreadId, FALSE ))
  1599. KdPrint(("[NWSPL] DetachThreadInput failed with %d.\n",GetLastError()));
  1600. return TRUE;
  1601. }
  1602. BOOL
  1603. AddPrinterConnectionW(
  1604. LPWSTR pszPrinterName
  1605. )
  1606. {
  1607. DWORD err=0;
  1608. LPHANDLE phPrinter = NULL;
  1609. LPPRINTER_DEFAULTS pDefault = NULL;
  1610. LPTSTR pszDriverPrefix = L"PnP Driver:";
  1611. HANDLE hTreeConn = NULL;
  1612. BYTE RawResponse[4096];
  1613. DWORD RawResponseSize = sizeof(RawResponse);
  1614. LPWSTR pszDescription = NULL;
  1615. LPWSTR pszCurrPtr = NULL;
  1616. BOOL bValidString = FALSE;
  1617. #if DBG
  1618. IF_DEBUG(PRINT)
  1619. {
  1620. KdPrint(("NWSPL [AddPrinterConnection] PrinterName = %ws\n",
  1621. pszPrinterName));
  1622. }
  1623. #endif
  1624. if ( !pszPrinterName )
  1625. {
  1626. SetLastError( ERROR_INVALID_NAME );
  1627. return FALSE;
  1628. }
  1629. // check registry for permission to add printers
  1630. if ( !bEnableAddPrinterConnection )
  1631. {
  1632. SetLastError( ERROR_ACCESS_DENIED );
  1633. return FALSE;
  1634. }
  1635. else
  1636. {
  1637. // Read first value of Description attribute for "PnP Driver:Driver Name"
  1638. DWORD dwOid;
  1639. NTSTATUS ntstatus = STATUS_SUCCESS;
  1640. LPBYTE pObjectClass = RawResponse;
  1641. DWORD iterHandle = (DWORD) -1;
  1642. UNICODE_STRING uAttrName;
  1643. PNDS_RESPONSE_READ_ATTRIBUTE pReadAttrResponse = (PNDS_RESPONSE_READ_ATTRIBUTE) RawResponse;
  1644. PNDS_ATTRIBUTE pNdsAttribute = NULL;
  1645. err = NwOpenAndGetTreeInfo( pszPrinterName,
  1646. &hTreeConn,
  1647. &dwOid );
  1648. if ( err != NO_ERROR )
  1649. {
  1650. goto NDSExit;
  1651. }
  1652. RtlInitUnicodeString( &uAttrName, L"Description");
  1653. ntstatus = NwNdsReadAttribute( hTreeConn,
  1654. dwOid,
  1655. &iterHandle,
  1656. &uAttrName,
  1657. RawResponse,
  1658. sizeof(RawResponse));
  1659. if ( !NT_SUCCESS( ntstatus )
  1660. || ( pReadAttrResponse->CompletionCode != 0 )
  1661. || ( pReadAttrResponse->NumAttributes == 0 )
  1662. )
  1663. {
  1664. // we don't need to set the error since this attribute might be empty and
  1665. // we might get an error indicating this.
  1666. goto NDSExit;
  1667. }
  1668. pNdsAttribute = (PNDS_ATTRIBUTE)((DWORD_PTR) RawResponse+sizeof(NDS_RESPONSE_READ_ATTRIBUTE));
  1669. pszDescription = (LPWSTR) ((DWORD_PTR) pNdsAttribute + 3*sizeof(DWORD)
  1670. + pNdsAttribute->AttribNameLength + sizeof(DWORD));
  1671. // NOTE: we only look at the first value
  1672. }
  1673. NDSExit:
  1674. if ( hTreeConn )
  1675. CloseHandle( hTreeConn );
  1676. if ( (pszDescription == NULL) || (*pszDescription == 0) )
  1677. {
  1678. SetLastError( ERROR_ACCESS_DENIED );
  1679. return FALSE;
  1680. }
  1681. // make sure Description is NULL terminated
  1682. pszCurrPtr = pszDescription;
  1683. while (pszCurrPtr < (WCHAR *)(RawResponse + RawResponseSize))
  1684. {
  1685. if (*pszCurrPtr == 0)
  1686. {
  1687. bValidString = TRUE;
  1688. break;
  1689. }
  1690. pszCurrPtr++;
  1691. }
  1692. if (!bValidString)
  1693. {
  1694. SetLastError( ERROR_ACCESS_DENIED );
  1695. return FALSE;
  1696. }
  1697. #if DBG
  1698. IF_DEBUG(PRINT)
  1699. {
  1700. KdPrint(("NWSPL [AddPrinterConnection] description=%ws\n", pszDescription));
  1701. }
  1702. #endif
  1703. if ( _wcsnicmp ( pszDriverPrefix, pszDescription, wcslen(pszDriverPrefix)) != 0 )
  1704. {
  1705. SetLastError( ERROR_ACCESS_DENIED );
  1706. return FALSE;
  1707. }
  1708. pszDescription += wcslen(pszDriverPrefix);
  1709. if ( bRestrictToInboxDrivers )
  1710. {
  1711. LPWSTR pszSeparator = wcschr( pszDescription, L'@' );
  1712. if ( pszSeparator )
  1713. *pszSeparator = 0;
  1714. }
  1715. RpcTryExcept
  1716. {
  1717. err = NwrAddPrinterConnection(NULL, pszPrinterName, pszDescription);
  1718. }
  1719. RpcExcept(1)
  1720. {
  1721. DWORD code = RpcExceptionCode();
  1722. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1723. {
  1724. err = ERROR_INVALID_NAME;
  1725. }
  1726. else
  1727. {
  1728. err = NwpMapRpcError( code );
  1729. }
  1730. }
  1731. RpcEndExcept
  1732. if ( err )
  1733. {
  1734. SetLastError( err );
  1735. #if DBG
  1736. IF_DEBUG(PRINT)
  1737. KdPrint(("NWSPL [AddPrinterConnection] err = %d\n", err));
  1738. #endif
  1739. return FALSE;
  1740. }
  1741. bNeedAddPrinterConnCleanup = TRUE;
  1742. return TRUE;
  1743. }
  1744. //------------------------------------------------------------------
  1745. //
  1746. // Print Provider Functions not supported by NetWare provider
  1747. //
  1748. //------------------------------------------------------------------
  1749. BOOL
  1750. EnumMonitorsW(
  1751. LPWSTR pszName,
  1752. DWORD dwLevel,
  1753. LPBYTE pbMonitor,
  1754. DWORD cbBuf,
  1755. LPDWORD pcbNeeded,
  1756. LPDWORD pcReturned
  1757. )
  1758. {
  1759. #if DBG
  1760. IF_DEBUG(PRINT)
  1761. KdPrint(("NWSPL [EnumMonitors]\n"));
  1762. #endif
  1763. SetLastError( ERROR_INVALID_NAME );
  1764. return FALSE;
  1765. }
  1766. BOOL
  1767. AddPortW(
  1768. LPWSTR pszName,
  1769. HWND hWnd,
  1770. LPWSTR pszMonitorName
  1771. )
  1772. {
  1773. #if DBG
  1774. IF_DEBUG(PRINT)
  1775. KdPrint(("NWSPL [AddPort]\n"));
  1776. #endif
  1777. SetLastError( ERROR_NOT_SUPPORTED );
  1778. return FALSE;
  1779. }
  1780. HANDLE
  1781. AddPrinterW(
  1782. LPWSTR pszName,
  1783. DWORD dwLevel,
  1784. LPBYTE pbPrinter
  1785. )
  1786. // Creates a print queue on the netware server and returns a handle to it
  1787. {
  1788. #ifdef NOT_USED
  1789. #if DBG
  1790. IF_DEBUG(PRINT)
  1791. KdPrint(("NWSPL [AddPrinterW]\n"));
  1792. #endif
  1793. SetLastError(ERROR_NOT_SUPPORTED);
  1794. return FALSE;
  1795. #else
  1796. LPTSTR pszPrinterName = NULL;
  1797. LPTSTR pszPServer = NULL;
  1798. LPTSTR pszQueue = NULL;
  1799. HANDLE hPrinter = NULL;
  1800. DWORD err;
  1801. PPRINTER_INFO_2 pPrinterInfo;
  1802. #if DBG
  1803. IF_DEBUG(PRINT)
  1804. KdPrint(("NWSPL [AddPrinterW]\n"));
  1805. #endif
  1806. pPrinterInfo = (PPRINTER_INFO_2)pbPrinter;
  1807. if (dwLevel != 2)
  1808. {
  1809. err = ERROR_INVALID_PARAMETER;
  1810. goto ErrorExit;
  1811. }
  1812. if (!(pszPrinterName = (LPTSTR)LocalAlloc(LPTR, (wcslen(((PRINTER_INFO_2 *)pbPrinter)->pPrinterName)+1)* sizeof(WCHAR))))
  1813. {
  1814. err = ERROR_NOT_ENOUGH_MEMORY;
  1815. goto ErrorExit;
  1816. }
  1817. wcscpy(pszPrinterName,pPrinterInfo->pPrinterName);
  1818. // PrinterName is the name represented as \\server\share
  1819. //The pszPServer parameter could have multiple fields separated by semicolons
  1820. if ( ( !ValidateUNCName( pszPrinterName ) )
  1821. || ( (pszQueue = wcschr( pszPrinterName + 2, L'\\')) == NULL )
  1822. || ( pszQueue == (pszPrinterName + 2) )
  1823. || ( *(pszQueue + 1) == L'\0' )
  1824. )
  1825. {
  1826. err = ERROR_INVALID_NAME;
  1827. goto ErrorExit;
  1828. }
  1829. #if DBG
  1830. IF_DEBUG(PRINT)
  1831. KdPrint(( "NWSPL [AddPrinter] Name = %ws\n",pszPServer));
  1832. #endif
  1833. if ( pszPrinterName == NULL )
  1834. //PrinterName is a mandatory field but not the list of PServers
  1835. {
  1836. #if DBG
  1837. IF_DEBUG(PRINT)
  1838. KdPrint(( "NWSPL [AddPrinter] Printername not supplied\n" ));
  1839. #endif
  1840. SetLastError( ERROR_INVALID_NAME );
  1841. goto ErrorExit;
  1842. }
  1843. //Check to see if there is a port of the same name
  1844. // If so, abort the addprinter operation.
  1845. // This code was commented earlier
  1846. if (PortExists(pszPrinterName, &err ) && !err )
  1847. {
  1848. #if DBG
  1849. IF_DEBUG(PRINT)
  1850. KdPrint(( "NWSPL [AddPrinter], = %ws; Port exists with same name\n", pszPrinterName ));
  1851. #endif
  1852. SetLastError(ERROR_ALREADY_ASSIGNED);
  1853. goto ErrorExit;
  1854. }
  1855. // Put all the relevant information into the PRINTER_INFO_2 structure
  1856. RpcTryExcept
  1857. {
  1858. err = NwrAddPrinter ( NULL,
  1859. (LPPRINTER_INFO_2W) pPrinterInfo,
  1860. (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter
  1861. );
  1862. if (!err)
  1863. {
  1864. #if DBG
  1865. IF_DEBUG(PRINT)
  1866. KdPrint(( "NWSPL [AddPrinter] Name = %ws\n", pszPrinterName ));
  1867. #endif
  1868. goto ErrorExit;
  1869. }
  1870. }
  1871. RpcExcept(1)
  1872. {
  1873. DWORD code = RpcExceptionCode();
  1874. err = NwpMapRpcError( code );
  1875. goto ErrorExit;
  1876. }
  1877. RpcEndExcept
  1878. if ( !pszPrinterName)
  1879. (void) LocalFree((HLOCAL)pszPrinterName);
  1880. return hPrinter;
  1881. ErrorExit:
  1882. if ( !pszPrinterName)
  1883. (void) LocalFree((HLOCAL)pszPrinterName);
  1884. SetLastError( err);
  1885. return (HANDLE)0x0;
  1886. #endif // #ifdef NOT_USED
  1887. }
  1888. BOOL
  1889. DeletePrinter(
  1890. HANDLE hPrinter
  1891. )
  1892. {
  1893. #ifdef NOT_USED
  1894. #if DBG
  1895. IF_DEBUG(PRINT)
  1896. KdPrint(("NWSPL [DeletePrinter]\n"));
  1897. #endif
  1898. SetLastError(ERROR_NOT_SUPPORTED);
  1899. return FALSE;
  1900. #else
  1901. LPWSTR pszPrinterName = NULL ; // Used to delete entry from registry
  1902. DWORD err = NO_ERROR;
  1903. DWORD DoesPortExist;
  1904. #if DBG
  1905. IF_DEBUG(PRINT)
  1906. KdPrint(("NWSPL [DeletePrinter]\n"));
  1907. #endif
  1908. pszPrinterName = (LPWSTR)LocalAlloc(LPTR,sizeof(WCHAR)*MAX_PATH);
  1909. if(pszPrinterName == NULL)
  1910. {
  1911. err = ERROR_NOT_ENOUGH_MEMORY;
  1912. return FALSE;
  1913. }
  1914. //
  1915. // Just return success if the handle is a dummy one
  1916. //
  1917. if ( hPrinter == &handleDummy )
  1918. {
  1919. #if DBG
  1920. IF_DEBUG(PRINT)
  1921. KdPrint(("NWSPL [DeletePrinter] Dummy handle \n"));
  1922. #endif
  1923. SetLastError(ERROR_NO_NETWORK);
  1924. return FALSE;
  1925. }
  1926. RpcTryExcept
  1927. {
  1928. err = NwrDeletePrinter( NULL,
  1929. // pszPrinterName,
  1930. (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter );
  1931. }
  1932. RpcExcept(1)
  1933. {
  1934. DWORD code = RpcExceptionCode();
  1935. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1936. err = ERROR_INVALID_HANDLE;
  1937. else
  1938. err = NwpMapRpcError( code );
  1939. }
  1940. RpcEndExcept
  1941. if (!err && PortExists(pszPrinterName, &DoesPortExist) && DoesPortExist)
  1942. {
  1943. if ( DeleteRegistryEntry (pszPrinterName))
  1944. (void) DeletePortEntry(pszPrinterName);
  1945. }
  1946. if ( err )
  1947. SetLastError( err );
  1948. return err == NO_ERROR;
  1949. #endif // #ifdef NOT_USED
  1950. }
  1951. BOOL
  1952. DeletePrinterConnectionW(
  1953. LPWSTR pszName
  1954. )
  1955. {
  1956. #if DBG
  1957. IF_DEBUG(PRINT)
  1958. KdPrint(("NWSPL [DeletePrinterConnection]\n"));
  1959. #endif
  1960. SetLastError( ERROR_INVALID_NAME );
  1961. return FALSE;
  1962. }
  1963. BOOL
  1964. AddPrinterDriverW(
  1965. LPWSTR pszName,
  1966. DWORD dwLevel,
  1967. LPBYTE pbPrinter
  1968. )
  1969. {
  1970. #if DBG
  1971. IF_DEBUG(PRINT)
  1972. KdPrint(("NWSPL [AddPrinterDriver]\n"));
  1973. #endif
  1974. SetLastError( ERROR_INVALID_NAME );
  1975. return FALSE;
  1976. }
  1977. BOOL
  1978. EnumPrinterDriversW(
  1979. LPWSTR pszName,
  1980. LPWSTR pszEnvironment,
  1981. DWORD dwLevel,
  1982. LPBYTE pbDriverInfo,
  1983. DWORD cbBuf,
  1984. LPDWORD pcbNeeded,
  1985. LPDWORD pcReturned
  1986. )
  1987. {
  1988. #if DBG
  1989. IF_DEBUG(PRINT)
  1990. KdPrint(("NWSPL [EnumPrinterDrivers]\n"));
  1991. #endif
  1992. SetLastError( ERROR_INVALID_NAME );
  1993. return FALSE;
  1994. }
  1995. BOOL
  1996. GetPrinterDriverW(
  1997. HANDLE hPrinter,
  1998. LPWSTR pszEnvironment,
  1999. DWORD dwLevel,
  2000. LPBYTE pbDriverInfo,
  2001. DWORD cbBuf,
  2002. LPDWORD pcbNeeded
  2003. )
  2004. {
  2005. #if DBG
  2006. IF_DEBUG(PRINT)
  2007. KdPrint(("NWSPL [GetPrinterDriver]\n"));
  2008. #endif
  2009. SetLastError( ERROR_NOT_SUPPORTED );
  2010. return FALSE;
  2011. }
  2012. BOOL
  2013. GetPrinterDriverDirectoryW(
  2014. LPWSTR pszName,
  2015. LPWSTR pszEnvironment,
  2016. DWORD dwLevel,
  2017. LPBYTE pbDriverDirectory,
  2018. DWORD cbBuf,
  2019. LPDWORD pcbNeeded
  2020. )
  2021. {
  2022. #if DBG
  2023. IF_DEBUG(PRINT)
  2024. KdPrint(("NWSPL [GetPrinterDriverDirectory]\n"));
  2025. #endif
  2026. SetLastError( ERROR_INVALID_NAME );
  2027. return FALSE;
  2028. }
  2029. BOOL
  2030. DeletePrinterDriverW(
  2031. LPWSTR pszName,
  2032. LPWSTR pszEnvironment,
  2033. LPWSTR pszDriverName
  2034. )
  2035. {
  2036. #if DBG
  2037. IF_DEBUG(PRINT)
  2038. KdPrint(("NWSPL [DeletePrinterDriver]\n"));
  2039. #endif
  2040. SetLastError( ERROR_INVALID_NAME );
  2041. return FALSE;
  2042. }
  2043. BOOL
  2044. AddPrintProcessorW(
  2045. LPWSTR pszName,
  2046. LPWSTR pszEnvironment,
  2047. LPWSTR pszPathName,
  2048. LPWSTR pszPrintProcessorName
  2049. )
  2050. {
  2051. #if DBG
  2052. IF_DEBUG(PRINT)
  2053. KdPrint(("NWSPL [AddPrintProcessor]\n"));
  2054. #endif
  2055. SetLastError( ERROR_INVALID_NAME );
  2056. return FALSE;
  2057. }
  2058. BOOL
  2059. EnumPrintProcessorsW(
  2060. LPWSTR pszName,
  2061. LPWSTR pszEnvironment,
  2062. DWORD dwLevel,
  2063. LPBYTE pbPrintProcessorInfo,
  2064. DWORD cbBuf,
  2065. LPDWORD pcbNeeded,
  2066. LPDWORD pcReturned
  2067. )
  2068. {
  2069. #if DBG
  2070. IF_DEBUG(PRINT)
  2071. KdPrint(("NWSPL [EnumPrintProcessors]\n"));
  2072. #endif
  2073. SetLastError( ERROR_INVALID_NAME );
  2074. return FALSE;
  2075. }
  2076. BOOL
  2077. EnumPrintProcessorDatatypesW(
  2078. LPWSTR pszName,
  2079. LPWSTR pszPrintProcessorName,
  2080. DWORD dwLevel,
  2081. LPBYTE pbDatatypes,
  2082. DWORD cbBuf,
  2083. LPDWORD pcbNeeded,
  2084. LPDWORD pcReturned
  2085. )
  2086. {
  2087. #if DBG
  2088. IF_DEBUG(PRINT)
  2089. KdPrint(("NWSPL [EnumPrintProcessorDatatypes]\n"));
  2090. #endif
  2091. SetLastError( ERROR_INVALID_NAME );
  2092. return FALSE;
  2093. }
  2094. BOOL
  2095. GetPrintProcessorDirectoryW(
  2096. LPWSTR pszName,
  2097. LPWSTR pszEnvironment,
  2098. DWORD dwLevel,
  2099. LPBYTE pbPrintProcessorDirectory,
  2100. DWORD cbBuf,
  2101. LPDWORD pcbNeeded
  2102. )
  2103. {
  2104. #if DBG
  2105. IF_DEBUG(PRINT)
  2106. KdPrint(("NWSPL [GetPrintProcessorDirectory]\n"));
  2107. #endif
  2108. SetLastError( ERROR_INVALID_NAME );
  2109. return FALSE;
  2110. }
  2111. BOOL
  2112. StartPagePrinter(
  2113. HANDLE hPrinter
  2114. )
  2115. {
  2116. #if DBG
  2117. IF_DEBUG(PRINT)
  2118. KdPrint(("NWSPL [StartPagePrinter]\n"));
  2119. #endif
  2120. SetLastError( ERROR_NOT_SUPPORTED );
  2121. return FALSE;
  2122. }
  2123. BOOL
  2124. EndPagePrinter(
  2125. HANDLE hPrinter
  2126. )
  2127. {
  2128. #if DBG
  2129. IF_DEBUG(PRINT)
  2130. KdPrint(("NWSPL [EndPagePrinter]\n"));
  2131. #endif
  2132. SetLastError( ERROR_NOT_SUPPORTED );
  2133. return FALSE;
  2134. }
  2135. BOOL
  2136. ReadPrinter(
  2137. HANDLE hPrinter,
  2138. LPVOID pBuf,
  2139. DWORD cbBuf,
  2140. LPDWORD pcbRead
  2141. )
  2142. {
  2143. #if DBG
  2144. IF_DEBUG(PRINT)
  2145. KdPrint(("NWSPL [ReadPrinter]\n"));
  2146. #endif
  2147. SetLastError( ERROR_NOT_SUPPORTED );
  2148. return FALSE;
  2149. }
  2150. DWORD
  2151. GetPrinterDataW(
  2152. HANDLE hPrinter,
  2153. LPWSTR pszValueName,
  2154. LPDWORD pdwType,
  2155. LPBYTE pbData,
  2156. DWORD cbBuf,
  2157. LPDWORD pcbNeeded
  2158. )
  2159. {
  2160. #if DBG
  2161. IF_DEBUG(PRINT)
  2162. KdPrint(("NWSPL [GetPrinterData]\n"));
  2163. #endif
  2164. SetLastError( ERROR_NOT_SUPPORTED );
  2165. return FALSE;
  2166. }
  2167. DWORD
  2168. SetPrinterDataW(
  2169. HANDLE hPrinter,
  2170. LPWSTR pszValueName,
  2171. DWORD dwType,
  2172. LPBYTE pbData,
  2173. DWORD cbData
  2174. )
  2175. {
  2176. #if DBG
  2177. IF_DEBUG(PRINT)
  2178. KdPrint(("NWSPL [SetPrinterData]\n"));
  2179. #endif
  2180. SetLastError( ERROR_NOT_SUPPORTED );
  2181. return FALSE;
  2182. }
  2183. BOOL
  2184. AddForm(
  2185. HANDLE hPrinter,
  2186. DWORD dwLevel,
  2187. LPBYTE pbForm
  2188. )
  2189. {
  2190. #if DBG
  2191. IF_DEBUG(PRINT)
  2192. KdPrint(("NWSPL [AddForm]\n"));
  2193. #endif
  2194. SetLastError( ERROR_NOT_SUPPORTED );
  2195. return FALSE;
  2196. }
  2197. BOOL
  2198. DeleteFormW(
  2199. HANDLE hPrinter,
  2200. LPWSTR pszFormName
  2201. )
  2202. {
  2203. #if DBG
  2204. IF_DEBUG(PRINT)
  2205. KdPrint(("NWSPL [DeleteForm]\n"));
  2206. #endif
  2207. SetLastError( ERROR_NOT_SUPPORTED );
  2208. return FALSE;
  2209. }
  2210. BOOL
  2211. GetFormW(
  2212. HANDLE hPrinter,
  2213. LPWSTR pszFormName,
  2214. DWORD dwLevel,
  2215. LPBYTE pbForm,
  2216. DWORD cbBuf,
  2217. LPDWORD pcbNeeded
  2218. )
  2219. {
  2220. #if DBG
  2221. IF_DEBUG(PRINT)
  2222. KdPrint(("NWSPL [GetForm]\n"));
  2223. #endif
  2224. SetLastError( ERROR_NOT_SUPPORTED );
  2225. return FALSE;
  2226. }
  2227. BOOL
  2228. SetFormW(
  2229. HANDLE hPrinter,
  2230. LPWSTR pszFormName,
  2231. DWORD dwLevel,
  2232. LPBYTE pbForm
  2233. )
  2234. {
  2235. #if DBG
  2236. IF_DEBUG(PRINT)
  2237. KdPrint(("NWSPL [SetForm]\n"));
  2238. #endif
  2239. SetLastError( ERROR_NOT_SUPPORTED );
  2240. return FALSE;
  2241. }
  2242. BOOL
  2243. EnumForms(
  2244. HANDLE hPrinter,
  2245. DWORD dwLevel,
  2246. LPBYTE pbForm,
  2247. DWORD cbBuf,
  2248. LPDWORD pcbNeeded,
  2249. LPDWORD pcReturned
  2250. )
  2251. {
  2252. #if DBG
  2253. IF_DEBUG(PRINT)
  2254. KdPrint(("NWSPL [EnumForms]\n"));
  2255. #endif
  2256. SetLastError( ERROR_NOT_SUPPORTED );
  2257. return FALSE;
  2258. }
  2259. HANDLE
  2260. CreatePrinterIC(
  2261. HANDLE hPrinter,
  2262. LPDEVMODE pDevMode
  2263. )
  2264. {
  2265. #if DBG
  2266. IF_DEBUG(PRINT)
  2267. KdPrint(("NWSPL [CreatePrinterIC]\n"));
  2268. #endif
  2269. SetLastError( ERROR_NOT_SUPPORTED );
  2270. return FALSE;
  2271. }
  2272. BOOL
  2273. PlayGdiScriptOnPrinterIC(
  2274. HANDLE hPrinterIC,
  2275. LPBYTE pbIn,
  2276. DWORD cbIn,
  2277. LPBYTE pbOut,
  2278. DWORD cbOut,
  2279. DWORD ul
  2280. )
  2281. {
  2282. #if DBG
  2283. IF_DEBUG(PRINT)
  2284. KdPrint(("NWSPL [PlayGdiScriptOnPrinterIC]\n"));
  2285. #endif
  2286. SetLastError( ERROR_NOT_SUPPORTED );
  2287. return FALSE;
  2288. }
  2289. BOOL
  2290. DeletePrinterIC(
  2291. HANDLE hPrinterIC
  2292. )
  2293. {
  2294. #if DBG
  2295. IF_DEBUG(PRINT)
  2296. KdPrint(("NWSPL [DeletePrinterIC]\n"));
  2297. #endif
  2298. SetLastError( ERROR_NOT_SUPPORTED );
  2299. return FALSE;
  2300. }
  2301. DWORD
  2302. PrinterMessageBoxW(
  2303. HANDLE hPrinter,
  2304. DWORD dwError,
  2305. HWND hWnd,
  2306. LPWSTR pszText,
  2307. LPWSTR pszCaption,
  2308. DWORD dwType
  2309. )
  2310. {
  2311. #if DBG
  2312. IF_DEBUG(PRINT)
  2313. KdPrint(("NWSPL [PrinterMessageBox]\n"));
  2314. #endif
  2315. SetLastError( ERROR_NOT_SUPPORTED );
  2316. return FALSE;
  2317. }
  2318. BOOL
  2319. AddMonitorW(
  2320. LPWSTR pszName,
  2321. DWORD dwLevel,
  2322. LPBYTE pbMonitorInfo
  2323. )
  2324. {
  2325. #if DBG
  2326. IF_DEBUG(PRINT)
  2327. KdPrint(("NWSPL [AddMonitor]\n"));
  2328. #endif
  2329. SetLastError( ERROR_INVALID_NAME );
  2330. return FALSE;
  2331. }
  2332. BOOL
  2333. DeleteMonitorW(
  2334. LPWSTR pszName,
  2335. LPWSTR pszEnvironment,
  2336. LPWSTR pszMonitorName
  2337. )
  2338. {
  2339. #if DBG
  2340. IF_DEBUG(PRINT)
  2341. KdPrint(("NWSPL [DeleteMonitor]\n"));
  2342. #endif
  2343. SetLastError( ERROR_INVALID_NAME );
  2344. return FALSE;
  2345. }
  2346. BOOL
  2347. DeletePrintProcessorW(
  2348. LPWSTR pszName,
  2349. LPWSTR pszEnvironment,
  2350. LPWSTR pszPrintProcessorName
  2351. )
  2352. {
  2353. #if DBG
  2354. IF_DEBUG(PRINT)
  2355. KdPrint(("NWSPL [DeletePrintProcessor]\n"));
  2356. #endif
  2357. SetLastError( ERROR_INVALID_NAME );
  2358. return FALSE;
  2359. }
  2360. //------------------------------------------------------------------
  2361. //
  2362. // Print Provider Miscellaneous Functions
  2363. //
  2364. //------------------------------------------------------------------
  2365. VOID
  2366. NwpGetUserInfo(
  2367. LPWSTR *ppszUser
  2368. )
  2369. /*++
  2370. Routine Description:
  2371. Get the user information of the impersonating client.
  2372. Arguments:
  2373. ppszUser - A pointer to buffer to store the Unicode string if
  2374. the impersonated client's user name can be looked up
  2375. successfully. If the conversion was unsuccessful, it points
  2376. to NULL.
  2377. Return Value:
  2378. None.
  2379. --*/
  2380. {
  2381. DWORD err;
  2382. LPWSTR pszUserSid = NULL;
  2383. // LPWSTR pszLogonUserSid = NULL; //Removed for Multi-user code merge
  2384. //Terminal Server doesn't user this varible
  2385. //There is no single "Logon User" in Terminal Server
  2386. //
  2387. // If any error occurs while trying to get the username, just
  2388. // assume no user name and not gateway printing.
  2389. //
  2390. *ppszUser = NULL;
  2391. if ( ((err = NwpGetThreadUserInfo( ppszUser, &pszUserSid )) == NO_ERROR)
  2392. // && ((err = NwpGetLogonUserInfo( &pszLogonUserSid ))) == NO_ERROR) //Removed from Multi-user code merge
  2393. ) {
  2394. #if DBG
  2395. IF_DEBUG(PRINT)
  2396. KdPrint(("NwpGetUserInfo: Thread User= %ws, Thread SID = %ws,\n",
  2397. *ppszUser, pszUserSid ));
  2398. #endif
  2399. // } else {
  2400. // if ( _wcsicmp( pszUserSid, pszLogonUserSid ) == 0 ) {
  2401. // }
  2402. //#if DBG
  2403. // IF_DEBUG(PRINT)
  2404. // KdPrint(("NwpGetUserInfo: Thread User= %ws, Thread SID = %ws,\nCurrent SID = %ws\n",
  2405. // *ppszUser, pszUserSid, pszLogonUserSid ));
  2406. //#endif
  2407. // }
  2408. LocalFree( pszUserSid );
  2409. }
  2410. }
  2411. #define SIZE_OF_TOKEN_INFORMATION \
  2412. sizeof( TOKEN_USER ) \
  2413. + sizeof( SID ) \
  2414. + sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
  2415. DWORD
  2416. NwpGetThreadUserInfo(
  2417. LPWSTR *ppszUser,
  2418. LPWSTR *ppszUserSid
  2419. )
  2420. /*++
  2421. Routine Description:
  2422. Get the user name and user sid string of the impersonating client.
  2423. Arguments:
  2424. ppszUser - A pointer to buffer to store the Unicode string
  2425. if the impersonated client's can be looked up. If the
  2426. lookup was unsuccessful, it points to NULL.
  2427. ppszUserSid - A pointer to buffer to store the string if the impersonated
  2428. client's SID can be expanded successfully into unicode string.
  2429. If the conversion was unsuccessful, it points to NULL.
  2430. Return Value:
  2431. The error code.
  2432. --*/
  2433. {
  2434. DWORD err;
  2435. HANDLE TokenHandle;
  2436. UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ];
  2437. ULONG ReturnLength;
  2438. *ppszUser = NULL;
  2439. *ppszUserSid = NULL;
  2440. // We can use OpenThreadToken because this server thread
  2441. // is impersonating a client
  2442. if ( !OpenThreadToken( GetCurrentThread(),
  2443. TOKEN_READ,
  2444. TRUE, /* Open as self */
  2445. &TokenHandle ))
  2446. {
  2447. #if DBG
  2448. IF_DEBUG(PRINT)
  2449. KdPrint(("NwpGetThreadUserInfo: OpenThreadToken failed: Error %d\n",
  2450. GetLastError()));
  2451. #endif
  2452. return(GetLastError());
  2453. }
  2454. // notice that we've allocated enough space for the
  2455. // TokenInformation structure. so if we fail, we
  2456. // return a NULL pointer indicating failure
  2457. if ( !GetTokenInformation( TokenHandle,
  2458. TokenUser,
  2459. TokenInformation,
  2460. sizeof( TokenInformation ),
  2461. &ReturnLength ))
  2462. {
  2463. #if DBG
  2464. IF_DEBUG(PRINT)
  2465. KdPrint(("NwpGetThreadUserInfo: GetTokenInformation failed: Error %d\n",
  2466. GetLastError()));
  2467. #endif
  2468. return(GetLastError());
  2469. }
  2470. CloseHandle( TokenHandle );
  2471. // convert the Sid (pointed to by pSid) to its
  2472. // equivalent Unicode string representation.
  2473. err = NwpGetUserNameFromSid( ((PTOKEN_USER)TokenInformation)->User.Sid,
  2474. ppszUser );
  2475. err = err? err : NwpConvertSid( ((PTOKEN_USER)TokenInformation)->User.Sid,
  2476. ppszUserSid );
  2477. if ( err )
  2478. {
  2479. if ( *ppszUser )
  2480. LocalFree( *ppszUser );
  2481. if ( *ppszUserSid )
  2482. LocalFree( *ppszUserSid );
  2483. }
  2484. return err;
  2485. }
  2486. DWORD
  2487. NwpGetUserNameFromSid(
  2488. PSID pUserSid,
  2489. LPWSTR *ppszUserName
  2490. )
  2491. /*++
  2492. Routine Description:
  2493. Lookup the user name given the user SID.
  2494. Arguments:
  2495. pUserSid - Points to the user sid to be looked up
  2496. ppszUserName - A pointer to buffer to store the string if the impersonated
  2497. client's SID can be expanded successfully into unicode string.
  2498. If the conversion was unsuccessful, it points to NULL.
  2499. Return Value:
  2500. The error code.
  2501. --*/
  2502. {
  2503. NTSTATUS ntstatus;
  2504. LSA_HANDLE hlsa;
  2505. OBJECT_ATTRIBUTES oa;
  2506. SECURITY_QUALITY_OF_SERVICE sqos;
  2507. PLSA_REFERENCED_DOMAIN_LIST plsardl = NULL;
  2508. PLSA_TRANSLATED_NAME plsatn = NULL;
  2509. sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  2510. sqos.ImpersonationLevel = SecurityImpersonation;
  2511. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  2512. sqos.EffectiveOnly = FALSE;
  2513. InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL );
  2514. oa.SecurityQualityOfService = &sqos;
  2515. ntstatus = LsaOpenPolicy( NULL,
  2516. &oa,
  2517. POLICY_LOOKUP_NAMES,
  2518. &hlsa );
  2519. if ( NT_SUCCESS( ntstatus ))
  2520. {
  2521. ntstatus = LsaLookupSids( hlsa,
  2522. 1,
  2523. &pUserSid,
  2524. &plsardl,
  2525. &plsatn );
  2526. if ( NT_SUCCESS( ntstatus ))
  2527. {
  2528. UNICODE_STRING *pUnicodeStr = &((*plsatn).Name);
  2529. *ppszUserName = LocalAlloc( LMEM_ZEROINIT,
  2530. pUnicodeStr->Length+sizeof(WCHAR));
  2531. if ( *ppszUserName != NULL )
  2532. {
  2533. memcpy( *ppszUserName, pUnicodeStr->Buffer, pUnicodeStr->Length );
  2534. }
  2535. else
  2536. {
  2537. ntstatus = STATUS_NO_MEMORY;
  2538. }
  2539. LsaFreeMemory( plsardl );
  2540. LsaFreeMemory( plsatn );
  2541. }
  2542. #if DBG
  2543. else
  2544. {
  2545. KdPrint(("NwpGetUserNameFromSid: LsaLookupSids failed: Error = %d\n",
  2546. GetLastError()));
  2547. }
  2548. #endif
  2549. LsaClose( hlsa );
  2550. }
  2551. #if DBG
  2552. else
  2553. {
  2554. KdPrint(("NwpGetUserNameFromSid: LsaOpenPolicy failed: Error = %d\n",
  2555. GetLastError()));
  2556. }
  2557. #endif
  2558. return RtlNtStatusToDosError( ntstatus );
  2559. }
  2560. DWORD
  2561. NwpGetLogonUserInfo(
  2562. LPWSTR *ppszUserSid
  2563. )
  2564. /*++
  2565. Routine Description:
  2566. Get the logon user sid string from the registry.
  2567. Arguments:
  2568. ppszUserSid - On return, this points to the current logon user
  2569. sid string.
  2570. Return Value:
  2571. The error code.
  2572. --*/
  2573. {
  2574. DWORD err;
  2575. HKEY WkstaKey;
  2576. LPWSTR CurrentUser = NULL;
  2577. //
  2578. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  2579. // \NWCWorkstation\Parameters to get the sid of the CurrentUser
  2580. //
  2581. err = RegOpenKeyExW(
  2582. HKEY_LOCAL_MACHINE,
  2583. NW_WORKSTATION_REGKEY,
  2584. REG_OPTION_NON_VOLATILE,
  2585. KEY_READ,
  2586. &WkstaKey
  2587. );
  2588. if ( err == NO_ERROR) {
  2589. //
  2590. // Read the current user SID string so that we
  2591. // know which key is the current user key to open.
  2592. //
  2593. err = NwReadRegValue(
  2594. WkstaKey,
  2595. NW_CURRENTUSER_VALUENAME,
  2596. &CurrentUser
  2597. );
  2598. RegCloseKey( WkstaKey );
  2599. if ( err == NO_ERROR) {
  2600. *ppszUserSid = CurrentUser;
  2601. }
  2602. }
  2603. return(err);
  2604. }
  2605. #define SIZE_OF_STATISTICS_TOKEN_INFORMATION \
  2606. sizeof( TOKEN_STATISTICS )
  2607. DWORD
  2608. ThreadIsInteractive(
  2609. VOID
  2610. )
  2611. /*++
  2612. Routine Description:
  2613. Determines if this is an "Interactive" logon thread
  2614. Arguments:
  2615. none
  2616. Return Value:
  2617. TRUE - Thread is interactive
  2618. FALSE - Thread is not interactive
  2619. --*/
  2620. {
  2621. HANDLE TokenHandle;
  2622. UCHAR TokenInformation[ SIZE_OF_STATISTICS_TOKEN_INFORMATION ];
  2623. WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN];
  2624. ULONG ReturnLength;
  2625. LUID LogonId;
  2626. LONG RegError;
  2627. HKEY InteractiveLogonKey;
  2628. HKEY OneLogonKey;
  2629. // We can use OpenThreadToken because this server thread
  2630. // is impersonating a client
  2631. if ( !OpenThreadToken( GetCurrentThread(),
  2632. TOKEN_READ,
  2633. TRUE, /* Open as self */
  2634. &TokenHandle ))
  2635. {
  2636. #if DBG
  2637. IF_DEBUG(PRINT)
  2638. KdPrint(("ThreadIsInteractive: OpenThreadToken failed: Error %d\n",
  2639. GetLastError()));
  2640. #endif
  2641. return FALSE;
  2642. }
  2643. // notice that we've allocated enough space for the
  2644. // TokenInformation structure. so if we fail, we
  2645. // return a NULL pointer indicating failure
  2646. if ( !GetTokenInformation( TokenHandle,
  2647. TokenStatistics,
  2648. TokenInformation,
  2649. sizeof( TokenInformation ),
  2650. &ReturnLength ))
  2651. {
  2652. #if DBG
  2653. IF_DEBUG(PRINT)
  2654. KdPrint(("ThreadIsInteractive: GetTokenInformation failed: Error %d\n",
  2655. GetLastError()));
  2656. #endif
  2657. return FALSE;
  2658. }
  2659. CloseHandle( TokenHandle );
  2660. LogonId = ((PTOKEN_STATISTICS)TokenInformation)->AuthenticationId;
  2661. RegError = RegOpenKeyExW(
  2662. HKEY_LOCAL_MACHINE,
  2663. NW_INTERACTIVE_LOGON_REGKEY,
  2664. REG_OPTION_NON_VOLATILE,
  2665. KEY_READ,
  2666. &InteractiveLogonKey
  2667. );
  2668. if (RegError != ERROR_SUCCESS) {
  2669. #if DBG
  2670. IF_DEBUG(PRINT)
  2671. KdPrint(("ThreadIsInteractive: RegOpenKeyExW failed: Error %d\n",
  2672. GetLastError()));
  2673. #endif
  2674. return FALSE;
  2675. }
  2676. NwLuidToWStr(&LogonId, LogonIdKeyName);
  2677. //
  2678. // Open the <LogonIdKeyName> key under Logon
  2679. //
  2680. RegError = RegOpenKeyExW(
  2681. InteractiveLogonKey,
  2682. LogonIdKeyName,
  2683. REG_OPTION_NON_VOLATILE,
  2684. KEY_READ,
  2685. &OneLogonKey
  2686. );
  2687. if ( RegError == ERROR_SUCCESS ) {
  2688. (void) RegCloseKey(OneLogonKey);
  2689. (void) RegCloseKey(InteractiveLogonKey);
  2690. return TRUE; /* We found it */
  2691. }
  2692. else {
  2693. (void) RegCloseKey(InteractiveLogonKey);
  2694. return FALSE; /* We did not find it */
  2695. }
  2696. }
  2697. DWORD
  2698. NwpCitrixGetUserInfo(
  2699. LPWSTR *ppszUserSid
  2700. )
  2701. /*++
  2702. Routine Description:
  2703. Get the user sid string of the client.
  2704. Arguments:
  2705. ppszUserSid - A pointer to buffer to store the string.
  2706. Return Value:
  2707. The error code.
  2708. --*/
  2709. {
  2710. DWORD err;
  2711. HANDLE TokenHandle;
  2712. UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ];
  2713. ULONG ReturnLength;
  2714. *ppszUserSid = NULL;
  2715. // We can use OpenThreadToken because this server thread
  2716. // is impersonating a client
  2717. if ( !OpenThreadToken( GetCurrentThread(),
  2718. TOKEN_READ,
  2719. TRUE, /* Open as self */
  2720. &TokenHandle ))
  2721. {
  2722. err = GetLastError();
  2723. if ( err == ERROR_NO_TOKEN ) {
  2724. if ( !OpenProcessToken( GetCurrentProcess(),
  2725. TOKEN_READ,
  2726. &TokenHandle )) {
  2727. #if DBG
  2728. IF_DEBUG(PRINT)
  2729. KdPrint(("NwpGetThreadUserInfo: OpenThreadToken failed: Error %d\n",
  2730. GetLastError()));
  2731. #endif
  2732. return(GetLastError());
  2733. }
  2734. }
  2735. else
  2736. return( err );
  2737. }
  2738. // notice that we've allocated enough space for the
  2739. // TokenInformation structure. so if we fail, we
  2740. // return a NULL pointer indicating failure
  2741. if ( !GetTokenInformation( TokenHandle,
  2742. TokenUser,
  2743. TokenInformation,
  2744. sizeof( TokenInformation ),
  2745. &ReturnLength ))
  2746. {
  2747. #if DBG
  2748. IF_DEBUG(PRINT)
  2749. KdPrint(("NwpGetThreadUserInfo: GetTokenInformation failed: Error %d\n",
  2750. GetLastError()));
  2751. #endif
  2752. return(GetLastError());
  2753. }
  2754. CloseHandle( TokenHandle );
  2755. // convert the Sid (pointed to by pSid) to its
  2756. // equivalent Unicode string representation.
  2757. err = NwpConvertSid( ((PTOKEN_USER)TokenInformation)->User.Sid,
  2758. ppszUserSid );
  2759. if ( err )
  2760. {
  2761. if ( *ppszUserSid )
  2762. LocalFree( *ppszUserSid );
  2763. }
  2764. return err;
  2765. }