449 lines
12 KiB
C++
449 lines
12 KiB
C++
/*++
|
|
|
|
Copyright (c) 1996-1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
remote.cxx
|
|
|
|
Abstract:
|
|
|
|
Process initialization for RPCSS.EXE
|
|
|
|
Author:
|
|
|
|
Satish Thatte [SatishT]
|
|
|
|
--*/
|
|
|
|
#include <or.hxx>
|
|
#include <remact.h>
|
|
#include <userapis.h> // bypass stack switching for USER APIs
|
|
|
|
// Starts the ping thread and rundown thread for remote objects
|
|
DWORD StartObjectExporter();
|
|
|
|
// Inits the shared memory SCM data structures
|
|
HRESULT CheckAndStartSCM(void);
|
|
|
|
extern "C" {
|
|
DWORD StartEndpointMapper(void); // Starts the end point mapper.
|
|
DWORD StartMqManagement(void); // Start MQ Manager Interface.
|
|
};
|
|
|
|
// Declarations for RegisterServiceProcess -- since we don't want to include
|
|
// the 16bit version of windows.h which is the only place this seems to be declared
|
|
|
|
|
|
#define RSP_UNREGISTER_SERVICE 0x00000000
|
|
#define RSP_SIMPLE_SERVICE 0x00000001
|
|
|
|
typedef DWORD
|
|
(APIENTRY *pfRegisterServiceProcess_ROUTINE) ( DWORD dwProcessId,
|
|
DWORD dwType ) ;
|
|
|
|
BOOL StartWin95Service()
|
|
{
|
|
//
|
|
// See KB Q125714 for details about the calls below.
|
|
//
|
|
|
|
//
|
|
// We dynamically load Kernel32.dll to avoid dependence on private libs
|
|
// which export the "internal" RegisterServiceProcess API.
|
|
//
|
|
|
|
HMODULE hMod = LoadLibraryA("kernel32.dll");
|
|
BOOL fResult = FALSE;
|
|
|
|
ASSERT(hMod != NULL);
|
|
|
|
if (hMod)
|
|
{
|
|
pfRegisterServiceProcess_ROUTINE
|
|
pfRegisterServiceProcess = (pfRegisterServiceProcess_ROUTINE)
|
|
GetProcAddress (hMod,"RegisterServiceProcess") ;
|
|
ASSERT(pfRegisterServiceProcess) ;
|
|
|
|
if (pfRegisterServiceProcess)
|
|
{
|
|
fResult = pfRegisterServiceProcess(NULL, RSP_SIMPLE_SERVICE);
|
|
ASSERT(fResult == TRUE) ;
|
|
}
|
|
|
|
FreeLibrary(hMod) ;
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
//
|
|
// Window for messages to RPCSS
|
|
//
|
|
|
|
HWND ghRpcssWnd = NULL;
|
|
|
|
//
|
|
// Handle for RPCSS sync event
|
|
//
|
|
|
|
HANDLE ghSyncEvent = NULL;
|
|
|
|
//
|
|
// paraphernalia for the ping thread
|
|
//
|
|
|
|
HANDLE ghPingThread;
|
|
DWORD gdwThrdId;
|
|
DWORD _stdcall PingThread(void);
|
|
RPC_STATUS StartPingThread();
|
|
BOOL fPingThreadStarted = FALSE;
|
|
|
|
//
|
|
// Window procedure for END session messages
|
|
//
|
|
|
|
LRESULT RpcssWndProc(
|
|
HWND hWnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
switch(message)
|
|
{
|
|
// this case allows RPCSS to clear RPC handles during logoff so that
|
|
// one user's credentials are not used for another -- this should be handled
|
|
// only by the RPCSS process
|
|
case WM_ENDSESSION:
|
|
ClearRPCSSHandles();
|
|
return 0;
|
|
|
|
case WM_RPCSS_MSG:
|
|
{
|
|
CProtectSharedMemory protector; // locks through rest of lexical scope
|
|
|
|
// Init this again
|
|
gpGlobalBlock->InitGlobals(
|
|
FALSE, // we are not creating shared memory
|
|
TRUE // we are reiniting globals from RPCSS
|
|
);
|
|
|
|
BOOL fResult = SetEvent(ghSyncEvent);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
ComDebOut((DEB_ERROR,
|
|
"Failed Signalling RPCSS Sync Event, GetLastError()=%d\n",
|
|
GetLastError()));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
case WM_TIMER:
|
|
// check on status of ping thread -- but make sure the ping thread was
|
|
// started at least once to avoid a race at initialization
|
|
if (fPingThreadStarted && (CTime() - gLastPingTime) > BaseTimeoutInterval)
|
|
{
|
|
// The ping thread is blocked in a ping
|
|
TerminateThread(ghPingThread,0);
|
|
ghPingThread = NULL;
|
|
StartPingThread();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// We don't process the message so pass it on to the default window proc
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
|
|
//
|
|
// Register Window Class and Create Window for END session messages
|
|
//
|
|
|
|
DWORD InitRpcssWindow()
|
|
{
|
|
DWORD dwResult = RPC_S_INTERNAL_ERROR;
|
|
|
|
// Register windows class.
|
|
WNDCLASST xClass;
|
|
xClass.style = 0;
|
|
xClass.lpfnWndProc = RpcssWndProc;
|
|
xClass.cbClsExtra = 0;
|
|
xClass.cbWndExtra = 0;
|
|
xClass.hInstance = g_hinst;
|
|
xClass.hIcon = NULL;
|
|
xClass.hCursor = NULL;
|
|
xClass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);
|
|
xClass.lpszMenuName = NULL;
|
|
xClass.lpszClassName = "RpcssLogoffWindowClass";
|
|
|
|
|
|
|
|
LPTSTR pszRpcssWindowClass = (LPTSTR) RegisterClassT(&xClass);
|
|
|
|
if (pszRpcssWindowClass == 0)
|
|
{
|
|
ComDebOut((DEB_ERROR, "RegisterClass failed in InitRpcssWindow\n"));
|
|
}
|
|
else
|
|
{
|
|
ghRpcssWnd = CreateWindowExA(0,
|
|
pszRpcssWindowClass,
|
|
"RPCSSWindow",
|
|
// must use WS_POPUP so the window does not get
|
|
// assigned a hot key by user.
|
|
(WS_DISABLED | WS_POPUP),
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
g_hinst, // OLE32 DLL's hInstance
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (IsWindow(ghRpcssWnd))
|
|
{
|
|
// set timer for checking ping thread
|
|
UINT ui = SetTimer(ghRpcssWnd, 1234, BaseTimeoutInterval * 1000, NULL);
|
|
|
|
if (ui > 0)
|
|
{
|
|
dwResult = RPC_S_OK;
|
|
}
|
|
}
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
RPC_STATUS
|
|
StartPingThread()
|
|
{
|
|
ghPingThread = CreateThread(
|
|
NULL, 0,
|
|
(LPTHREAD_START_ROUTINE)PingThread,
|
|
NULL, 0, &gdwThrdId);
|
|
|
|
|
|
|
|
if (NULL == ghPingThread)
|
|
{
|
|
ComDebOut((DEB_ERROR,"Creation of Pinging Thread Failed With Error=%d",
|
|
GetLastError()));
|
|
return(RPC_S_INTERNAL_ERROR);
|
|
}
|
|
else
|
|
{
|
|
fPingThreadStarted = TRUE;
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
DWORD __declspec(dllexport) I_RemoteMain(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Main entry point for RPCSS on Win9x.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DWORD DcomStatus = RPC_S_INTERNAL_ERROR,
|
|
EndpointMapperStatus = RPC_S_INTERNAL_ERROR,
|
|
MqStatus = RPC_S_INTERNAL_ERROR,
|
|
RpcssServiceStatus = RPC_S_INTERNAL_ERROR;
|
|
|
|
// Register Authentication Info -- this should be done first before
|
|
// starting the resolver so that the resolver's security initialization
|
|
// is done with this info available
|
|
|
|
// see .\bridge.cxx for implementation
|
|
|
|
// CODEWORK: needs generalization -- probably by eliminating parameter
|
|
// Actually, this needs to be integrated into Connect again
|
|
|
|
// we don't care much about the status returned -- bash on regardless
|
|
RegisterAuthInfoIfNecessary(RPC_C_AUTHN_WINNT);
|
|
|
|
// Register RPCSS as a Win95 service so it will not shut down
|
|
// when the user logs off. This routime will also call InitRpcssWindow
|
|
// to register a window class and create a window to receive the logoff message
|
|
|
|
// This is mainly needed for the MQ Service started below, but we do the registration here
|
|
// since we will shut down naturally if DCOM or the EP mapper does not start properly
|
|
|
|
BOOL fGoodStart = StartWin95Service();
|
|
ASSERT(fGoodStart); // this ought not to fail
|
|
|
|
if (fGoodStart)
|
|
{
|
|
RpcssServiceStatus = RPC_S_OK;
|
|
}
|
|
|
|
// initialize the RPCSS window -- this must succeed for RPCSS
|
|
// to be useful to DCOM, and must be done before starting resolver
|
|
// The window should be destroyed if DCOM fails to start properly
|
|
DcomStatus = InitRpcssWindow();
|
|
|
|
// .\bridge.cxx
|
|
// start the resolver before starting EP mapper so we only get DCOM protocols
|
|
// in the resolver's bindings
|
|
if (DcomStatus == ERROR_SUCCESS)
|
|
{
|
|
DcomStatus = StartObjectExporter();
|
|
}
|
|
|
|
// Start OLESCM
|
|
if (DcomStatus == ERROR_SUCCESS)
|
|
{
|
|
// ..\..\..\olescm\scmsvc.cxx
|
|
DcomStatus = CheckAndStartSCM();
|
|
}
|
|
|
|
// we register the remote activation interface here because
|
|
// Win95's SCM startup does not do it, unlike NT
|
|
if (DcomStatus == ERROR_SUCCESS)
|
|
{
|
|
DcomStatus = RpcServerRegisterIf(_IActivation_ServerIfHandle, 0, 0);
|
|
}
|
|
|
|
// Start endpoint mapper -- this is independent of DcomStatus
|
|
MqStatus = EndpointMapperStatus = StartEndpointMapper();
|
|
|
|
// Start MQ Manager Interface
|
|
if (EndpointMapperStatus == ERROR_SUCCESS)
|
|
{
|
|
// MSMQ depends on the endpoint mapper
|
|
MqStatus = StartMqManagement();
|
|
}
|
|
|
|
|
|
// Start listening for RPC requests -- we start whether or not
|
|
// the resolver and SCM started successfully. This is to avoid
|
|
// failing in situations like: EnableDCOM=Y but Access Control
|
|
// is set to share level. This makes DCOM unusable but not RPC.
|
|
if (EndpointMapperStatus == ERROR_SUCCESS)
|
|
{
|
|
// Always listen to local protocols.
|
|
// If this fails, the EP Mapper service should fail,
|
|
// and RPCSS isn't much use for DCOM either.
|
|
|
|
EndpointMapperStatus = UseProtseqIfNecessary(ID_LPC);
|
|
|
|
if (EndpointMapperStatus != RPC_S_OK)
|
|
{
|
|
return(EndpointMapperStatus);
|
|
}
|
|
|
|
EndpointMapperStatus = UseProtseqIfNecessary(ID_WMSG);
|
|
|
|
if (EndpointMapperStatus != RPC_S_OK)
|
|
{
|
|
return(EndpointMapperStatus);
|
|
}
|
|
else // need special listen for WMSG
|
|
{
|
|
I_RpcServerStartListening(NULL);
|
|
}
|
|
|
|
EndpointMapperStatus = RpcServerListen(1, 1234, TRUE);
|
|
}
|
|
|
|
if (DcomStatus == ERROR_SUCCESS) // resolver/scm started properly
|
|
{
|
|
// start pinging service
|
|
DcomStatus = StartPingThread();
|
|
}
|
|
|
|
if (DcomStatus == ERROR_SUCCESS)
|
|
{
|
|
// We initialized outselves successfully. We can now signal to all
|
|
// interested OLE processes that new values of gpLocalResolver and
|
|
// the security packages
|
|
|
|
ghSyncEvent = CreateEventA(
|
|
NULL, // no security
|
|
TRUE, // stays signalled
|
|
FALSE, // initially, not signalled
|
|
RPCSS_SYNC_EVENT
|
|
);
|
|
|
|
if (ghSyncEvent == NULL)
|
|
{
|
|
DcomStatus = GetLastError();
|
|
|
|
ComDebOut((DEB_ERROR,
|
|
"Failed Creating RPCSS Sync Event, GetLastError()=%d\n",
|
|
DcomStatus));
|
|
}
|
|
else
|
|
{
|
|
BOOL fResult = SetEvent(ghSyncEvent);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
DcomStatus = GetLastError();
|
|
|
|
ComDebOut((DEB_ERROR,
|
|
"Failed Signalling RPCSS Sync Event, GetLastError()=%d\n",
|
|
DcomStatus));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (EndpointMapperStatus != ERROR_SUCCESS ||
|
|
DcomStatus != ERROR_SUCCESS ||
|
|
MqStatus != ERROR_SUCCESS ||
|
|
RpcssServiceStatus != ERROR_SUCCESS)
|
|
{
|
|
ComDebOut((DEB_OXID,"RPCSS startup failed\n"));
|
|
ComDebOut((DEB_OXID,"EndpointMapperStatus = %08x\n", EndpointMapperStatus));
|
|
ComDebOut((DEB_OXID,"DcomStatus = %08x\n", DcomStatus));
|
|
ComDebOut((DEB_OXID,"MqStatus = %08x\n", MqStatus));
|
|
ComDebOut((DEB_OXID,"RpcssServiceStatus = %08x\n", RpcssServiceStatus));
|
|
}
|
|
|
|
if (DcomStatus == ERROR_SUCCESS)
|
|
{
|
|
// we need the message loop for the RPCSS window
|
|
MSG Msg;
|
|
|
|
while (GetMessage(&Msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&Msg);
|
|
DispatchMessage(&Msg);
|
|
}
|
|
}
|
|
else if (EndpointMapperStatus == ERROR_SUCCESS)
|
|
{
|
|
// All we have is the EP mapper, so just wait after we
|
|
// destroy the RPCSS window if it was successfully created
|
|
if (IsWindow(ghRpcssWnd))
|
|
{
|
|
DestroyWindow(ghRpcssWnd);
|
|
ghRpcssWnd = NULL;
|
|
}
|
|
|
|
EndpointMapperStatus = RpcMgmtWaitServerListen();
|
|
}
|
|
|
|
|
|
return EndpointMapperStatus;
|
|
}
|