314 lines
8.9 KiB
C++
314 lines
8.9 KiB
C++
//+-----------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1991 - 1992
|
|
//
|
|
// File: scmsvc.cxx
|
|
//
|
|
// Contents: Initialization for win32 service controller.
|
|
//
|
|
// History: 14-Jul-92 CarlH Created.
|
|
// 31-Dec-93 ErikGav Chicago port
|
|
// 25-Aug-99 a-sergiv Fixed ScmCreatedEvent vulnerability
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
#include "act.hxx"
|
|
|
|
#ifdef DFSACTIVATION
|
|
HANDLE ghDfs = 0;
|
|
#endif
|
|
|
|
#define SCM_CREATED_EVENT TEXT("ScmCreatedEvent")
|
|
|
|
DECLARE_INFOLEVEL(Cairole);
|
|
|
|
extern CRITICAL_SECTION ShellQueryCS;
|
|
|
|
SC_HANDLE g_hServiceController = 0;
|
|
PSID psidMySid = NULL;
|
|
|
|
#if DBG
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SetScmDefaultInfoLevel
|
|
//
|
|
// Synopsis: Sets the default infolevel for the SCM
|
|
//
|
|
// History: 07-Jan-94 Ricksa Created
|
|
//
|
|
// Notes: Uses standard place in win.ini defined by KevinRo but
|
|
// does not use the same value as compob32.dll so you don't
|
|
// have to get all the debugging in the universe just to
|
|
// get the SCM's debug output.
|
|
//
|
|
// A second point is that we don't use unicode here because
|
|
// it is just easier to avoid the unicode headache with
|
|
// mulitple builds between chicago and nt
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
char *pszInfoLevelSectionName = "Cairo InfoLevels";
|
|
char *pszInfoLevelName = "scm";
|
|
char *pszInfoLevelDefault = "$";
|
|
|
|
#define INIT_VALUE_SIZE 16
|
|
void SetScmDefaultInfoLevel(void)
|
|
{
|
|
char aszInitValue[INIT_VALUE_SIZE];
|
|
|
|
ULONG ulRet;
|
|
|
|
ulRet = GetProfileStringA(pszInfoLevelSectionName,
|
|
pszInfoLevelName,
|
|
pszInfoLevelDefault,
|
|
aszInitValue,
|
|
INIT_VALUE_SIZE);
|
|
|
|
if ((ulRet != INIT_VALUE_SIZE - 1) && (aszInitValue[0] != L'$'))
|
|
{
|
|
if((ulRet = strtoul(aszInitValue, NULL, 16)) == 1)
|
|
{
|
|
CairoleInfoLevel = ulRet;
|
|
}
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: InitializeSCMBeforeListen
|
|
//
|
|
// Synopsis: Initializes OLE side of rpcss. Put things in here that do
|
|
// not depend on RPC being initialized, etc.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: Status of initialization. Note that this function is a bit
|
|
// weak on cleanup in the face of errors, but this is okay since if this
|
|
// function fails, RPCSS will not start.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
InitializeSCMBeforeListen( void )
|
|
{
|
|
LONG Status;
|
|
SCODE sc;
|
|
RPC_STATUS rs;
|
|
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
UpdateState(SERVICE_START_PENDING);
|
|
|
|
Status = RtlInitializeCriticalSection(&gTokenCS);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
Status = RtlInitializeCriticalSection(&ShellQueryCS);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
// Allocate locks
|
|
Status = OR_NOMEM;
|
|
gpClientLock = new CSharedLock(Status);
|
|
if (OR_OK != Status)
|
|
return(Status);
|
|
|
|
Status = OR_NOMEM;
|
|
gpServerLock = new CSharedLock(Status);
|
|
if (OR_OK != Status)
|
|
return(Status);
|
|
|
|
Status = OR_NOMEM;
|
|
gpIPCheckLock = new CSharedLock(Status);
|
|
if (OR_OK != Status)
|
|
return(Status);
|
|
|
|
g_hServiceController = OpenSCManager(NULL, NULL, GENERIC_EXECUTE);
|
|
if (!g_hServiceController)
|
|
return GetLastError();
|
|
|
|
//
|
|
// Get my sid
|
|
// This is simplified under the assumption that SCM runs as LocalSystem.
|
|
// We should remove this code when we incorporate OLE service into the
|
|
// Service Control Manager since this becomes duplicated code then.
|
|
//
|
|
Status = RtlAllocateAndInitializeSid (
|
|
&NtAuthority,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&psidMySid
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
UpdateState(SERVICE_START_PENDING);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = InitSCMRegistry();
|
|
if (FAILED(hr))
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
//Initialize runas cache
|
|
InitRunAsCache(); // returns void
|
|
|
|
gpClassLock = new CSharedLock(Status);
|
|
if (!gpClassLock)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
gpProcessLock = new CSharedLock(Status);
|
|
if (!gpProcessLock)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
gpProcessListLock = new CSharedLock(Status);
|
|
if (!gpProcessListLock)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
gpClassTable = new CServerTable(Status, ENTRY_TYPE_CLASS);
|
|
if (!gpClassTable)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
gpProcessTable = new CServerTable(Status, ENTRY_TYPE_PROCESS);
|
|
if (!gpProcessTable)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
gpSurrogateList = new CSurrogateList();
|
|
if (!gpSurrogateList)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
gpRemoteMachineLock = new CSharedLock(Status);
|
|
if (!gpRemoteMachineLock)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
gpRemoteMachineList = new CRemoteMachineList();
|
|
if (!gpRemoteMachineList)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
UpdateState(SERVICE_START_PENDING);
|
|
|
|
#ifdef DFSACTIVATION
|
|
DfsOpen( &ghDfs );
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: InitializeSCM
|
|
//
|
|
// Synopsis: Initializes OLE side of rpcss.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: ERROR_SUCCESS
|
|
//
|
|
// (REVIEW: should we be returning an error whenever any of
|
|
// the stuff in this function fails?)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
InitializeSCM( void )
|
|
{
|
|
LONG Status;
|
|
SCODE sc;
|
|
RPC_STATUS rs;
|
|
HRESULT hr;
|
|
|
|
// start the RPC service
|
|
hr = InitScmRot();
|
|
if (FAILED(hr))
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
sc = RpcServerRegisterIf(ISCM_ServerIfHandle, 0, 0);
|
|
Win4Assert((sc == 0) && "RpcServerRegisterIf failed!");
|
|
|
|
sc = RpcServerRegisterIf(ISCMActivator_ServerIfHandle, 0, 0);
|
|
Win4Assert((sc == 0) && "RpcServerRegisterIf failed!");
|
|
|
|
sc = RpcServerRegisterIf(IMachineActivatorControl_ServerIfHandle, 0, 0);
|
|
Win4Assert((sc == 0) && "RpcServerRegisterIf failed!");
|
|
|
|
sc = RpcServerRegisterIf(_IActivation_ServerIfHandle, 0, 0);
|
|
Win4Assert((sc == 0) && "RpcServerRegisterIf failed!");
|
|
|
|
sc = RpcServerRegisterIf(_IRemoteSCMActivator_ServerIfHandle, 0, 0);
|
|
Win4Assert((sc == 0) && "RpcServerRegisterIf failed!");
|
|
|
|
UpdateState(SERVICE_START_PENDING);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
void
|
|
InitializeSCMAfterListen()
|
|
{
|
|
//
|
|
// This is for the OLE apps which start during boot. They must wait for
|
|
// rpcss to start before completing OLE calls that talk to rpcss.
|
|
//
|
|
// Need to do this work to make sure the DACL for the event doesn't have
|
|
// WRITE_DAC and WRITE_OWNER on it.
|
|
//
|
|
SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_WORLD_SID_AUTHORITY;
|
|
PSID pSidEveryone = NULL;
|
|
PACL pAcl = NULL;
|
|
DWORD cbAcl = 0;
|
|
|
|
AllocateAndInitializeSid(&SidAuthority, 1, SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0, &pSidEveryone);
|
|
|
|
if(pSidEveryone)
|
|
{
|
|
cbAcl = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(pSidEveryone);
|
|
pAcl = (PACL) LocalAlloc(LMEM_FIXED, cbAcl);
|
|
|
|
if(pAcl)
|
|
{
|
|
InitializeAcl(pAcl, cbAcl, ACL_REVISION);
|
|
AddAccessAllowedAce(pAcl, ACL_REVISION, EVENT_QUERY_STATE|EVENT_MODIFY_STATE|SYNCHRONIZE|READ_CONTROL, pSidEveryone);
|
|
}
|
|
}
|
|
|
|
// Create security descriptor and attach the DACL to it
|
|
SECURITY_DESCRIPTOR sd;
|
|
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
|
|
SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE);
|
|
|
|
SECURITY_ATTRIBUTES sa;
|
|
sa.nLength = sizeof(sa);
|
|
sa.bInheritHandle = FALSE;
|
|
sa.lpSecurityDescriptor = &sd;
|
|
|
|
HANDLE EventHandle;
|
|
RPC_STATUS rpcstatus;
|
|
|
|
EventHandle = CreateEventT( &sa, TRUE, FALSE, SCM_CREATED_EVENT );
|
|
|
|
if ( !EventHandle && GetLastError() == ERROR_ACCESS_DENIED )
|
|
EventHandle = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, SCM_CREATED_EVENT);
|
|
|
|
if ( EventHandle )
|
|
SetEvent( EventHandle );
|
|
else
|
|
ASSERT(0 && "Unable to get ScmCreatedEvent");
|
|
|
|
if (pSidEveryone)
|
|
FreeSid(pSidEveryone);
|
|
if (pAcl)
|
|
LocalFree(pAcl);
|
|
|
|
// Tell RPC to enable cleanup of idle connections. This function only needs to be
|
|
// called one time.
|
|
rpcstatus = RpcMgmtEnableIdleCleanup();
|
|
ASSERT(rpcstatus == RPC_S_OK && "unexpected failure from RpcMgmtEnableIdleCleanup");
|
|
// don't fail in free builds, this is an non-essential optimization
|
|
|
|
return;
|
|
}
|