2027 lines
47 KiB
C
2027 lines
47 KiB
C
|
/*++
|
|||
|
|
|||
|
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>
|
|||
|
#include <winsta.h>
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// GetProcAddr Prototype for winsta.dll function WinStationSetInformationW
|
|||
|
//
|
|||
|
|
|||
|
typedef BOOLEAN (*PWINSTATION_SET_INFORMATION) (
|
|||
|
HANDLE hServer,
|
|||
|
ULONG SessionId,
|
|||
|
WINSTATIONINFOCLASS WinStationInformationClass,
|
|||
|
PVOID pWinStationInformation,
|
|||
|
ULONG WinStationInformationLength
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// GetProcAddr Prototype for winsta.dll function WinStationSendMessageW
|
|||
|
//
|
|||
|
|
|||
|
typedef BOOLEAN
|
|||
|
(*PWINSTATION_SEND_MESSAGE) (
|
|||
|
HANDLE hServer,
|
|||
|
ULONG LogonId,
|
|||
|
LPWSTR pTitle,
|
|||
|
ULONG TitleLength,
|
|||
|
LPWSTR pMessage,
|
|||
|
ULONG MessageLength,
|
|||
|
ULONG Style,
|
|||
|
ULONG Timeout,
|
|||
|
PULONG pResponse,
|
|||
|
BOOLEAN DoNotWait
|
|||
|
);
|
|||
|
//------------------------------------------------------------------
|
|||
|
//
|
|||
|
// 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"
|
|||
|
|
|||
|
#define REG_SETUP_PATH L"System\\Setup"
|
|||
|
#define REG_SETUP_VALUE_NAME L"SystemSetupInProgress"
|
|||
|
|
|||
|
//
|
|||
|
// 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
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
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 LUID LogonId,
|
|||
|
IN LPWSTR Server,
|
|||
|
IN LPWSTR Message
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
NwDisplayPopup(
|
|||
|
IN LPNWWKS_POPUP_DATA lpPopupData
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
SendMessageIfUserW(
|
|||
|
LUID LogonId,
|
|||
|
LPWSTR pMessage,
|
|||
|
LPWSTR pTitle
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
NwSetupInProgress(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
NwGetLUIDDeviceMapsEnabled(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Global variables //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
//
|
|||
|
// For service control
|
|||
|
//
|
|||
|
STATIC SERVICE_STATUS NwStatus;
|
|||
|
STATIC SERVICE_STATUS_HANDLE NwStatusHandle = 0;
|
|||
|
HANDLE NwDoneEvent = NULL ;
|
|||
|
|
|||
|
//
|
|||
|
// For popping up errors.
|
|||
|
//
|
|||
|
HANDLE NwPopupEvent = NULL ;
|
|||
|
HANDLE NwPopupDoneEvent = NULL ;
|
|||
|
NWWKS_POPUP_DATA PopupData ;
|
|||
|
|
|||
|
//
|
|||
|
// For NTAS vs Winnt
|
|||
|
//
|
|||
|
BOOL fIsWinnt = TRUE; // default is this is Workstation (FALSE = Server)
|
|||
|
|
|||
|
//
|
|||
|
// Flag to control DBCS translations
|
|||
|
//
|
|||
|
|
|||
|
extern LONG Japan = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Data global to nwsvc.exe
|
|||
|
//
|
|||
|
PSVCHOST_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
|
|||
|
|
|||
|
BOOL NwLUIDDeviceMapsEnabled;
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
VOID
|
|||
|
SvchostPushServiceGlobals(
|
|||
|
PSVCHOST_GLOBAL_DATA pGlobals
|
|||
|
)
|
|||
|
{
|
|||
|
NwsvcGlobalData = pGlobals;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ServiceMain(
|
|||
|
DWORD NumArgs,
|
|||
|
LPTSTR *ArgsArray
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
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);
|
|||
|
|
|||
|
//
|
|||
|
// Make sure svchost.exe gave us the global data
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(NwsvcGlobalData != NULL);
|
|||
|
|
|||
|
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:
|
|||
|
|
|||
|
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?
|
|||
|
//
|
|||
|
#ifdef GATEWAY_ENABLED
|
|||
|
fIsWinnt = RtlGetNtProductType(&ProductType) ?
|
|||
|
(ProductType == NtProductWinNt) :
|
|||
|
FALSE ;
|
|||
|
#else
|
|||
|
fIsWinnt = TRUE;
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// initialize all our critical sections as soon as we can
|
|||
|
//
|
|||
|
status = NwInitializeCritSects();
|
|||
|
|
|||
|
if (status != NO_ERROR)
|
|||
|
{
|
|||
|
KdPrint(("NWWORKSTATION: NwInitializeCritSects error %lu\n", status));
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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
|
|||
|
)) == 0) {
|
|||
|
|
|||
|
status = GetLastError();
|
|||
|
KdPrint(("NWWORKSTATION: RegisterServiceCtrlHandlerW error %lu\n", status));
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Tell Service Controller that we are start pending.
|
|||
|
//
|
|||
|
(void) NwUpdateStatus();
|
|||
|
|
|||
|
//
|
|||
|
// Don't run during GUI-mode setup (doing so can cause migration of
|
|||
|
// registry keys the service opens to fail, deleting share names)
|
|||
|
//
|
|||
|
if (NwSetupInProgress())
|
|||
|
{
|
|||
|
//
|
|||
|
// Fail silently so there's no Eventlog message to panic the user
|
|||
|
//
|
|||
|
NwShutdown(NO_ERROR, *NwInitState);
|
|||
|
|
|||
|
//
|
|||
|
// Bit of a hack since ServiceMain will wait on the NwDoneEvent
|
|||
|
// (which hasn't yet been created) if NwInitialize returns anything
|
|||
|
// other than NO_ERROR. This error code isn't used for anything
|
|||
|
// other than telling ServiceMain to return without waiting.
|
|||
|
//
|
|||
|
return ERROR_SERVICE_DISABLED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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
|
|||
|
//
|
|||
|
status = NwBindToTransports();
|
|||
|
|
|||
|
//
|
|||
|
// tommye MS 24187 / MCS 255
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// G/CSNW has been unbound in the connection manager and so, we haven't
|
|||
|
// found the linkage key to bind to.
|
|||
|
//
|
|||
|
|
|||
|
if (status == ERROR_INVALID_PARAMETER) {
|
|||
|
|
|||
|
//
|
|||
|
// Fail silently so there's no Eventlog message to panic the user
|
|||
|
//
|
|||
|
|
|||
|
NwShutdown(NO_ERROR, *NwInitState);
|
|||
|
|
|||
|
//
|
|||
|
// Bit of a hack since SvcEntry_NWCS will wait on the NwDoneEvent
|
|||
|
// (which hasn't yet been created) if NwInitialize returns anything
|
|||
|
// other than NO_ERROR. This error code isn't used for anything
|
|||
|
// other than telling SvcEntry_NWCS to return without waiting.
|
|||
|
//
|
|||
|
|
|||
|
return ERROR_SERVICE_DISABLED;
|
|||
|
|
|||
|
} else if (status != 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();
|
|||
|
|
|||
|
//
|
|||
|
// tommye - MS 176469
|
|||
|
//
|
|||
|
// No longer supporting the Gateway - so just force it to be disabled
|
|||
|
//
|
|||
|
|
|||
|
#ifdef GATEWAY_ENABLED
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// 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(
|
|||
|
NWWKS_INTERFACE_NAME,
|
|||
|
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 |
|
|||
|
SERVICE_ACCEPT_SHUTDOWN;
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
NwLUIDDeviceMapsEnabled = NwGetLUIDDeviceMapsEnabled();
|
|||
|
//
|
|||
|
// 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 FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
NwDeleteInteractiveLogon(NULL);
|
|||
|
|
|||
|
(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 ) ;
|
|||
|
|
|||
|
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:
|
|||
|
case SERVICE_CONTROL_SHUTDOWN:
|
|||
|
|
|||
|
if ((NwStatus.dwCurrentState != SERVICE_STOP_PENDING) &&
|
|||
|
(NwStatus.dwCurrentState != SERVICE_STOPPED)){
|
|||
|
|
|||
|
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 == 0) {
|
|||
|
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)]; //Need more space for terminal server
|
|||
|
BYTE OutputBuffer[ 2 * sizeof(ULONG) + 48 * sizeof(WCHAR) + 256 * sizeof(WCHAR)]; // Need space for UID to redirect message to correct user
|
|||
|
|
|||
|
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->LogonId,
|
|||
|
ServerMessage->Server,
|
|||
|
(LPWSTR) ((UINT_PTR) 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 LUID LogonId, /* Need to send to a user station - for terminal server */
|
|||
|
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);
|
|||
|
|
|||
|
if (IsTerminalServer()) {
|
|||
|
(void) SendMessageToLogonIdW( LogonId, Buffer, Title );
|
|||
|
} else {
|
|||
|
(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) {
|
|||
|
if (IsTerminalServer()) {
|
|||
|
//--- Multiuser change -----
|
|||
|
(void) SendMessageToLogonIdW( lpPopupData->LogonId, Buffer, Title );
|
|||
|
} else {
|
|||
|
(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
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
NwInitializeCritSects(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
static BOOL s_fBeenInitialized;
|
|||
|
|
|||
|
DWORD dwError = NO_ERROR;
|
|||
|
BOOL fFirst = FALSE;
|
|||
|
|
|||
|
if (!s_fBeenInitialized)
|
|||
|
{
|
|||
|
s_fBeenInitialized = TRUE;
|
|||
|
|
|||
|
__try
|
|||
|
{
|
|||
|
//
|
|||
|
// Initialize the critical section to serialize access to
|
|||
|
// NwLogonNotifiedRdr flag. This is also used to serialize
|
|||
|
// access to GetewayLoggedOnFlag
|
|||
|
//
|
|||
|
InitializeCriticalSection( &NwLoggedOnCritSec );
|
|||
|
fFirst = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the critical section used by the print provider
|
|||
|
//
|
|||
|
InitializeCriticalSection( &NwPrintCritSec );
|
|||
|
}
|
|||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|||
|
{
|
|||
|
//
|
|||
|
// InitializeCriticalSection() can throw an out of memory exception
|
|||
|
//
|
|||
|
KdPrint(("NwInitializeCritSects: Caught exception %d\n",
|
|||
|
GetExceptionCode()));
|
|||
|
|
|||
|
if (fFirst)
|
|||
|
{
|
|||
|
DeleteCriticalSection( &NwLoggedOnCritSec );
|
|||
|
}
|
|||
|
|
|||
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
|
|||
|
s_fBeenInitialized = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return dwError;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
NwSetupInProgress(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
HKEY hKey;
|
|||
|
DWORD dwErr;
|
|||
|
DWORD dwValue;
|
|||
|
DWORD cbValue = sizeof(DWORD);
|
|||
|
|
|||
|
dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|||
|
REG_SETUP_PATH,
|
|||
|
0,
|
|||
|
KEY_QUERY_VALUE,
|
|||
|
&hKey);
|
|||
|
|
|||
|
if (dwErr != ERROR_SUCCESS)
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
dwErr = RegQueryValueEx(hKey,
|
|||
|
REG_SETUP_VALUE_NAME,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
(LPBYTE) &dwValue,
|
|||
|
&cbValue);
|
|||
|
|
|||
|
RegCloseKey(hKey);
|
|||
|
|
|||
|
if (dwErr != ERROR_SUCCESS)
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return dwValue;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Multi-User Addition
|
|||
|
//
|
|||
|
/*****************************************************************************
|
|||
|
*
|
|||
|
* SendMessageToLogonIdW
|
|||
|
*
|
|||
|
* Send the supplied Message to the WinStation of LogonId
|
|||
|
*
|
|||
|
* ENTRY:
|
|||
|
* LogonId (input)
|
|||
|
* LogonId of WinStation to attempt to deliver the message to
|
|||
|
*
|
|||
|
* pMessage (input)
|
|||
|
* Pointer to message
|
|||
|
*
|
|||
|
* pTitle (input)
|
|||
|
* Pointer to title to use for the message box.
|
|||
|
*
|
|||
|
* EXIT:
|
|||
|
* TRUE - Delivered the message
|
|||
|
* FALSE - Could not deliver the message
|
|||
|
*
|
|||
|
****************************************************************************/
|
|||
|
|
|||
|
BOOL
|
|||
|
SendMessageToLogonIdW(
|
|||
|
LUID LogonId,
|
|||
|
LPWSTR pMessage,
|
|||
|
LPWSTR pTitle
|
|||
|
)
|
|||
|
{
|
|||
|
WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN];
|
|||
|
LONG RegError;
|
|||
|
HKEY InteractiveLogonKey;
|
|||
|
HKEY OneLogonKey;
|
|||
|
ULONG TitleLength;
|
|||
|
ULONG MessageLength, Response;
|
|||
|
DWORD status;
|
|||
|
ULONG WinStationId;
|
|||
|
PULONG pWinId = NULL;
|
|||
|
BEEPINPUT BeepStruct;
|
|||
|
HMODULE hwinsta = NULL;
|
|||
|
PWINSTATION_SET_INFORMATION pfnWinStationSetInformation;
|
|||
|
PWINSTATION_SEND_MESSAGE pfnWinStationSendMessage;
|
|||
|
BOOL bStatus = TRUE;
|
|||
|
|
|||
|
RegError = RegOpenKeyExW(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
NW_INTERACTIVE_LOGON_REGKEY,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_READ,
|
|||
|
&InteractiveLogonKey
|
|||
|
);
|
|||
|
|
|||
|
if (RegError != ERROR_SUCCESS) {
|
|||
|
KdPrint(("SendMessageToLogonId: RegOpenKeyExW failed: Error %d\n",
|
|||
|
GetLastError()));
|
|||
|
bStatus = FALSE;
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
NwLuidToWStr(&LogonId, LogonIdKeyName);
|
|||
|
|
|||
|
//
|
|||
|
// Open the <LogonIdKeyName> key under Logon
|
|||
|
//
|
|||
|
RegError = RegOpenKeyExW(
|
|||
|
InteractiveLogonKey,
|
|||
|
LogonIdKeyName,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_READ,
|
|||
|
&OneLogonKey
|
|||
|
);
|
|||
|
|
|||
|
if ( RegError != ERROR_SUCCESS ) {
|
|||
|
#if DBG
|
|||
|
IF_DEBUG(PRINT)
|
|||
|
KdPrint(("SendMessageToLogonId: RegOpenKeyExW failed, Not interactive Logon: Error %d\n",
|
|||
|
GetLastError()));
|
|||
|
#endif
|
|||
|
(void) RegCloseKey(InteractiveLogonKey);
|
|||
|
bStatus = FALSE;
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read the WinStation ID value.
|
|||
|
//
|
|||
|
status = NwReadRegValue(
|
|||
|
OneLogonKey,
|
|||
|
NW_WINSTATION_VALUENAME,
|
|||
|
(LPWSTR *) &pWinId
|
|||
|
);
|
|||
|
|
|||
|
(void) RegCloseKey(OneLogonKey);
|
|||
|
(void) RegCloseKey(InteractiveLogonKey);
|
|||
|
|
|||
|
if (status != NO_ERROR) {
|
|||
|
KdPrint(("NWWORKSTATION: SendMessageToLogonId: Could not read WinStation ID ID from reg %lu\n", status));
|
|||
|
bStatus = FALSE;
|
|||
|
goto Exit;
|
|||
|
} else if (pWinId != NULL) {
|
|||
|
WinStationId = *pWinId;
|
|||
|
(void) LocalFree((HLOCAL) pWinId);
|
|||
|
} else {
|
|||
|
bStatus = FALSE;
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
if ( WinStationId == 0L ) {
|
|||
|
(void) MessageBeep(MB_ICONEXCLAMATION);
|
|||
|
|
|||
|
(void) MessageBoxW(
|
|||
|
NULL,
|
|||
|
pMessage,
|
|||
|
pTitle,
|
|||
|
MB_OK | MB_SETFOREGROUND |
|
|||
|
MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION
|
|||
|
);
|
|||
|
bStatus = TRUE;
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Beep the WinStation
|
|||
|
*/
|
|||
|
BeepStruct.uType = MB_ICONEXCLAMATION;
|
|||
|
|
|||
|
/* Nevermind any errors it's just a Beep */
|
|||
|
|
|||
|
/*
|
|||
|
* Get handle to winsta.dll
|
|||
|
*/
|
|||
|
if ( (hwinsta = LoadLibraryW( L"WINSTA" )) != NULL ) {
|
|||
|
|
|||
|
pfnWinStationSetInformation = (PWINSTATION_SET_INFORMATION)
|
|||
|
GetProcAddress( hwinsta, "WinStationSetInformationW" );
|
|||
|
|
|||
|
pfnWinStationSendMessage = (PWINSTATION_SEND_MESSAGE)
|
|||
|
GetProcAddress( hwinsta, "WinStationSendMessageW" );
|
|||
|
|
|||
|
if (pfnWinStationSetInformation) {
|
|||
|
(void) pfnWinStationSetInformation( SERVERNAME_CURRENT,
|
|||
|
WinStationId,
|
|||
|
WinStationBeep,
|
|||
|
&BeepStruct,
|
|||
|
sizeof( BeepStruct ) );
|
|||
|
}
|
|||
|
|
|||
|
if (pfnWinStationSendMessage) {
|
|||
|
|
|||
|
// Now attempt to send the message
|
|||
|
|
|||
|
TitleLength = (wcslen( pTitle ) + 1) * sizeof(WCHAR);
|
|||
|
MessageLength = (wcslen( pMessage ) + 1) * sizeof(WCHAR);
|
|||
|
|
|||
|
if ( !pfnWinStationSendMessage( SERVERNAME_CURRENT,
|
|||
|
WinStationId,
|
|||
|
pTitle,
|
|||
|
TitleLength,
|
|||
|
pMessage,
|
|||
|
MessageLength,
|
|||
|
MB_OK | MB_SETFOREGROUND |
|
|||
|
MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION,
|
|||
|
(ULONG)-1,
|
|||
|
&Response,
|
|||
|
TRUE ) ) {
|
|||
|
|
|||
|
bStatus = FALSE;
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
} else {
|
|||
|
bStatus = FALSE;
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
}
|
|||
|
Exit:
|
|||
|
|
|||
|
if (hwinsta) {
|
|||
|
FreeLibrary(hwinsta);
|
|||
|
}
|
|||
|
return(bStatus);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
NwGetLUIDDeviceMapsEnabled(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function calls NtQueryInformationProcess() to determine if
|
|||
|
LUID device maps are enabled
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - LUID device maps are enabled
|
|||
|
|
|||
|
FALSE - LUID device maps are disabled
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG LUIDDeviceMapsEnabled;
|
|||
|
BOOL Result;
|
|||
|
|
|||
|
Status = NtQueryInformationProcess( NtCurrentProcess(),
|
|||
|
ProcessLUIDDeviceMapsEnabled,
|
|||
|
&LUIDDeviceMapsEnabled,
|
|||
|
sizeof(LUIDDeviceMapsEnabled),
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
#if DBG
|
|||
|
IF_DEBUG(PRINT)
|
|||
|
KdPrint(("NwGetLUIDDeviceMapsEnabled: Fail to check LUID DosDevices Enabled: Status 0x%lx\n",
|
|||
|
Status));
|
|||
|
#endif
|
|||
|
|
|||
|
Result = FALSE;
|
|||
|
}
|
|||
|
else {
|
|||
|
Result = (LUIDDeviceMapsEnabled != 0);
|
|||
|
}
|
|||
|
|
|||
|
return( Result );
|
|||
|
}
|
|||
|
|