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.

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