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

2026 lines
47 KiB

  1. /*++
  2. Copyright (c) 1992-1993 Microsoft Corporation
  3. Module Name:
  4. nwmain.c
  5. Abstract:
  6. Main module of the NetWare workstation service.
  7. Author:
  8. Rita Wong (ritaw) 11-Dec-1992
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include <nw.h>
  14. #include <nwreg.h>
  15. #include <wsipx.h>
  16. #include <wsnwlink.h>
  17. #include <nwmisc.h>
  18. #include <winsta.h>
  19. //
  20. //
  21. // GetProcAddr Prototype for winsta.dll function WinStationSetInformationW
  22. //
  23. typedef BOOLEAN (*PWINSTATION_SET_INFORMATION) (
  24. HANDLE hServer,
  25. ULONG SessionId,
  26. WINSTATIONINFOCLASS WinStationInformationClass,
  27. PVOID pWinStationInformation,
  28. ULONG WinStationInformationLength
  29. );
  30. //
  31. //
  32. // GetProcAddr Prototype for winsta.dll function WinStationSendMessageW
  33. //
  34. typedef BOOLEAN
  35. (*PWINSTATION_SEND_MESSAGE) (
  36. HANDLE hServer,
  37. ULONG LogonId,
  38. LPWSTR pTitle,
  39. ULONG TitleLength,
  40. LPWSTR pMessage,
  41. ULONG MessageLength,
  42. ULONG Style,
  43. ULONG Timeout,
  44. PULONG pResponse,
  45. BOOLEAN DoNotWait
  46. );
  47. //------------------------------------------------------------------
  48. //
  49. // Local Definitions
  50. //
  51. //------------------------------------------------------------------
  52. #define NW_EVENT_MESSAGE_FILE L"nwevent.dll"
  53. #define NW_MAX_POPUP_MESSAGE_LENGTH 512
  54. #define REG_WORKSTATION_PROVIDER_PATH L"System\\CurrentControlSet\\Services\\NWCWorkstation\\networkprovider"
  55. #define REG_PROVIDER_VALUE_NAME L"Name"
  56. #define REG_WORKSTATION_PARAMETERS_PATH L"System\\CurrentControlSet\\Services\\NWCWorkstation\\Parameters"
  57. #define REG_BURST_VALUE_NAME L"MaxBurstSize"
  58. #define REG_GATEWAY_VALUE_NAME L"GatewayPrintOption"
  59. #define REG_DISABLEPOPUP_VALUE_NAME L"DisablePopup"
  60. #define REG_GW_NOCONNECT_VALUE_NAME L"GWDontConnectAtStart"
  61. #define REG_SETUP_PATH L"System\\Setup"
  62. #define REG_SETUP_VALUE_NAME L"SystemSetupInProgress"
  63. //
  64. // QFE release does not have this. so for QFE, we make it a no-op bit.
  65. //
  66. #ifdef QFE_BUILD
  67. #define MB_SERVICE_NOTIFICATION 0
  68. #endif
  69. //-------------------------------------------------------------------//
  70. // //
  71. // Local Function Prototypes //
  72. // //
  73. //-------------------------------------------------------------------//
  74. DWORD
  75. NwInitialize(
  76. OUT LPDWORD NwInitState
  77. );
  78. DWORD
  79. NwInitializeCritSects(
  80. VOID
  81. );
  82. VOID
  83. NwInitializeWkstaInfo(
  84. VOID
  85. );
  86. DWORD
  87. NwInitializeMessage(
  88. VOID
  89. );
  90. BOOL NwShutdownNotify(
  91. DWORD dwCtrlType
  92. );
  93. VOID
  94. NwShutdown(
  95. IN DWORD ErrorCode,
  96. IN DWORD NwInitState
  97. );
  98. VOID
  99. NwShutdownMessage(
  100. VOID
  101. );
  102. VOID
  103. NwControlHandler(
  104. IN DWORD Opcode
  105. );
  106. DWORD
  107. NwUpdateStatus(
  108. VOID
  109. );
  110. VOID
  111. NwMessageThread(
  112. IN HANDLE RdrHandle
  113. );
  114. VOID
  115. NwDisplayMessage(
  116. IN LUID LogonId,
  117. IN LPWSTR Server,
  118. IN LPWSTR Message
  119. );
  120. VOID
  121. NwDisplayPopup(
  122. IN LPNWWKS_POPUP_DATA lpPopupData
  123. );
  124. BOOL
  125. SendMessageIfUserW(
  126. LUID LogonId,
  127. LPWSTR pMessage,
  128. LPWSTR pTitle
  129. );
  130. BOOL
  131. NwSetupInProgress(
  132. VOID
  133. );
  134. BOOL
  135. NwGetLUIDDeviceMapsEnabled(
  136. VOID
  137. );
  138. //-------------------------------------------------------------------//
  139. // //
  140. // Global variables //
  141. // //
  142. //-------------------------------------------------------------------//
  143. //
  144. // For service control
  145. //
  146. STATIC SERVICE_STATUS NwStatus;
  147. STATIC SERVICE_STATUS_HANDLE NwStatusHandle = 0;
  148. HANDLE NwDoneEvent = NULL ;
  149. //
  150. // For popping up errors.
  151. //
  152. HANDLE NwPopupEvent = NULL ;
  153. HANDLE NwPopupDoneEvent = NULL ;
  154. NWWKS_POPUP_DATA PopupData ;
  155. //
  156. // For NTAS vs Winnt
  157. //
  158. BOOL fIsWinnt = TRUE; // default is this is Workstation (FALSE = Server)
  159. //
  160. // Flag to control DBCS translations
  161. //
  162. extern LONG Japan = 0;
  163. //
  164. // Data global to nwsvc.exe
  165. //
  166. PSVCHOST_GLOBAL_DATA NwsvcGlobalData;
  167. //
  168. // Handle for receiving server messages
  169. //
  170. STATIC HANDLE NwRdrMessageHandle;
  171. //
  172. // Stores the network and print provider name
  173. //
  174. WCHAR NwProviderName[MAX_PATH] = L"";
  175. // Stores the packet burst size
  176. DWORD NwPacketBurstSize = 32 * 1024;
  177. //
  178. // remember if gateway is logged on
  179. //
  180. BOOL GatewayLoggedOn = FALSE ;
  181. //
  182. // should gateway always take up a connection?
  183. //
  184. BOOL GatewayConnectionAlways = TRUE ;
  185. //
  186. // critical sections used
  187. //
  188. CRITICAL_SECTION NwLoggedOnCritSec;
  189. CRITICAL_SECTION NwPrintCritSec; // protect the linked list of printers
  190. BOOL NwLUIDDeviceMapsEnabled;
  191. //-------------------------------------------------------------------//
  192. VOID
  193. SvchostPushServiceGlobals(
  194. PSVCHOST_GLOBAL_DATA pGlobals
  195. )
  196. {
  197. NwsvcGlobalData = pGlobals;
  198. }
  199. VOID
  200. ServiceMain(
  201. DWORD NumArgs,
  202. LPTSTR *ArgsArray
  203. )
  204. /*++
  205. Routine Description:
  206. This is the main entry point of the NetWare workstation service. After
  207. the service has been initialized, this thread will wait on NwDoneEvent
  208. for a signal to terminate the service.
  209. Arguments:
  210. NumArgs - Supplies the number of strings specified in ArgsArray.
  211. ArgsArray - Supplies string arguments that are specified in the
  212. StartService API call. This parameter is ignored.
  213. Return Value:
  214. None.
  215. --*/
  216. {
  217. DWORD NwInitState = 0;
  218. UNREFERENCED_PARAMETER(NumArgs);
  219. UNREFERENCED_PARAMETER(ArgsArray);
  220. //
  221. // Make sure svchost.exe gave us the global data
  222. //
  223. ASSERT(NwsvcGlobalData != NULL);
  224. if (NwInitialize(&NwInitState) != NO_ERROR) {
  225. return;
  226. }
  227. //
  228. // Wait until we are told to stop.
  229. //
  230. (void) WaitForSingleObject(
  231. NwDoneEvent,
  232. INFINITE
  233. );
  234. NwShutdown(
  235. NO_ERROR, // Normal termination
  236. NwInitState
  237. );
  238. }
  239. DWORD
  240. NwInitialize(
  241. OUT LPDWORD NwInitState
  242. )
  243. /*++
  244. Routine Description:
  245. This function initializes the NetWare workstation service.
  246. Arguments:
  247. NwInitState - Returns a flag to indicate how far we got with initializing
  248. the service before an error occurred.
  249. Return Value:
  250. NO_ERROR or reason for failure.
  251. Notes:
  252. See IMPORTANT NOTE below.
  253. --*/
  254. {
  255. DWORD status;
  256. NT_PRODUCT_TYPE ProductType ;
  257. LCID lcid;
  258. //
  259. // are we a winnt machine?
  260. //
  261. #ifdef GATEWAY_ENABLED
  262. fIsWinnt = RtlGetNtProductType(&ProductType) ?
  263. (ProductType == NtProductWinNt) :
  264. FALSE ;
  265. #else
  266. fIsWinnt = TRUE;
  267. #endif
  268. //
  269. // initialize all our critical sections as soon as we can
  270. //
  271. status = NwInitializeCritSects();
  272. if (status != NO_ERROR)
  273. {
  274. KdPrint(("NWWORKSTATION: NwInitializeCritSects error %lu\n", status));
  275. return status;
  276. }
  277. //
  278. // Initialize all the status fields so that subsequent calls to
  279. // SetServiceStatus need to only update fields that changed.
  280. //
  281. NwStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  282. NwStatus.dwCurrentState = SERVICE_START_PENDING;
  283. NwStatus.dwControlsAccepted = 0;
  284. NwStatus.dwCheckPoint = 1;
  285. NwStatus.dwWaitHint = 5000;
  286. NwStatus.dwWin32ExitCode = NO_ERROR;
  287. NwStatus.dwServiceSpecificExitCode = 0;
  288. //
  289. // Initialize workstation to receive service requests by registering the
  290. // control handler.
  291. //
  292. if ((NwStatusHandle = RegisterServiceCtrlHandlerW(
  293. NW_WORKSTATION_SERVICE,
  294. NwControlHandler
  295. )) == 0) {
  296. status = GetLastError();
  297. KdPrint(("NWWORKSTATION: RegisterServiceCtrlHandlerW error %lu\n", status));
  298. return status;
  299. }
  300. //
  301. // Tell Service Controller that we are start pending.
  302. //
  303. (void) NwUpdateStatus();
  304. //
  305. // Don't run during GUI-mode setup (doing so can cause migration of
  306. // registry keys the service opens to fail, deleting share names)
  307. //
  308. if (NwSetupInProgress())
  309. {
  310. //
  311. // Fail silently so there's no Eventlog message to panic the user
  312. //
  313. NwShutdown(NO_ERROR, *NwInitState);
  314. //
  315. // Bit of a hack since ServiceMain will wait on the NwDoneEvent
  316. // (which hasn't yet been created) if NwInitialize returns anything
  317. // other than NO_ERROR. This error code isn't used for anything
  318. // other than telling ServiceMain to return without waiting.
  319. //
  320. return ERROR_SERVICE_DISABLED;
  321. }
  322. //
  323. // Create events to synchronize message popups
  324. //
  325. if (((NwPopupEvent = CreateEvent(
  326. NULL, // no security descriptor
  327. FALSE, // use automatic reset
  328. FALSE, // initial state: not signalled
  329. NULL // no name
  330. )) == NULL)
  331. || ((NwPopupDoneEvent = CreateEvent(
  332. NULL, // no security descriptor
  333. FALSE, // use automatic reset
  334. TRUE, // initial state: signalled
  335. NULL // no name
  336. )) == NULL))
  337. {
  338. status = GetLastError();
  339. NwShutdown(status, *NwInitState);
  340. return status;
  341. }
  342. //
  343. // Create event to synchronize termination
  344. //
  345. if ((NwDoneEvent = CreateEvent(
  346. NULL, // no security descriptor
  347. TRUE, // do not use automatic reset
  348. FALSE, // initial state: not signalled
  349. NULL // no name
  350. )) == NULL) {
  351. status = GetLastError();
  352. NwShutdown(status, *NwInitState);
  353. return status;
  354. }
  355. (*NwInitState) |= NW_EVENTS_CREATED;
  356. //
  357. // Load the redirector.
  358. //
  359. if ((status = NwInitializeRedirector()) != NO_ERROR) {
  360. NwShutdown(status, *NwInitState);
  361. return status;
  362. }
  363. (*NwInitState) |= NW_RDR_INITIALIZED;
  364. //
  365. // Service still start pending. Update checkpoint to reflect that
  366. // we are making progress.
  367. //
  368. NwStatus.dwCheckPoint++;
  369. (void) NwUpdateStatus();
  370. //
  371. // Bind to transports
  372. //
  373. status = NwBindToTransports();
  374. //
  375. // tommye MS 24187 / MCS 255
  376. //
  377. //
  378. // G/CSNW has been unbound in the connection manager and so, we haven't
  379. // found the linkage key to bind to.
  380. //
  381. if (status == ERROR_INVALID_PARAMETER) {
  382. //
  383. // Fail silently so there's no Eventlog message to panic the user
  384. //
  385. NwShutdown(NO_ERROR, *NwInitState);
  386. //
  387. // Bit of a hack since SvcEntry_NWCS will wait on the NwDoneEvent
  388. // (which hasn't yet been created) if NwInitialize returns anything
  389. // other than NO_ERROR. This error code isn't used for anything
  390. // other than telling SvcEntry_NWCS to return without waiting.
  391. //
  392. return ERROR_SERVICE_DISABLED;
  393. } else if (status != NO_ERROR) {
  394. NwShutdown(status, *NwInitState);
  395. return status;
  396. }
  397. (*NwInitState) |= NW_BOUND_TO_TRANSPORTS;
  398. //
  399. // Service still start pending. Update checkpoint to reflect that
  400. // we are making progress.
  401. //
  402. NwStatus.dwCheckPoint++;
  403. (void) NwUpdateStatus();
  404. //
  405. // Initialize credential management.
  406. //
  407. NwInitializeLogon();
  408. //
  409. // Setup thread to receive server messages. Even if not successful,
  410. // just press on as the workstation is mostly functional.
  411. //
  412. if ((status = NwInitializeMessage()) == NO_ERROR) {
  413. (*NwInitState) |= NW_INITIALIZED_MESSAGE;
  414. }
  415. //
  416. // Service still start pending. Update checkpoint to reflect that
  417. // we are making progress.
  418. //
  419. NwStatus.dwCheckPoint++;
  420. (void) NwUpdateStatus();
  421. //
  422. // Read some workstation information stored in the registry
  423. // and passes some info to the redirector. This has to be
  424. // done before opening up the RPC interface.
  425. //
  426. NwInitializeWkstaInfo();
  427. //
  428. // Initialize the server side print provider.
  429. //
  430. NwInitializePrintProvider();
  431. //
  432. // Initialize the service provider.
  433. //
  434. NwInitializeServiceProvider();
  435. //
  436. // tommye - MS 176469
  437. //
  438. // No longer supporting the Gateway - so just force it to be disabled
  439. //
  440. #ifdef GATEWAY_ENABLED
  441. //
  442. // Login the Gateway account. if not setup, this is a no-op.
  443. // Failures are non fatal.
  444. //
  445. if ((status = NwGatewayLogon()) == NO_ERROR) {
  446. (*NwInitState) |= NW_GATEWAY_LOGON;
  447. }
  448. #endif
  449. //
  450. // Service still start pending. Update checkpoint to reflect that
  451. // we are making progress.
  452. //
  453. NwStatus.dwCheckPoint++;
  454. (void) NwUpdateStatus();
  455. //
  456. // Open up the RPC interface
  457. //
  458. status = NwsvcGlobalData->StartRpcServer(
  459. NWWKS_INTERFACE_NAME,
  460. nwwks_ServerIfHandle
  461. );
  462. if (status != NO_ERROR) {
  463. NwShutdown(status, *NwInitState);
  464. return status;
  465. }
  466. (*NwInitState) |= NW_RPC_SERVER_STARTED;
  467. //
  468. // Set up the hook to handle computer shut down.
  469. //
  470. // IMPORTANT NOTE: this is the last step after everything else
  471. // has suceeded. When shutdown handler is called, it assumes that
  472. // the redir is fully initialized.
  473. //
  474. if ( !SetConsoleCtrlHandler( NwShutdownNotify, TRUE ))
  475. {
  476. KdPrint(("SetConsoleCtrlHandler failed with %d\n", GetLastError()));
  477. NwShutdown( status, *NwInitState );
  478. return GetLastError();
  479. }
  480. //
  481. // We are done with workstation startup.
  482. //
  483. NwStatus.dwCurrentState = SERVICE_RUNNING;
  484. NwStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  485. SERVICE_ACCEPT_SHUTDOWN;
  486. NwStatus.dwCheckPoint = 0;
  487. NwStatus.dwWaitHint = 0;
  488. NwStatus.dwWin32ExitCode = NO_ERROR;
  489. if ((status = NwUpdateStatus()) != NO_ERROR) {
  490. NwShutdown(status, *NwInitState);
  491. return status;
  492. }
  493. //
  494. // Read user and service logon credentias from the registry, in
  495. // case user logged on before workstation was started.
  496. // Eg. restart workstation.
  497. //
  498. NwGetLogonCredential();
  499. #if 0
  500. //
  501. // check that the NWLINK has the right sockopts
  502. //
  503. // see comment on the actual function
  504. //
  505. if (!NwIsNWLinkVersionOK())
  506. {
  507. //
  508. // log the error in the event log
  509. //
  510. LPWSTR InsertStrings[1] ;
  511. NwLogEvent(EVENT_NWWKSTA_WRONG_NWLINK_VERSION,
  512. 0,
  513. InsertStrings,
  514. 0) ;
  515. }
  516. #endif
  517. //
  518. // Check to see if we're in a DBCS environment.
  519. //
  520. NtQueryDefaultLocale( TRUE, &lcid );
  521. Japan = 0;
  522. if (PRIMARYLANGID(lcid) == LANG_JAPANESE ||
  523. PRIMARYLANGID(lcid) == LANG_KOREAN ||
  524. PRIMARYLANGID(lcid) == LANG_CHINESE) {
  525. Japan = 1;
  526. }
  527. NwLUIDDeviceMapsEnabled = NwGetLUIDDeviceMapsEnabled();
  528. //
  529. // Successful initialization
  530. //
  531. return NO_ERROR;
  532. }
  533. BOOL NwShutdownNotify(
  534. IN DWORD dwCtrlType
  535. )
  536. /*++
  537. Routine Description:
  538. This function is a control handler used in SetConsoleCtrlHandler.
  539. We are only interested in CTRL_SHUTDOWN_EVENT. On shutdown, we
  540. need to notify redirector to shut down and then delete the
  541. CurrentUser key in the registry.
  542. Arguments:
  543. dwCtrlType - The control type that occurred. We will only
  544. process CTRL_SHUTDOWN_EVENT.
  545. Return Value:
  546. TRUE if we don't want the default or other handlers to be called.
  547. FALSE otherwise.
  548. Note:
  549. This Handler is registered after all the Init steps have completed.
  550. As such, it does not check for what state the service is in as it
  551. cleans up.
  552. --*/
  553. {
  554. DWORD err;
  555. #if DBG
  556. IF_DEBUG(INIT)
  557. KdPrint(("NwShutdownNotify\n"));
  558. #endif
  559. if ( dwCtrlType != CTRL_SHUTDOWN_EVENT )
  560. {
  561. return FALSE;
  562. }
  563. //
  564. // stop the RPC server
  565. //
  566. (void) NwsvcGlobalData->StopRpcServer(nwwks_ServerIfHandle);
  567. //
  568. // get rid of all connections
  569. //
  570. (void) DeleteAllConnections();
  571. NwGatewayLogoff() ;
  572. err = NwShutdownRedirector();
  573. if ( err != NO_ERROR )
  574. KdPrint(("Shut down redirector failed with %d\n", err ));
  575. #if DBG
  576. else
  577. {
  578. IF_DEBUG(INIT)
  579. KdPrint(("NwShutdownRedirector success!\n"));
  580. }
  581. #endif
  582. //
  583. // Delete all logon session information in the registry.
  584. //
  585. NwDeleteInteractiveLogon(NULL);
  586. (void) NwDeleteServiceLogon(NULL);
  587. return FALSE; // The default handler will terminate the process.
  588. }
  589. VOID
  590. NwShutdown(
  591. IN DWORD ErrorCode,
  592. IN DWORD NwInitState
  593. )
  594. /*++
  595. Routine Description:
  596. This function shuts down the Workstation service.
  597. Arguments:
  598. ErrorCode - Supplies the error code of the failure
  599. NwInitState - Supplies a flag to indicate how far we got with initializing
  600. the service before an error occurred, thus the amount of clean up
  601. needed.
  602. Return Value:
  603. None.
  604. --*/
  605. {
  606. DWORD status = NO_ERROR;
  607. //
  608. // Service stop still pending. Update checkpoint counter and the
  609. // status with the Service Controller.
  610. //
  611. (NwStatus.dwCheckPoint)++;
  612. (void) NwUpdateStatus();
  613. if (NwInitState & NW_RPC_SERVER_STARTED) {
  614. NwsvcGlobalData->StopRpcServer(nwwks_ServerIfHandle);
  615. }
  616. if (NwInitState & NW_INITIALIZED_MESSAGE) {
  617. NwShutdownMessage();
  618. }
  619. if (NwInitState & NW_GATEWAY_LOGON)
  620. {
  621. (void) NwDeleteRedirections() ;
  622. }
  623. //
  624. // Service stop still pending. Update checkpoint counter and the
  625. // status with the Service Controller.
  626. //
  627. (NwStatus.dwCheckPoint)++;
  628. (void) NwUpdateStatus();
  629. if (NwInitState & NW_BOUND_TO_TRANSPORTS) {
  630. DeleteAllConnections();
  631. NwGatewayLogoff() ;
  632. }
  633. //
  634. // Clean up the service provider.
  635. //
  636. // NwTerminateServiceProvider(); NOT CALLED! This is done at DLL unload time already.
  637. //
  638. // Clean up the server side print provider
  639. //
  640. NwTerminatePrintProvider();
  641. //
  642. // Service stop still pending. Update checkpoint counter and the
  643. // status with the Service Controller.
  644. //
  645. (NwStatus.dwCheckPoint)++;
  646. (void) NwUpdateStatus();
  647. if (NwInitState & NW_RDR_INITIALIZED) {
  648. //
  649. // Unload the redirector
  650. //
  651. status = NwShutdownRedirector();
  652. }
  653. if (NwInitState & NW_EVENTS_CREATED) {
  654. //
  655. // Close handle to termination event and popup event
  656. //
  657. if (NwDoneEvent) CloseHandle(NwDoneEvent);
  658. if (NwPopupEvent) CloseHandle(NwPopupEvent);
  659. if (NwPopupDoneEvent) CloseHandle(NwPopupDoneEvent);
  660. }
  661. //
  662. // We are done with cleaning up. Tell Service Controller that we are
  663. // stopped.
  664. //
  665. NwStatus.dwCurrentState = SERVICE_STOPPED;
  666. NwStatus.dwControlsAccepted = 0;
  667. if ((ErrorCode == NO_ERROR) &&
  668. (status == ERROR_REDIRECTOR_HAS_OPEN_HANDLES)) {
  669. ErrorCode = status;
  670. }
  671. //
  672. // Deregister the control handler
  673. //
  674. (void) SetConsoleCtrlHandler( NwShutdownNotify, FALSE ) ;
  675. NwStatus.dwWin32ExitCode = ErrorCode;
  676. NwStatus.dwServiceSpecificExitCode = 0;
  677. NwStatus.dwCheckPoint = 0;
  678. NwStatus.dwWaitHint = 0;
  679. (void) NwUpdateStatus();
  680. }
  681. VOID
  682. NwControlHandler(
  683. IN DWORD Opcode
  684. )
  685. /*++
  686. Routine Description:
  687. This is the service control handler of the Workstation service.
  688. Arguments:
  689. Opcode - Supplies a value which specifies the action for the
  690. service to perform.
  691. Return Value:
  692. None.
  693. --*/
  694. {
  695. switch (Opcode) {
  696. case SERVICE_CONTROL_STOP:
  697. case SERVICE_CONTROL_SHUTDOWN:
  698. if ((NwStatus.dwCurrentState != SERVICE_STOP_PENDING) &&
  699. (NwStatus.dwCurrentState != SERVICE_STOPPED)){
  700. NwStatus.dwCurrentState = SERVICE_STOP_PENDING;
  701. NwStatus.dwCheckPoint = 1;
  702. NwStatus.dwWaitHint = 60000;
  703. //
  704. // Send the status response.
  705. //
  706. (void) NwUpdateStatus();
  707. if (! SetEvent(NwDoneEvent)) {
  708. //
  709. // Problem with setting event to terminate Workstation
  710. // service.
  711. //
  712. KdPrint(("NWWORKSTATION: Error setting NwDoneEvent %lu\n",
  713. GetLastError()));
  714. ASSERT(FALSE);
  715. }
  716. return;
  717. }
  718. break;
  719. case SERVICE_CONTROL_INTERROGATE:
  720. break;
  721. }
  722. //
  723. // Send the status response.
  724. //
  725. (void) NwUpdateStatus();
  726. }
  727. DWORD
  728. NwUpdateStatus(
  729. VOID
  730. )
  731. /*++
  732. Routine Description:
  733. This function updates the workstation service status with the Service
  734. Controller.
  735. Arguments:
  736. None.
  737. Return Value:
  738. Return code from SetServiceStatus.
  739. --*/
  740. {
  741. DWORD status = NO_ERROR;
  742. if (NwStatusHandle == 0) {
  743. KdPrint(("NWWORKSTATION: Cannot call SetServiceStatus, no status handle.\n"));
  744. return ERROR_INVALID_HANDLE;
  745. }
  746. if (! SetServiceStatus(NwStatusHandle, &NwStatus)) {
  747. status = GetLastError();
  748. KdPrint(("NWWORKSTATION: SetServiceStatus error %lu\n", status));
  749. }
  750. return status;
  751. }
  752. VOID
  753. NwInitializeWkstaInfo(
  754. VOID
  755. )
  756. /*++
  757. Routine Description:
  758. This function reads some workstation info, including the packet burst
  759. size and the provider name. We will ignore all errors that occurred when
  760. reading from the registry and use the default values instead.
  761. Arguments:
  762. None.
  763. Return Value:
  764. None.
  765. --*/
  766. {
  767. DWORD err;
  768. HKEY hkey;
  769. DWORD dwTemp;
  770. DWORD dwSize = sizeof( dwTemp );
  771. LPWSTR pszProviderName = NULL;
  772. //
  773. // Read the Network and Print Provider Name.
  774. //
  775. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  776. // \NWCWorkstation\networkprovider
  777. //
  778. err = RegOpenKeyExW(
  779. HKEY_LOCAL_MACHINE,
  780. REG_WORKSTATION_PROVIDER_PATH,
  781. REG_OPTION_NON_VOLATILE, // options
  782. KEY_READ, // desired access
  783. &hkey
  784. );
  785. if ( !err )
  786. {
  787. //
  788. // Read the network provider name
  789. //
  790. err = NwReadRegValue(
  791. hkey,
  792. REG_PROVIDER_VALUE_NAME,
  793. &pszProviderName
  794. );
  795. if ( !err )
  796. {
  797. wcscpy( NwProviderName, pszProviderName );
  798. (void) LocalFree( (HLOCAL) pszProviderName );
  799. #if DBG
  800. IF_DEBUG(INIT)
  801. {
  802. KdPrint(("\nNWWORKSTATION: Provider Name = %ws\n",
  803. NwProviderName ));
  804. }
  805. #endif
  806. }
  807. RegCloseKey( hkey );
  808. }
  809. if ( err )
  810. {
  811. KdPrint(("Error %d when reading provider name.\n", err ));
  812. }
  813. //
  814. // Read the Packet Burst Size
  815. //
  816. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  817. // \NWCWorkstation\Parameters
  818. //
  819. err = RegOpenKeyExW(
  820. HKEY_LOCAL_MACHINE,
  821. REG_WORKSTATION_PARAMETERS_PATH,
  822. REG_OPTION_NON_VOLATILE, // options
  823. KEY_READ, // desired access
  824. &hkey
  825. );
  826. if ( !err )
  827. {
  828. err = RegQueryValueExW( hkey,
  829. REG_BURST_VALUE_NAME,
  830. NULL,
  831. NULL,
  832. (LPBYTE) &dwTemp,
  833. &dwSize );
  834. if ( !err )
  835. {
  836. NwPacketBurstSize = dwTemp;
  837. #if DBG
  838. IF_DEBUG(INIT)
  839. {
  840. KdPrint(("\nNWWORKSTATION: Packet Burst Size = %d\n",
  841. NwPacketBurstSize ));
  842. }
  843. #endif
  844. }
  845. err = RegQueryValueExW( hkey,
  846. REG_GATEWAY_VALUE_NAME,
  847. NULL,
  848. NULL,
  849. (LPBYTE) &dwTemp,
  850. &dwSize );
  851. if ( !err )
  852. {
  853. NwGatewayPrintOption = dwTemp;
  854. #if DBG
  855. IF_DEBUG(INIT)
  856. {
  857. KdPrint(("\nNWWORKSTATION: Gateway Print Option = %d\n",
  858. NwGatewayPrintOption ));
  859. }
  860. #endif
  861. }
  862. err = RegQueryValueExW( hkey,
  863. REG_GW_NOCONNECT_VALUE_NAME,
  864. NULL,
  865. NULL,
  866. (LPBYTE) &dwTemp,
  867. &dwSize );
  868. if ( !err )
  869. {
  870. if (dwTemp == 1)
  871. GatewayConnectionAlways = FALSE ;
  872. }
  873. RegCloseKey( hkey );
  874. }
  875. //
  876. // Passes the information to the redirector
  877. //
  878. (void) NwRdrSetInfo(
  879. NW_PRINT_OPTION_DEFAULT,
  880. NwPacketBurstSize,
  881. NULL,
  882. 0,
  883. NwProviderName,
  884. ((NwProviderName != NULL) ?
  885. wcslen( NwProviderName) * sizeof( WCHAR ) : 0 )
  886. );
  887. }
  888. DWORD
  889. NwInitializeMessage(
  890. VOID
  891. )
  892. /*++
  893. Routine Description:
  894. This routine opens a handle to the redirector device to receive
  895. server messages and creates a thread to wait for the incoming
  896. messages.
  897. Arguments:
  898. None.
  899. Return Value:
  900. NO_ERROR or reason for failure.
  901. --*/
  902. {
  903. DWORD status;
  904. UNICODE_STRING RdrName;
  905. HKEY hkey;
  906. DWORD dwTemp;
  907. DWORD dwSize = sizeof( dwTemp );
  908. BOOL fDisablePopup = FALSE ;
  909. HANDLE ThreadHandle;
  910. DWORD ThreadId;
  911. //
  912. // Read the Disable Popup Flag. By default it is cleared.
  913. // We only set to TRUE if we find the value.
  914. //
  915. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  916. // \NWCWorkstation\Parameters
  917. //
  918. status = RegOpenKeyExW(
  919. HKEY_LOCAL_MACHINE,
  920. REG_WORKSTATION_PARAMETERS_PATH,
  921. REG_OPTION_NON_VOLATILE, // options
  922. KEY_READ, // desired access
  923. &hkey
  924. );
  925. if ( status == NO_ERROR )
  926. {
  927. status = RegQueryValueExW( hkey,
  928. REG_DISABLEPOPUP_VALUE_NAME,
  929. NULL,
  930. NULL,
  931. (LPBYTE) &dwTemp,
  932. &dwSize );
  933. if ( status == NO_ERROR )
  934. {
  935. fDisablePopup = (dwTemp == 1);
  936. }
  937. RegCloseKey( hkey );
  938. }
  939. if (fDisablePopup)
  940. {
  941. return NO_ERROR ;
  942. }
  943. RtlInitUnicodeString(&RdrName, DD_NWFS_DEVICE_NAME_U);
  944. status = NwMapStatus(
  945. NwCallNtOpenFile(
  946. &NwRdrMessageHandle,
  947. FILE_GENERIC_READ | SYNCHRONIZE,
  948. &RdrName,
  949. 0 // Handle for async call
  950. )
  951. );
  952. if (status != NO_ERROR) {
  953. return status;
  954. }
  955. //
  956. // Create the thread to wait for incoming messages
  957. //
  958. ThreadHandle = CreateThread(
  959. NULL,
  960. 0,
  961. (LPTHREAD_START_ROUTINE) NwMessageThread,
  962. (LPVOID) NwRdrMessageHandle,
  963. 0,
  964. &ThreadId
  965. );
  966. if (ThreadHandle == NULL) {
  967. (void) NtClose(NwRdrMessageHandle);
  968. return GetLastError();
  969. }
  970. return NO_ERROR;
  971. }
  972. VOID
  973. NwShutdownMessage(
  974. VOID
  975. )
  976. {
  977. (void) NtClose(NwRdrMessageHandle);
  978. }
  979. VOID
  980. NwMessageThread(
  981. IN HANDLE RdrHandle
  982. )
  983. {
  984. NTSTATUS getmsg_ntstatus;
  985. IO_STATUS_BLOCK IoStatusBlock;
  986. DWORD ReturnVal, NumEventsToWaitOn ;
  987. HANDLE EventsToWaitOn[3];
  988. //BYTE OutputBuffer[48 * sizeof(WCHAR) + 256 * sizeof(WCHAR)]; //Need more space for terminal server
  989. BYTE OutputBuffer[ 2 * sizeof(ULONG) + 48 * sizeof(WCHAR) + 256 * sizeof(WCHAR)]; // Need space for UID to redirect message to correct user
  990. PNWR_SERVER_MESSAGE ServerMessage = (PNWR_SERVER_MESSAGE) OutputBuffer;
  991. BOOL DoFsctl = TRUE ;
  992. NWWKS_POPUP_DATA LocalPopupData ;
  993. EventsToWaitOn[0] = NwDoneEvent;
  994. EventsToWaitOn[1] = NwPopupEvent;
  995. EventsToWaitOn[2] = RdrHandle;
  996. while (TRUE) {
  997. if (DoFsctl)
  998. {
  999. getmsg_ntstatus = NtFsControlFile(
  1000. RdrHandle,
  1001. NULL,
  1002. NULL,
  1003. NULL,
  1004. &IoStatusBlock,
  1005. FSCTL_NWR_GET_MESSAGE,
  1006. NULL,
  1007. 0,
  1008. OutputBuffer,
  1009. sizeof(OutputBuffer)
  1010. );
  1011. DoFsctl = FALSE ;
  1012. }
  1013. if (NT_SUCCESS(getmsg_ntstatus))
  1014. {
  1015. NumEventsToWaitOn = 3 ;
  1016. }
  1017. else
  1018. {
  1019. NumEventsToWaitOn = 2 ;
  1020. }
  1021. ReturnVal = WaitForMultipleObjects(
  1022. NumEventsToWaitOn,
  1023. EventsToWaitOn,
  1024. FALSE, // Wait for any one
  1025. INFINITE
  1026. );
  1027. switch (ReturnVal) {
  1028. case WAIT_OBJECT_0 :
  1029. //
  1030. // Workstation is terminating. Just die.
  1031. //
  1032. ExitThread(0);
  1033. break;
  1034. case WAIT_OBJECT_0 + 1:
  1035. //
  1036. // We have a popup to do. Grab the data and Set the
  1037. // event so that the structure can be used once more.
  1038. //
  1039. LocalPopupData = PopupData ;
  1040. RtlZeroMemory(&PopupData, sizeof(PopupData)) ;
  1041. if (! SetEvent(NwPopupDoneEvent)) {
  1042. //
  1043. // should not happen
  1044. //
  1045. KdPrint(("NWWORKSTATION: Error setting NwPopupDoneEvent %lu\n",
  1046. GetLastError()));
  1047. ASSERT(FALSE);
  1048. }
  1049. NwDisplayPopup(&LocalPopupData) ;
  1050. break;
  1051. case WAIT_OBJECT_0 + 2:
  1052. {
  1053. NTSTATUS ntstatus ;
  1054. //
  1055. // GET_MESSAGE fsctl completed.
  1056. //
  1057. ntstatus = IoStatusBlock.Status;
  1058. DoFsctl = TRUE ;
  1059. if (ntstatus == STATUS_SUCCESS) {
  1060. NwDisplayMessage(
  1061. ServerMessage->LogonId,
  1062. ServerMessage->Server,
  1063. (LPWSTR) ((UINT_PTR) ServerMessage +
  1064. ServerMessage->MessageOffset)
  1065. );
  1066. }
  1067. else {
  1068. KdPrint(("NWWORKSTATION: GET_MESSAGE fsctl failed %08lx\n", ntstatus));
  1069. }
  1070. break;
  1071. }
  1072. case WAIT_FAILED:
  1073. default:
  1074. //
  1075. // Don't care.
  1076. //
  1077. break;
  1078. }
  1079. }
  1080. }
  1081. VOID
  1082. NwDisplayMessage(
  1083. IN LUID LogonId, /* Need to send to a user station - for terminal server */
  1084. IN LPWSTR Server,
  1085. IN LPWSTR Message
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. This routine puts up a popup message with the text received from
  1090. a server.
  1091. Arguments:
  1092. Server - Supplies the name of the server which the message was
  1093. received from.
  1094. Message - Supplies the message to put up received from the server.
  1095. Return Value:
  1096. None.
  1097. --*/
  1098. {
  1099. HMODULE MessageDll;
  1100. WCHAR Title[128];
  1101. WCHAR Buffer[NW_MAX_POPUP_MESSAGE_LENGTH];
  1102. DWORD MessageLength;
  1103. DWORD CharsToCopy;
  1104. #if DBG
  1105. IF_DEBUG(MESSAGE)
  1106. {
  1107. KdPrint(("Server: (%ws), Message: (%ws)\n", Server, Message));
  1108. }
  1109. #endif
  1110. //
  1111. // Load the netware message file DLL
  1112. //
  1113. MessageDll = LoadLibraryW(NW_EVENT_MESSAGE_FILE);
  1114. if (MessageDll == NULL) {
  1115. return;
  1116. }
  1117. RtlZeroMemory(Buffer, sizeof(Buffer)) ;
  1118. MessageLength = FormatMessageW(
  1119. FORMAT_MESSAGE_FROM_HMODULE,
  1120. (LPVOID) MessageDll,
  1121. fIsWinnt? NW_MESSAGE_TITLE : NW_MESSAGE_TITLE_NTAS,
  1122. 0,
  1123. Title,
  1124. sizeof(Title) / sizeof(WCHAR),
  1125. NULL
  1126. );
  1127. if (MessageLength == 0) {
  1128. KdPrint(("NWWORKSTATION: FormatMessageW of title failed\n"));
  1129. return;
  1130. }
  1131. //
  1132. // Get string from message file to display where the message come
  1133. // from.
  1134. //
  1135. MessageLength = FormatMessageW(
  1136. FORMAT_MESSAGE_FROM_HMODULE |
  1137. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1138. (LPVOID) MessageDll,
  1139. NW_MESSAGE_FROM_SERVER,
  1140. 0,
  1141. Buffer,
  1142. sizeof(Buffer) / sizeof(WCHAR),
  1143. (va_list *) &Server
  1144. );
  1145. if (MessageLength != 0) {
  1146. CharsToCopy = wcslen(Message);
  1147. if (MessageLength + 1 + CharsToCopy > NW_MAX_POPUP_MESSAGE_LENGTH) {
  1148. //
  1149. // Message is too big. Truncate the message.
  1150. //
  1151. CharsToCopy = NW_MAX_POPUP_MESSAGE_LENGTH - (MessageLength + 1);
  1152. }
  1153. wcsncpy(&Buffer[MessageLength], Message, CharsToCopy);
  1154. if (IsTerminalServer()) {
  1155. (void) SendMessageToLogonIdW( LogonId, Buffer, Title );
  1156. } else {
  1157. (void) MessageBeep(MB_ICONEXCLAMATION);
  1158. (void) MessageBoxW(
  1159. NULL,
  1160. Buffer,
  1161. Title,
  1162. MB_OK | MB_SETFOREGROUND |
  1163. MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION
  1164. );
  1165. }
  1166. }
  1167. else {
  1168. KdPrint(("NWWORKSTATION: FormatMessageW failed %lu\n", GetLastError()));
  1169. }
  1170. (void) FreeLibrary(MessageDll);
  1171. }
  1172. VOID
  1173. NwDisplayPopup(
  1174. IN LPNWWKS_POPUP_DATA lpPopupData
  1175. )
  1176. /*++
  1177. Routine Description:
  1178. This routine puts up a popup message for the given Id.
  1179. Arguments:
  1180. MessageId - Supplies the message to put up.
  1181. Return Value:
  1182. None.
  1183. --*/
  1184. {
  1185. HMODULE MessageDll;
  1186. WCHAR Title[128];
  1187. WCHAR Buffer[NW_MAX_POPUP_MESSAGE_LENGTH];
  1188. DWORD MessageLength;
  1189. DWORD i ;
  1190. //
  1191. // Load the netware message file DLL
  1192. //
  1193. MessageDll = LoadLibraryW(NW_EVENT_MESSAGE_FILE);
  1194. if (MessageDll == NULL) {
  1195. return;
  1196. }
  1197. MessageLength = FormatMessageW(
  1198. FORMAT_MESSAGE_FROM_HMODULE,
  1199. (LPVOID) MessageDll,
  1200. NW_MESSAGE_TITLE,
  1201. 0,
  1202. Title,
  1203. sizeof(Title) / sizeof(WCHAR),
  1204. NULL
  1205. );
  1206. if (MessageLength == 0) {
  1207. KdPrint(("NWWORKSTATION: FormatMessageW of title failed\n"));
  1208. return;
  1209. }
  1210. //
  1211. // Get string from message file to display where the message come
  1212. // from.
  1213. //
  1214. MessageLength = FormatMessageW(
  1215. FORMAT_MESSAGE_FROM_HMODULE |
  1216. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1217. (LPVOID) MessageDll,
  1218. lpPopupData->MessageId,
  1219. 0,
  1220. Buffer,
  1221. sizeof(Buffer) / sizeof(WCHAR),
  1222. (va_list *) &(lpPopupData->InsertStrings)
  1223. );
  1224. for (i = 0; i < lpPopupData->InsertCount; i++)
  1225. (void) LocalFree((HLOCAL)lpPopupData->InsertStrings[i]) ;
  1226. if (MessageLength != 0) {
  1227. if (IsTerminalServer()) {
  1228. //--- Multiuser change -----
  1229. (void) SendMessageToLogonIdW( lpPopupData->LogonId, Buffer, Title );
  1230. } else {
  1231. (void) MessageBeep(MB_ICONEXCLAMATION);
  1232. (void) MessageBoxW(
  1233. NULL,
  1234. Buffer,
  1235. Title,
  1236. MB_OK | MB_SETFOREGROUND |
  1237. MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION
  1238. );
  1239. }
  1240. }
  1241. else {
  1242. KdPrint(("NWWORKSTATION: FormatMessageW failed %lu\n", GetLastError()));
  1243. }
  1244. (void) FreeLibrary(MessageDll);
  1245. }
  1246. #if 0
  1247. //
  1248. // This code was needed when we used to have a version of NwLink from MCS
  1249. // that didnt do the sockopts we needed. It used to be called by NwInitialize()
  1250. // and if the check failed, we logged an event
  1251. //
  1252. BOOL
  1253. NwIsNWLinkVersionOK(
  1254. void
  1255. )
  1256. /*++
  1257. Routine Description:
  1258. This routine puts checks if the NWLINK version supports the
  1259. sockopts added for IPX/SPX. if not, barf.
  1260. Arguments:
  1261. None.
  1262. Return Value:
  1263. TRUE is the version is OK, FALSE otherwise.
  1264. --*/
  1265. {
  1266. int err ;
  1267. SOCKET s ;
  1268. WORD VersionRequested ;
  1269. WSADATA wsaData ;
  1270. IPX_NETNUM_DATA buf;
  1271. int buflen = sizeof(buf);
  1272. BOOL NeedCleanup = FALSE ;
  1273. BOOL NeedClose = FALSE ;
  1274. BOOL result = TRUE ;
  1275. VersionRequested = MAKEWORD(1,1) ;
  1276. if (err = WSAStartup(VersionRequested,
  1277. &wsaData))
  1278. {
  1279. //
  1280. // cant even get winsock initialized. this is not a question
  1281. // of wrong version. we will fail later. return TRUE
  1282. //
  1283. result = TRUE ;
  1284. goto ErrorExit ;
  1285. }
  1286. NeedCleanup = TRUE ;
  1287. s = socket(AF_IPX,
  1288. SOCK_DGRAM,
  1289. NSPROTO_IPX
  1290. );
  1291. if (s == INVALID_SOCKET)
  1292. {
  1293. //
  1294. // cant even open socket. this is not a question
  1295. // of wrong version. we will fail later. return TRUE
  1296. //
  1297. result = TRUE ;
  1298. goto ErrorExit ;
  1299. }
  1300. NeedClose = TRUE ;
  1301. if (err = getsockopt(s,
  1302. NSPROTO_IPX,
  1303. IPX_GETNETINFO,
  1304. (char FAR*)&buf,
  1305. &buflen
  1306. ))
  1307. {
  1308. err = WSAGetLastError() ;
  1309. if (err == WSAENOPROTOOPT)
  1310. {
  1311. //
  1312. // we got a no supported call. we know this is OLD
  1313. // return FALSE
  1314. //
  1315. result = FALSE ;
  1316. goto ErrorExit ;
  1317. }
  1318. }
  1319. //
  1320. // everything dandy. return TRUE
  1321. //
  1322. result = TRUE ;
  1323. ErrorExit:
  1324. if (NeedClose)
  1325. closesocket(s) ;
  1326. if (NeedCleanup)
  1327. WSACleanup() ;
  1328. return result ;
  1329. }
  1330. #endif
  1331. DWORD
  1332. NwInitializeCritSects(
  1333. VOID
  1334. )
  1335. {
  1336. static BOOL s_fBeenInitialized;
  1337. DWORD dwError = NO_ERROR;
  1338. BOOL fFirst = FALSE;
  1339. if (!s_fBeenInitialized)
  1340. {
  1341. s_fBeenInitialized = TRUE;
  1342. __try
  1343. {
  1344. //
  1345. // Initialize the critical section to serialize access to
  1346. // NwLogonNotifiedRdr flag. This is also used to serialize
  1347. // access to GetewayLoggedOnFlag
  1348. //
  1349. InitializeCriticalSection( &NwLoggedOnCritSec );
  1350. fFirst = TRUE;
  1351. //
  1352. // Initialize the critical section used by the print provider
  1353. //
  1354. InitializeCriticalSection( &NwPrintCritSec );
  1355. }
  1356. __except(EXCEPTION_EXECUTE_HANDLER)
  1357. {
  1358. //
  1359. // InitializeCriticalSection() can throw an out of memory exception
  1360. //
  1361. KdPrint(("NwInitializeCritSects: Caught exception %d\n",
  1362. GetExceptionCode()));
  1363. if (fFirst)
  1364. {
  1365. DeleteCriticalSection( &NwLoggedOnCritSec );
  1366. }
  1367. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1368. s_fBeenInitialized = FALSE;
  1369. }
  1370. }
  1371. return dwError;
  1372. }
  1373. BOOL
  1374. NwSetupInProgress(
  1375. VOID
  1376. )
  1377. {
  1378. HKEY hKey;
  1379. DWORD dwErr;
  1380. DWORD dwValue;
  1381. DWORD cbValue = sizeof(DWORD);
  1382. dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1383. REG_SETUP_PATH,
  1384. 0,
  1385. KEY_QUERY_VALUE,
  1386. &hKey);
  1387. if (dwErr != ERROR_SUCCESS)
  1388. {
  1389. return FALSE;
  1390. }
  1391. dwErr = RegQueryValueEx(hKey,
  1392. REG_SETUP_VALUE_NAME,
  1393. NULL,
  1394. NULL,
  1395. (LPBYTE) &dwValue,
  1396. &cbValue);
  1397. RegCloseKey(hKey);
  1398. if (dwErr != ERROR_SUCCESS)
  1399. {
  1400. return FALSE;
  1401. }
  1402. return dwValue;
  1403. }
  1404. //
  1405. // Multi-User Addition
  1406. //
  1407. /*****************************************************************************
  1408. *
  1409. * SendMessageToLogonIdW
  1410. *
  1411. * Send the supplied Message to the WinStation of LogonId
  1412. *
  1413. * ENTRY:
  1414. * LogonId (input)
  1415. * LogonId of WinStation to attempt to deliver the message to
  1416. *
  1417. * pMessage (input)
  1418. * Pointer to message
  1419. *
  1420. * pTitle (input)
  1421. * Pointer to title to use for the message box.
  1422. *
  1423. * EXIT:
  1424. * TRUE - Delivered the message
  1425. * FALSE - Could not deliver the message
  1426. *
  1427. ****************************************************************************/
  1428. BOOL
  1429. SendMessageToLogonIdW(
  1430. LUID LogonId,
  1431. LPWSTR pMessage,
  1432. LPWSTR pTitle
  1433. )
  1434. {
  1435. WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN];
  1436. LONG RegError;
  1437. HKEY InteractiveLogonKey;
  1438. HKEY OneLogonKey;
  1439. ULONG TitleLength;
  1440. ULONG MessageLength, Response;
  1441. DWORD status;
  1442. ULONG WinStationId;
  1443. PULONG pWinId = NULL;
  1444. BEEPINPUT BeepStruct;
  1445. HMODULE hwinsta = NULL;
  1446. PWINSTATION_SET_INFORMATION pfnWinStationSetInformation;
  1447. PWINSTATION_SEND_MESSAGE pfnWinStationSendMessage;
  1448. BOOL bStatus = TRUE;
  1449. RegError = RegOpenKeyExW(
  1450. HKEY_LOCAL_MACHINE,
  1451. NW_INTERACTIVE_LOGON_REGKEY,
  1452. REG_OPTION_NON_VOLATILE,
  1453. KEY_READ,
  1454. &InteractiveLogonKey
  1455. );
  1456. if (RegError != ERROR_SUCCESS) {
  1457. KdPrint(("SendMessageToLogonId: RegOpenKeyExW failed: Error %d\n",
  1458. GetLastError()));
  1459. bStatus = FALSE;
  1460. goto Exit;
  1461. }
  1462. NwLuidToWStr(&LogonId, LogonIdKeyName);
  1463. //
  1464. // Open the <LogonIdKeyName> key under Logon
  1465. //
  1466. RegError = RegOpenKeyExW(
  1467. InteractiveLogonKey,
  1468. LogonIdKeyName,
  1469. REG_OPTION_NON_VOLATILE,
  1470. KEY_READ,
  1471. &OneLogonKey
  1472. );
  1473. if ( RegError != ERROR_SUCCESS ) {
  1474. #if DBG
  1475. IF_DEBUG(PRINT)
  1476. KdPrint(("SendMessageToLogonId: RegOpenKeyExW failed, Not interactive Logon: Error %d\n",
  1477. GetLastError()));
  1478. #endif
  1479. (void) RegCloseKey(InteractiveLogonKey);
  1480. bStatus = FALSE;
  1481. goto Exit;
  1482. }
  1483. //
  1484. // Read the WinStation ID value.
  1485. //
  1486. status = NwReadRegValue(
  1487. OneLogonKey,
  1488. NW_WINSTATION_VALUENAME,
  1489. (LPWSTR *) &pWinId
  1490. );
  1491. (void) RegCloseKey(OneLogonKey);
  1492. (void) RegCloseKey(InteractiveLogonKey);
  1493. if (status != NO_ERROR) {
  1494. KdPrint(("NWWORKSTATION: SendMessageToLogonId: Could not read WinStation ID ID from reg %lu\n", status));
  1495. bStatus = FALSE;
  1496. goto Exit;
  1497. } else if (pWinId != NULL) {
  1498. WinStationId = *pWinId;
  1499. (void) LocalFree((HLOCAL) pWinId);
  1500. } else {
  1501. bStatus = FALSE;
  1502. goto Exit;
  1503. }
  1504. if ( WinStationId == 0L ) {
  1505. (void) MessageBeep(MB_ICONEXCLAMATION);
  1506. (void) MessageBoxW(
  1507. NULL,
  1508. pMessage,
  1509. pTitle,
  1510. MB_OK | MB_SETFOREGROUND |
  1511. MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION
  1512. );
  1513. bStatus = TRUE;
  1514. goto Exit;
  1515. }
  1516. /*
  1517. * Beep the WinStation
  1518. */
  1519. BeepStruct.uType = MB_ICONEXCLAMATION;
  1520. /* Nevermind any errors it's just a Beep */
  1521. /*
  1522. * Get handle to winsta.dll
  1523. */
  1524. if ( (hwinsta = LoadLibraryW( L"WINSTA" )) != NULL ) {
  1525. pfnWinStationSetInformation = (PWINSTATION_SET_INFORMATION)
  1526. GetProcAddress( hwinsta, "WinStationSetInformationW" );
  1527. pfnWinStationSendMessage = (PWINSTATION_SEND_MESSAGE)
  1528. GetProcAddress( hwinsta, "WinStationSendMessageW" );
  1529. if (pfnWinStationSetInformation) {
  1530. (void) pfnWinStationSetInformation( SERVERNAME_CURRENT,
  1531. WinStationId,
  1532. WinStationBeep,
  1533. &BeepStruct,
  1534. sizeof( BeepStruct ) );
  1535. }
  1536. if (pfnWinStationSendMessage) {
  1537. // Now attempt to send the message
  1538. TitleLength = (wcslen( pTitle ) + 1) * sizeof(WCHAR);
  1539. MessageLength = (wcslen( pMessage ) + 1) * sizeof(WCHAR);
  1540. if ( !pfnWinStationSendMessage( SERVERNAME_CURRENT,
  1541. WinStationId,
  1542. pTitle,
  1543. TitleLength,
  1544. pMessage,
  1545. MessageLength,
  1546. MB_OK | MB_SETFOREGROUND |
  1547. MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION,
  1548. (ULONG)-1,
  1549. &Response,
  1550. TRUE ) ) {
  1551. bStatus = FALSE;
  1552. goto Exit;
  1553. }
  1554. } else {
  1555. bStatus = FALSE;
  1556. goto Exit;
  1557. }
  1558. }
  1559. Exit:
  1560. if (hwinsta) {
  1561. FreeLibrary(hwinsta);
  1562. }
  1563. return(bStatus);
  1564. }
  1565. BOOL
  1566. NwGetLUIDDeviceMapsEnabled(
  1567. VOID
  1568. )
  1569. /*++
  1570. Routine Description:
  1571. This function calls NtQueryInformationProcess() to determine if
  1572. LUID device maps are enabled
  1573. Arguments:
  1574. none
  1575. Return Value:
  1576. TRUE - LUID device maps are enabled
  1577. FALSE - LUID device maps are disabled
  1578. --*/
  1579. {
  1580. NTSTATUS Status;
  1581. ULONG LUIDDeviceMapsEnabled;
  1582. BOOL Result;
  1583. Status = NtQueryInformationProcess( NtCurrentProcess(),
  1584. ProcessLUIDDeviceMapsEnabled,
  1585. &LUIDDeviceMapsEnabled,
  1586. sizeof(LUIDDeviceMapsEnabled),
  1587. NULL
  1588. );
  1589. if (!NT_SUCCESS( Status )) {
  1590. #if DBG
  1591. IF_DEBUG(PRINT)
  1592. KdPrint(("NwGetLUIDDeviceMapsEnabled: Fail to check LUID DosDevices Enabled: Status 0x%lx\n",
  1593. Status));
  1594. #endif
  1595. Result = FALSE;
  1596. }
  1597. else {
  1598. Result = (LUIDDeviceMapsEnabled != 0);
  1599. }
  1600. return( Result );
  1601. }