summaryrefslogtreecommitdiffstats
path: root/private/nw/svcdlls/nwwks/server/nwmain.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/svcdlls/nwwks/server/nwmain.c')
-rw-r--r--private/nw/svcdlls/nwwks/server/nwmain.c1570
1 files changed, 1570 insertions, 0 deletions
diff --git a/private/nw/svcdlls/nwwks/server/nwmain.c b/private/nw/svcdlls/nwwks/server/nwmain.c
new file mode 100644
index 000000000..de213bf7a
--- /dev/null
+++ b/private/nw/svcdlls/nwwks/server/nwmain.c
@@ -0,0 +1,1570 @@
+/*++
+
+Copyright (c) 1992-1993 Microsoft Corporation
+
+Module Name:
+
+ nwmain.c
+
+Abstract:
+
+ Main module of the NetWare workstation service.
+
+Author:
+
+ Rita Wong (ritaw) 11-Dec-1992
+
+Environment:
+
+ User Mode - Win32
+
+Revision History:
+
+--*/
+
+#include <nw.h>
+#include <nwreg.h>
+#include <wsipx.h>
+#include <wsnwlink.h>
+#include <nwmisc.h>
+
+
+//------------------------------------------------------------------
+//
+// Local Definitions
+//
+//------------------------------------------------------------------
+
+#define NW_EVENT_MESSAGE_FILE L"nwevent.dll"
+#define NW_MAX_POPUP_MESSAGE_LENGTH 512
+
+#define REG_WORKSTATION_PROVIDER_PATH L"System\\CurrentControlSet\\Services\\NWCWorkstation\\networkprovider"
+#define REG_PROVIDER_VALUE_NAME L"Name"
+
+#define REG_WORKSTATION_PARAMETERS_PATH L"System\\CurrentControlSet\\Services\\NWCWorkstation\\Parameters"
+#define REG_BURST_VALUE_NAME L"MaxBurstSize"
+#define REG_GATEWAY_VALUE_NAME L"GatewayPrintOption"
+#define REG_DISABLEPOPUP_VALUE_NAME L"DisablePopup"
+#define REG_GW_NOCONNECT_VALUE_NAME L"GWDontConnectAtStart"
+
+//
+// QFE release does not have this. so for QFE, we make it a no-op bit.
+//
+#ifdef QFE_BUILD
+#define MB_SERVICE_NOTIFICATION 0
+#endif
+
+//-------------------------------------------------------------------//
+// //
+// Local Function Prototypes //
+// //
+//-------------------------------------------------------------------//
+
+DWORD
+NwInitialize(
+ OUT LPDWORD NwInitState
+ );
+
+VOID
+NwInitializeCritSects(
+ VOID
+ );
+
+VOID
+NwInitializeWkstaInfo(
+ VOID
+ );
+
+DWORD
+NwInitializeMessage(
+ VOID
+ );
+
+BOOL NwShutdownNotify(
+ DWORD dwCtrlType
+ );
+
+VOID
+NwShutdown(
+ IN DWORD ErrorCode,
+ IN DWORD NwInitState
+ );
+
+VOID
+NwShutdownMessage(
+ VOID
+ );
+
+VOID
+NwControlHandler(
+ IN DWORD Opcode
+ );
+
+DWORD
+NwUpdateStatus(
+ VOID
+ );
+
+VOID
+NwMessageThread(
+ IN HANDLE RdrHandle
+ );
+
+VOID
+NwDisplayMessage(
+ IN LPWSTR Server,
+ IN LPWSTR Message
+ );
+
+VOID
+NwDisplayPopup(
+ IN LPNWWKS_POPUP_DATA lpPopupData
+ );
+
+//-------------------------------------------------------------------//
+// //
+// Global variables //
+// //
+//-------------------------------------------------------------------//
+
+//
+// For service control
+//
+STATIC SERVICE_STATUS NwStatus;
+STATIC SERVICE_STATUS_HANDLE NwStatusHandle = (SERVICE_STATUS_HANDLE) NULL;
+HANDLE NwDoneEvent = NULL ;
+
+//
+// For popping up errors.
+//
+HANDLE NwPopupEvent = NULL ;
+HANDLE NwPopupDoneEvent = NULL ;
+NWWKS_POPUP_DATA PopupData ;
+
+//
+// For NTAS vs Winnt
+//
+BOOL fIsWinnt ;
+
+//
+// Flag to control DBCS translations
+//
+
+extern LONG Japan = 0;
+
+//
+// Data global to nwsvc.exe
+//
+PLMSVCS_GLOBAL_DATA NwsvcGlobalData;
+
+//
+// Handle for receiving server messages
+//
+STATIC HANDLE NwRdrMessageHandle;
+
+//
+// Stores the network and print provider name
+//
+WCHAR NwProviderName[MAX_PATH] = L"";
+
+// Stores the packet burst size
+DWORD NwPacketBurstSize = 32 * 1024;
+
+//
+// remember if gateway is logged on
+//
+BOOL GatewayLoggedOn = FALSE ;
+
+//
+// should gateway always take up a connection?
+//
+BOOL GatewayConnectionAlways = TRUE ;
+
+//
+// critical sections used
+//
+CRITICAL_SECTION NwLoggedOnCritSec;
+CRITICAL_SECTION NwPrintCritSec; // protect the linked list of printers
+
+
+//-------------------------------------------------------------------//
+
+
+VOID
+LMSVCS_ENTRY_POINT( // (NWWKS_main)
+ DWORD NumArgs,
+ LPTSTR *ArgsArray,
+ PLMSVCS_GLOBAL_DATA LmsvcsGlobalData,
+ HANDLE SvcRefHandle
+ )
+/*++
+
+Routine Description:
+
+ This is the main entry point of the NetWare workstation service. After
+ the service has been initialized, this thread will wait on NwDoneEvent
+ for a signal to terminate the service.
+
+Arguments:
+
+ NumArgs - Supplies the number of strings specified in ArgsArray.
+
+ ArgsArray - Supplies string arguments that are specified in the
+ StartService API call. This parameter is ignored.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ DWORD NwInitState = 0;
+
+
+ UNREFERENCED_PARAMETER(NumArgs);
+ UNREFERENCED_PARAMETER(ArgsArray);
+ UNREFERENCED_PARAMETER(SvcRefHandle);
+
+ //
+ // Make nwsvc.exe data global to this DLL.
+ //
+ NwsvcGlobalData = LmsvcsGlobalData;
+
+ if (NwInitialize(&NwInitState) != NO_ERROR) {
+ return;
+ }
+
+ //
+ // Wait until we are told to stop.
+ //
+ (void) WaitForSingleObject(
+ NwDoneEvent,
+ INFINITE
+ );
+
+ NwShutdown(
+ NO_ERROR, // Normal termination
+ NwInitState
+ );
+}
+
+
+DWORD
+NwInitialize(
+ OUT LPDWORD NwInitState
+ )
+/*++
+
+Routine Description:
+
+ This function initializes the NetWare workstation service.
+
+Arguments:
+429
+ NwInitState - Returns a flag to indicate how far we got with initializing
+ the service before an error occurred.
+
+Return Value:
+
+ NO_ERROR or reason for failure.
+
+Notes:
+
+ See IMPORTANT NOTE below.
+
+--*/
+{
+ DWORD status;
+ NT_PRODUCT_TYPE ProductType ;
+ LCID lcid;
+
+ //
+ // are we a winnt machine?
+ //
+ fIsWinnt = RtlGetNtProductType(&ProductType) ?
+ (ProductType == NtProductWinNt) :
+ FALSE ;
+
+ //
+ // initialize all our critical sections as soon as we can
+ //
+ NwInitializeCritSects() ;
+
+ //
+ // Initialize all the status fields so that subsequent calls to
+ // SetServiceStatus need to only update fields that changed.
+ //
+ NwStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
+ NwStatus.dwCurrentState = SERVICE_START_PENDING;
+ NwStatus.dwControlsAccepted = 0;
+ NwStatus.dwCheckPoint = 1;
+ NwStatus.dwWaitHint = 5000;
+ NwStatus.dwWin32ExitCode = NO_ERROR;
+ NwStatus.dwServiceSpecificExitCode = 0;
+
+ //
+ // Initialize workstation to receive service requests by registering the
+ // control handler.
+ //
+ if ((NwStatusHandle = RegisterServiceCtrlHandlerW(
+ NW_WORKSTATION_SERVICE,
+ NwControlHandler
+ )) == (SERVICE_STATUS_HANDLE) NULL) {
+
+ status = GetLastError();
+ KdPrint(("NWWORKSTATION: RegisterServiceCtrlHandlerW error %lu\n", status));
+ return status;
+ }
+
+ //
+ // Tell Service Controller that we are start pending.
+ //
+ (void) NwUpdateStatus();
+
+ //
+ // Create events to synchronize message popups
+ //
+ if (((NwPopupEvent = CreateEvent(
+ NULL, // no security descriptor
+ FALSE, // use automatic reset
+ FALSE, // initial state: not signalled
+ NULL // no name
+ )) == NULL)
+ || ((NwPopupDoneEvent = CreateEvent(
+ NULL, // no security descriptor
+ FALSE, // use automatic reset
+ TRUE, // initial state: signalled
+ NULL // no name
+ )) == NULL))
+ {
+
+ status = GetLastError();
+ NwShutdown(status, *NwInitState);
+ return status;
+ }
+
+ //
+ // Create event to synchronize termination
+ //
+ if ((NwDoneEvent = CreateEvent(
+ NULL, // no security descriptor
+ TRUE, // do not use automatic reset
+ FALSE, // initial state: not signalled
+ NULL // no name
+ )) == NULL) {
+
+ status = GetLastError();
+ NwShutdown(status, *NwInitState);
+ return status;
+ }
+ (*NwInitState) |= NW_EVENTS_CREATED;
+
+
+ //
+ // Load the redirector.
+ //
+ if ((status = NwInitializeRedirector()) != NO_ERROR) {
+ NwShutdown(status, *NwInitState);
+ return status;
+ }
+ (*NwInitState) |= NW_RDR_INITIALIZED;
+
+ //
+ // Service still start pending. Update checkpoint to reflect that
+ // we are making progress.
+ //
+ NwStatus.dwCheckPoint++;
+ (void) NwUpdateStatus();
+
+ //
+ // Bind to transports
+ //
+ if ((status = NwBindToTransports()) != NO_ERROR) {
+ NwShutdown(status, *NwInitState);
+ return status;
+ }
+ (*NwInitState) |= NW_BOUND_TO_TRANSPORTS;
+
+ //
+ // Service still start pending. Update checkpoint to reflect that
+ // we are making progress.
+ //
+ NwStatus.dwCheckPoint++;
+ (void) NwUpdateStatus();
+
+ //
+ // Initialize credential management.
+ //
+ NwInitializeLogon();
+
+ //
+ // Setup thread to receive server messages. Even if not successful,
+ // just press on as the workstation is mostly functional.
+ //
+ if ((status = NwInitializeMessage()) == NO_ERROR) {
+ (*NwInitState) |= NW_INITIALIZED_MESSAGE;
+ }
+
+ //
+ // Service still start pending. Update checkpoint to reflect that
+ // we are making progress.
+ //
+ NwStatus.dwCheckPoint++;
+ (void) NwUpdateStatus();
+
+ //
+ // Read some workstation information stored in the registry
+ // and passes some info to the redirector. This has to be
+ // done before opening up the RPC interface.
+ //
+ NwInitializeWkstaInfo();
+
+ //
+ // Initialize the server side print provider.
+ //
+ NwInitializePrintProvider();
+
+ //
+ // Initialize the service provider.
+ //
+ NwInitializeServiceProvider();
+
+ //
+ // Login the Gateway account. if not setup, this is a no-op.
+ // Failures are non fatal.
+ //
+ if ((status = NwGatewayLogon()) == NO_ERROR) {
+ (*NwInitState) |= NW_GATEWAY_LOGON;
+ }
+
+ //
+ // Service still start pending. Update checkpoint to reflect that
+ // we are making progress.
+ //
+ NwStatus.dwCheckPoint++;
+ (void) NwUpdateStatus();
+
+ //
+ // Open up the RPC interface
+ //
+ status = NwsvcGlobalData->StartRpcServer(
+ NwsvcGlobalData->SvcsRpcPipeName,
+ nwwks_ServerIfHandle
+ );
+
+ if (status != NO_ERROR) {
+ NwShutdown(status, *NwInitState);
+ return status;
+ }
+ (*NwInitState) |= NW_RPC_SERVER_STARTED;
+
+ //
+ // Set up the hook to handle computer shut down.
+ //
+ // IMPORTANT NOTE: this is the last step after everything else
+ // has suceeded. When shutdown handler is called, it assumes that
+ // the redir is fully initialized.
+ //
+ if ( !SetConsoleCtrlHandler( NwShutdownNotify, TRUE ))
+ {
+ KdPrint(("SetConsoleCtrlHandler failed with %d\n", GetLastError()));
+ NwShutdown( status, *NwInitState );
+ return GetLastError();
+ }
+
+ //
+ // We are done with workstation startup.
+ //
+ NwStatus.dwCurrentState = SERVICE_RUNNING;
+ NwStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+ NwStatus.dwCheckPoint = 0;
+ NwStatus.dwWaitHint = 0;
+ NwStatus.dwWin32ExitCode = NO_ERROR;
+
+ if ((status = NwUpdateStatus()) != NO_ERROR) {
+ NwShutdown(status, *NwInitState);
+ return status;
+ }
+
+ //
+ // Read user and service logon credentias from the registry, in
+ // case user logged on before workstation was started.
+ // Eg. restart workstation.
+ //
+ NwGetLogonCredential();
+
+
+#if 0
+ //
+ // check that the NWLINK has the right sockopts
+ //
+ // see comment on the actual function
+ //
+ if (!NwIsNWLinkVersionOK())
+ {
+ //
+ // log the error in the event log
+ //
+
+ LPWSTR InsertStrings[1] ;
+
+ NwLogEvent(EVENT_NWWKSTA_WRONG_NWLINK_VERSION,
+ 0,
+ InsertStrings,
+ 0) ;
+ }
+#endif
+
+ //
+ // Check to see if we're in a DBCS environment.
+ //
+ NtQueryDefaultLocale( TRUE, &lcid );
+ Japan = 0;
+ if (PRIMARYLANGID(lcid) == LANG_JAPANESE ||
+ PRIMARYLANGID(lcid) == LANG_KOREAN ||
+ PRIMARYLANGID(lcid) == LANG_CHINESE) {
+
+ Japan = 1;
+ }
+
+ //
+ // Successful initialization
+ //
+ return NO_ERROR;
+}
+
+
+BOOL NwShutdownNotify(
+ IN DWORD dwCtrlType
+ )
+/*++
+
+Routine Description:
+
+ This function is a control handler used in SetConsoleCtrlHandler.
+ We are only interested in CTRL_SHUTDOWN_EVENT. On shutdown, we
+ need to notify redirector to shut down and then delete the
+ CurrentUser key in the registry.
+
+Arguments:
+
+ dwCtrlType - The control type that occurred. We will only
+ process CTRL_SHUTDOWN_EVENT.
+
+Return Value:
+
+ TRUE if we don't want the default or other handlers to be called.
+ FALSE otherwise.
+
+Note:
+
+ This Handler is registered after all the Init steps have completed.
+ As such, it does not check for what state the service is in as it
+ cleans up.
+
+--*/
+{
+ DWORD err;
+
+#if DBG
+ IF_DEBUG(INIT)
+ KdPrint(("NwShutdownNotify\n"));
+#endif
+
+ if ( dwCtrlType != CTRL_SHUTDOWN_EVENT )
+ return TRUE;
+
+ //
+ // stop the RPC server
+ //
+ (void) NwsvcGlobalData->StopRpcServer(nwwks_ServerIfHandle);
+
+ //
+ // get rid of all connections
+ //
+ (void) DeleteAllConnections();
+
+ NwGatewayLogoff() ;
+
+ err = NwShutdownRedirector();
+
+ if ( err != NO_ERROR )
+ KdPrint(("Shut down redirector failed with %d\n", err ));
+#if DBG
+ else
+ {
+ IF_DEBUG(INIT)
+ KdPrint(("NwShutdownRedirector success!\n"));
+ }
+#endif
+
+ //
+ // Delete all logon session information in the registry.
+ //
+ NwDeleteCurrentUser();
+ (void) NwDeleteServiceLogon(NULL);
+
+ return FALSE; // The default handler will terminate the process.
+}
+
+
+VOID
+NwShutdown(
+ IN DWORD ErrorCode,
+ IN DWORD NwInitState
+ )
+/*++
+
+Routine Description:
+
+ This function shuts down the Workstation service.
+
+Arguments:
+
+ ErrorCode - Supplies the error code of the failure
+
+ NwInitState - Supplies a flag to indicate how far we got with initializing
+ the service before an error occurred, thus the amount of clean up
+ needed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+
+ //
+ // Service stop still pending. Update checkpoint counter and the
+ // status with the Service Controller.
+ //
+ (NwStatus.dwCheckPoint)++;
+ (void) NwUpdateStatus();
+
+ if (NwInitState & NW_RPC_SERVER_STARTED) {
+ NwsvcGlobalData->StopRpcServer(nwwks_ServerIfHandle);
+ }
+
+ if (NwInitState & NW_INITIALIZED_MESSAGE) {
+ NwShutdownMessage();
+ }
+
+ if (NwInitState & NW_GATEWAY_LOGON)
+ {
+ (void) NwDeleteRedirections() ;
+ }
+
+ //
+ // Service stop still pending. Update checkpoint counter and the
+ // status with the Service Controller.
+ //
+ (NwStatus.dwCheckPoint)++;
+ (void) NwUpdateStatus();
+
+ if (NwInitState & NW_BOUND_TO_TRANSPORTS) {
+ DeleteAllConnections();
+ NwGatewayLogoff() ;
+ }
+
+ //
+ // Clean up the service provider.
+ //
+ // NwTerminateServiceProvider(); NOT CALLED! This is done at DLL unload time already.
+
+ //
+ // Clean up the server side print provider
+ //
+ NwTerminatePrintProvider();
+
+ //
+ // Service stop still pending. Update checkpoint counter and the
+ // status with the Service Controller.
+ //
+ (NwStatus.dwCheckPoint)++;
+ (void) NwUpdateStatus();
+
+ if (NwInitState & NW_RDR_INITIALIZED) {
+ //
+ // Unload the redirector
+ //
+ status = NwShutdownRedirector();
+ }
+
+ if (NwInitState & NW_EVENTS_CREATED) {
+ //
+ // Close handle to termination event and popup event
+ //
+ if (NwDoneEvent) CloseHandle(NwDoneEvent);
+ if (NwPopupEvent) CloseHandle(NwPopupEvent);
+ if (NwPopupDoneEvent) CloseHandle(NwPopupDoneEvent);
+ }
+
+ //
+ // We are done with cleaning up. Tell Service Controller that we are
+ // stopped.
+ //
+ NwStatus.dwCurrentState = SERVICE_STOPPED;
+ NwStatus.dwControlsAccepted = 0;
+
+ if ((ErrorCode == NO_ERROR) &&
+ (status == ERROR_REDIRECTOR_HAS_OPEN_HANDLES)) {
+ ErrorCode = status;
+ }
+
+ //
+ // Deregister the control handler
+ //
+ (void) SetConsoleCtrlHandler( NwShutdownNotify, FALSE ) ;
+
+ //
+ // BUGBUG: If error is within Win32 error range, assign it to
+ // dwWin32ExitCode field, otherwise assign it to the
+ // dwServiceSpecificExitCode field;
+ //
+ NwStatus.dwWin32ExitCode = ErrorCode;
+ NwStatus.dwServiceSpecificExitCode = 0;
+
+ NwStatus.dwCheckPoint = 0;
+ NwStatus.dwWaitHint = 0;
+
+ (void) NwUpdateStatus();
+}
+
+
+VOID
+NwControlHandler(
+ IN DWORD Opcode
+ )
+/*++
+
+Routine Description:
+
+ This is the service control handler of the Workstation service.
+
+Arguments:
+
+ Opcode - Supplies a value which specifies the action for the
+ service to perform.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ switch (Opcode) {
+
+ case SERVICE_CONTROL_STOP:
+
+ if (NwStatus.dwCurrentState != SERVICE_STOP_PENDING) {
+
+ NwStatus.dwCurrentState = SERVICE_STOP_PENDING;
+ NwStatus.dwCheckPoint = 1;
+ NwStatus.dwWaitHint = 60000;
+
+ //
+ // Send the status response.
+ //
+ (void) NwUpdateStatus();
+
+ if (! SetEvent(NwDoneEvent)) {
+
+ //
+ // Problem with setting event to terminate Workstation
+ // service.
+ //
+ KdPrint(("NWWORKSTATION: Error setting NwDoneEvent %lu\n",
+ GetLastError()));
+
+ ASSERT(FALSE);
+ }
+ return;
+ }
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ break;
+
+ }
+
+ //
+ // Send the status response.
+ //
+ (void) NwUpdateStatus();
+}
+
+
+DWORD
+NwUpdateStatus(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function updates the workstation service status with the Service
+ Controller.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Return code from SetServiceStatus.
+
+--*/
+{
+ DWORD status = NO_ERROR;
+
+
+ if (NwStatusHandle == (SERVICE_STATUS_HANDLE) NULL) {
+ KdPrint(("NWWORKSTATION: Cannot call SetServiceStatus, no status handle.\n"));
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (! SetServiceStatus(NwStatusHandle, &NwStatus)) {
+
+ status = GetLastError();
+
+ KdPrint(("NWWORKSTATION: SetServiceStatus error %lu\n", status));
+ }
+
+ return status;
+}
+
+
+
+VOID
+NwInitializeWkstaInfo(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function reads some workstation info, including the packet burst
+ size and the provider name. We will ignore all errors that occurred when
+ reading from the registry and use the default values instead.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DWORD err;
+ HKEY hkey;
+ DWORD dwTemp;
+ DWORD dwSize = sizeof( dwTemp );
+ LPWSTR pszProviderName = NULL;
+
+ //
+ // Read the Network and Print Provider Name.
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCWorkstation\networkprovider
+ //
+ err = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ REG_WORKSTATION_PROVIDER_PATH,
+ REG_OPTION_NON_VOLATILE, // options
+ KEY_READ, // desired access
+ &hkey
+ );
+
+ if ( !err )
+ {
+ //
+ // Read the network provider name
+ //
+ err = NwReadRegValue(
+ hkey,
+ REG_PROVIDER_VALUE_NAME,
+ &pszProviderName
+ );
+
+ if ( !err )
+ {
+ wcscpy( NwProviderName, pszProviderName );
+ (void) LocalFree( (HLOCAL) pszProviderName );
+
+#if DBG
+ IF_DEBUG(INIT)
+ {
+ KdPrint(("\nNWWORKSTATION: Provider Name = %ws\n",
+ NwProviderName ));
+ }
+#endif
+ }
+
+ RegCloseKey( hkey );
+ }
+
+ if ( err )
+ {
+ KdPrint(("Error %d when reading provider name.\n", err ));
+ }
+
+
+ //
+ // Read the Packet Burst Size
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCWorkstation\Parameters
+ //
+ err = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ REG_WORKSTATION_PARAMETERS_PATH,
+ REG_OPTION_NON_VOLATILE, // options
+ KEY_READ, // desired access
+ &hkey
+ );
+
+ if ( !err )
+ {
+ err = RegQueryValueExW( hkey,
+ REG_BURST_VALUE_NAME,
+ NULL,
+ NULL,
+ (LPBYTE) &dwTemp,
+ &dwSize );
+
+ if ( !err )
+ {
+ NwPacketBurstSize = dwTemp;
+
+#if DBG
+ IF_DEBUG(INIT)
+ {
+ KdPrint(("\nNWWORKSTATION: Packet Burst Size = %d\n",
+ NwPacketBurstSize ));
+ }
+#endif
+ }
+
+ err = RegQueryValueExW( hkey,
+ REG_GATEWAY_VALUE_NAME,
+ NULL,
+ NULL,
+ (LPBYTE) &dwTemp,
+ &dwSize );
+
+ if ( !err )
+ {
+ NwGatewayPrintOption = dwTemp;
+
+#if DBG
+ IF_DEBUG(INIT)
+ {
+ KdPrint(("\nNWWORKSTATION: Gateway Print Option = %d\n",
+ NwGatewayPrintOption ));
+ }
+#endif
+ }
+
+ err = RegQueryValueExW( hkey,
+ REG_GW_NOCONNECT_VALUE_NAME,
+ NULL,
+ NULL,
+ (LPBYTE) &dwTemp,
+ &dwSize );
+
+ if ( !err )
+ {
+ if (dwTemp == 1)
+ GatewayConnectionAlways = FALSE ;
+ }
+
+ RegCloseKey( hkey );
+ }
+
+ //
+ // Passes the information to the redirector
+ //
+ (void) NwRdrSetInfo(
+ NW_PRINT_OPTION_DEFAULT,
+ NwPacketBurstSize,
+ NULL,
+ 0,
+ NwProviderName,
+ ((NwProviderName != NULL) ?
+ wcslen( NwProviderName) * sizeof( WCHAR ) : 0 )
+ );
+
+}
+
+
+
+DWORD
+NwInitializeMessage(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine opens a handle to the redirector device to receive
+ server messages and creates a thread to wait for the incoming
+ messages.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NO_ERROR or reason for failure.
+
+--*/
+{
+ DWORD status;
+ UNICODE_STRING RdrName;
+
+ HKEY hkey;
+ DWORD dwTemp;
+ DWORD dwSize = sizeof( dwTemp );
+ BOOL fDisablePopup = FALSE ;
+
+ HANDLE ThreadHandle;
+ DWORD ThreadId;
+
+ //
+ // Read the Disable Popup Flag. By default it is cleared.
+ // We only set to TRUE if we find the value.
+ //
+ // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
+ // \NWCWorkstation\Parameters
+ //
+ status = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ REG_WORKSTATION_PARAMETERS_PATH,
+ REG_OPTION_NON_VOLATILE, // options
+ KEY_READ, // desired access
+ &hkey
+ );
+
+ if ( status == NO_ERROR )
+ {
+ status = RegQueryValueExW( hkey,
+ REG_DISABLEPOPUP_VALUE_NAME,
+ NULL,
+ NULL,
+ (LPBYTE) &dwTemp,
+ &dwSize );
+
+ if ( status == NO_ERROR )
+ {
+ fDisablePopup = (dwTemp == 1);
+ }
+
+ RegCloseKey( hkey );
+ }
+
+ if (fDisablePopup)
+ {
+ return NO_ERROR ;
+ }
+
+ RtlInitUnicodeString(&RdrName, DD_NWFS_DEVICE_NAME_U);
+
+ status = NwMapStatus(
+ NwCallNtOpenFile(
+ &NwRdrMessageHandle,
+ FILE_GENERIC_READ | SYNCHRONIZE,
+ &RdrName,
+ 0 // Handle for async call
+ )
+ );
+
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ //
+ // Create the thread to wait for incoming messages
+ //
+ ThreadHandle = CreateThread(
+ NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE) NwMessageThread,
+ (LPVOID) NwRdrMessageHandle,
+ 0,
+ &ThreadId
+ );
+
+ if (ThreadHandle == NULL) {
+ (void) NtClose(NwRdrMessageHandle);
+ return GetLastError();
+ }
+
+ return NO_ERROR;
+}
+
+
+VOID
+NwShutdownMessage(
+ VOID
+ )
+{
+ (void) NtClose(NwRdrMessageHandle);
+}
+
+
+VOID
+NwMessageThread(
+ IN HANDLE RdrHandle
+ )
+{
+ NTSTATUS getmsg_ntstatus;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ DWORD ReturnVal, NumEventsToWaitOn ;
+ HANDLE EventsToWaitOn[3];
+
+ BYTE OutputBuffer[48 * sizeof(WCHAR) + 256 * sizeof(WCHAR)];
+ PNWR_SERVER_MESSAGE ServerMessage = (PNWR_SERVER_MESSAGE) OutputBuffer;
+ BOOL DoFsctl = TRUE ;
+ NWWKS_POPUP_DATA LocalPopupData ;
+
+
+ EventsToWaitOn[0] = NwDoneEvent;
+ EventsToWaitOn[1] = NwPopupEvent;
+ EventsToWaitOn[2] = RdrHandle;
+
+ while (TRUE) {
+ if (DoFsctl)
+ {
+ getmsg_ntstatus = NtFsControlFile(
+ RdrHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_GET_MESSAGE,
+ NULL,
+ 0,
+ OutputBuffer,
+ sizeof(OutputBuffer)
+ );
+
+ DoFsctl = FALSE ;
+ }
+
+ if (NT_SUCCESS(getmsg_ntstatus))
+ {
+ NumEventsToWaitOn = 3 ;
+ }
+ else
+ {
+ NumEventsToWaitOn = 2 ;
+ }
+
+ ReturnVal = WaitForMultipleObjects(
+ NumEventsToWaitOn,
+ EventsToWaitOn,
+ FALSE, // Wait for any one
+ INFINITE
+ );
+
+ switch (ReturnVal) {
+
+ case WAIT_OBJECT_0 :
+ //
+ // Workstation is terminating. Just die.
+ //
+ ExitThread(0);
+ break;
+
+ case WAIT_OBJECT_0 + 1:
+ //
+ // We have a popup to do. Grab the data and Set the
+ // event so that the structure can be used once more.
+ //
+ LocalPopupData = PopupData ;
+ RtlZeroMemory(&PopupData, sizeof(PopupData)) ;
+ if (! SetEvent(NwPopupDoneEvent)) {
+ //
+ // should not happen
+ //
+ KdPrint(("NWWORKSTATION: Error setting NwPopupDoneEvent %lu\n",
+ GetLastError()));
+
+ ASSERT(FALSE);
+ }
+
+ NwDisplayPopup(&LocalPopupData) ;
+ break;
+
+ case WAIT_OBJECT_0 + 2:
+ {
+ NTSTATUS ntstatus ;
+
+ //
+ // GET_MESSAGE fsctl completed.
+ //
+ ntstatus = IoStatusBlock.Status;
+ DoFsctl = TRUE ;
+
+ if (ntstatus == STATUS_SUCCESS) {
+ NwDisplayMessage(
+ ServerMessage->Server,
+ (LPWSTR) ((DWORD) ServerMessage +
+ ServerMessage->MessageOffset)
+ );
+ }
+ else {
+ KdPrint(("NWWORKSTATION: GET_MESSAGE fsctl failed %08lx\n", ntstatus));
+ }
+
+ break;
+ }
+
+ case WAIT_FAILED:
+ default:
+ //
+ // Don't care.
+ //
+ break;
+ }
+
+ }
+}
+
+
+VOID
+NwDisplayMessage(
+ IN LPWSTR Server,
+ IN LPWSTR Message
+ )
+/*++
+
+Routine Description:
+
+ This routine puts up a popup message with the text received from
+ a server.
+
+Arguments:
+
+ Server - Supplies the name of the server which the message was
+ received from.
+
+ Message - Supplies the message to put up received from the server.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ HMODULE MessageDll;
+
+ WCHAR Title[128];
+ WCHAR Buffer[NW_MAX_POPUP_MESSAGE_LENGTH];
+
+ DWORD MessageLength;
+ DWORD CharsToCopy;
+
+#if DBG
+ IF_DEBUG(MESSAGE)
+ {
+ KdPrint(("Server: (%ws), Message: (%ws)\n", Server, Message));
+ }
+#endif
+
+ //
+ // Load the netware message file DLL
+ //
+ MessageDll = LoadLibraryW(NW_EVENT_MESSAGE_FILE);
+
+ if (MessageDll == NULL) {
+ return;
+ }
+
+ RtlZeroMemory(Buffer, sizeof(Buffer)) ;
+ MessageLength = FormatMessageW(
+ FORMAT_MESSAGE_FROM_HMODULE,
+ (LPVOID) MessageDll,
+ fIsWinnt? NW_MESSAGE_TITLE : NW_MESSAGE_TITLE_NTAS,
+ 0,
+ Title,
+ sizeof(Title) / sizeof(WCHAR),
+ NULL
+ );
+
+ if (MessageLength == 0) {
+ KdPrint(("NWWORKSTATION: FormatMessageW of title failed\n"));
+ return;
+ }
+
+
+ //
+ // Get string from message file to display where the message come
+ // from.
+ //
+ MessageLength = FormatMessageW(
+ FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ (LPVOID) MessageDll,
+ NW_MESSAGE_FROM_SERVER,
+ 0,
+ Buffer,
+ sizeof(Buffer) / sizeof(WCHAR),
+ (va_list *) &Server
+ );
+
+
+ if (MessageLength != 0) {
+
+ CharsToCopy = wcslen(Message);
+
+ if (MessageLength + 1 + CharsToCopy > NW_MAX_POPUP_MESSAGE_LENGTH) {
+
+ //
+ // Message is too big. Truncate the message.
+ //
+ CharsToCopy = NW_MAX_POPUP_MESSAGE_LENGTH - (MessageLength + 1);
+
+ }
+
+ wcsncpy(&Buffer[MessageLength], Message, CharsToCopy);
+
+ (void) MessageBeep(MB_ICONEXCLAMATION);
+
+ (void) MessageBoxW(
+ NULL,
+ Buffer,
+ Title,
+ MB_OK | MB_SETFOREGROUND |
+ MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION
+ );
+ }
+ else {
+ KdPrint(("NWWORKSTATION: FormatMessageW failed %lu\n", GetLastError()));
+ }
+
+ (void) FreeLibrary(MessageDll);
+}
+
+VOID
+NwDisplayPopup(
+ IN LPNWWKS_POPUP_DATA lpPopupData
+ )
+/*++
+
+Routine Description:
+
+ This routine puts up a popup message for the given Id.
+
+Arguments:
+
+ MessageId - Supplies the message to put up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ HMODULE MessageDll;
+
+ WCHAR Title[128];
+ WCHAR Buffer[NW_MAX_POPUP_MESSAGE_LENGTH];
+
+ DWORD MessageLength;
+ DWORD i ;
+
+ //
+ // Load the netware message file DLL
+ //
+ MessageDll = LoadLibraryW(NW_EVENT_MESSAGE_FILE);
+
+ if (MessageDll == NULL) {
+ return;
+ }
+
+ MessageLength = FormatMessageW(
+ FORMAT_MESSAGE_FROM_HMODULE,
+ (LPVOID) MessageDll,
+ NW_MESSAGE_TITLE,
+ 0,
+ Title,
+ sizeof(Title) / sizeof(WCHAR),
+ NULL
+ );
+
+ if (MessageLength == 0) {
+ KdPrint(("NWWORKSTATION: FormatMessageW of title failed\n"));
+ return;
+ }
+
+
+ //
+ // Get string from message file to display where the message come
+ // from.
+ //
+ MessageLength = FormatMessageW(
+ FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ (LPVOID) MessageDll,
+ lpPopupData->MessageId,
+ 0,
+ Buffer,
+ sizeof(Buffer) / sizeof(WCHAR),
+ (va_list *) &(lpPopupData->InsertStrings)
+ );
+
+ for (i = 0; i < lpPopupData->InsertCount; i++)
+ (void) LocalFree((HLOCAL)lpPopupData->InsertStrings[i]) ;
+
+
+ if (MessageLength != 0) {
+
+ (void) MessageBeep(MB_ICONEXCLAMATION);
+
+ (void) MessageBoxW(
+ NULL,
+ Buffer,
+ Title,
+ MB_OK | MB_SETFOREGROUND |
+ MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION
+ );
+ }
+ else {
+ KdPrint(("NWWORKSTATION: FormatMessageW failed %lu\n", GetLastError()));
+ }
+
+ (void) FreeLibrary(MessageDll);
+}
+
+#if 0
+
+//
+// This code was needed when we used to have a version of NwLink from MCS
+// that didnt do the sockopts we needed. It used to be called by NwInitialize()
+// and if the check failed, we logged an event
+//
+
+BOOL
+NwIsNWLinkVersionOK(
+ void
+ )
+/*++
+
+Routine Description:
+
+ This routine puts checks if the NWLINK version supports the
+ sockopts added for IPX/SPX. if not, barf.
+
+ Arguments:
+
+ None.
+
+ Return Value:
+
+ TRUE is the version is OK, FALSE otherwise.
+
+--*/
+{
+ int err ;
+ SOCKET s ;
+ WORD VersionRequested ;
+ WSADATA wsaData ;
+ IPX_NETNUM_DATA buf;
+ int buflen = sizeof(buf);
+
+ BOOL NeedCleanup = FALSE ;
+ BOOL NeedClose = FALSE ;
+ BOOL result = TRUE ;
+
+ VersionRequested = MAKEWORD(1,1) ;
+
+ if (err = WSAStartup(VersionRequested,
+ &wsaData))
+ {
+ //
+ // cant even get winsock initialized. this is not a question
+ // of wrong version. we will fail later. return TRUE
+ //
+ result = TRUE ;
+ goto ErrorExit ;
+ }
+ NeedCleanup = TRUE ;
+
+ s = socket(AF_IPX,
+ SOCK_DGRAM,
+ NSPROTO_IPX
+ );
+
+ if (s == INVALID_SOCKET)
+ {
+ //
+ // cant even open socket. this is not a question
+ // of wrong version. we will fail later. return TRUE
+ //
+ result = TRUE ;
+ goto ErrorExit ;
+ }
+ NeedClose = TRUE ;
+
+ if (err = getsockopt(s,
+ NSPROTO_IPX,
+ IPX_GETNETINFO,
+ (char FAR*)&buf,
+ &buflen
+ ))
+ {
+ err = WSAGetLastError() ;
+ if (err == WSAENOPROTOOPT)
+ {
+ //
+ // we got a no supported call. we know this is OLD
+ // return FALSE
+ //
+ result = FALSE ;
+ goto ErrorExit ;
+ }
+ }
+
+ //
+ // everything dandy. return TRUE
+ //
+ result = TRUE ;
+
+ErrorExit:
+
+ if (NeedClose)
+ closesocket(s) ;
+ if (NeedCleanup)
+ WSACleanup() ;
+
+ return result ;
+}
+
+#endif
+
+
+VOID
+NwInitializeCritSects(
+ VOID
+ )
+{
+ //
+ // Initialize the critical section to serialize access to
+ // NwLogonNotifiedRdr flag. This is also used to serialize
+ // access to GetewayLoggedOnFlag
+ //
+ InitializeCriticalSection(&NwLoggedOnCritSec);
+
+ //
+ // Initialize the critical section used by the print provider
+ //
+ InitializeCriticalSection( &NwPrintCritSec );
+
+}