diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/nw/svcdlls/nwwks/server/nwmain.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/nw/svcdlls/nwwks/server/nwmain.c')
-rw-r--r-- | private/nw/svcdlls/nwwks/server/nwmain.c | 1570 |
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 ); + +} |