2025-04-27 07:49:33 -04:00

1080 lines
24 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996-1997 Microsoft Corporation
Module Name:
Manager.cxx
Abstract:
InProc OR entry points
Author:
Satish Thatte [SatishT] Feb-07-1996
--*/
#include <or.hxx>
//
// Update the channel hook list if it has changed in the registry.
//
void UpdateChannelHooks( LONG *pcChannelHook, GUID **paChannelHook )
{
DWORD cChannelHook = gpSecVals->s_cChannelHook;
if (cChannelHook == 0)
{
*pcChannelHook = 0;
*paChannelHook = NULL;
return;
}
GUID * aChannelHook = gpSecVals->s_aChannelHook;
// Return the channel hook list.
*paChannelHook = (GUID *) MIDL_user_allocate(cChannelHook * sizeof(GUID));
if (*paChannelHook != NULL)
{
*pcChannelHook = cChannelHook;
memcpy(*paChannelHook, aChannelHook, cChannelHook * sizeof(GUID));
}
else
*pcChannelHook = 0;
}
//
// Manager (server-side) calls to the local OR interface. lclor.idl
//
error_status_t
ConnectDCOM(
IN OUT HPROCESS *phProcess,
OUT ULONG *pdwTimeoutInSeconds,
OUT MID *pLocalMid,
OUT ULONG *pfConnectFlags,
OUT DWORD *pAuthnLevel,
OUT DWORD *pImpLevel,
OUT DWORD *pThreadID
)
{
CProcess *hProcess;
*phProcess = NULL; // in case of failure
ORSTATUS status = StartDCOM();
if (status != OR_OK)
{
if (status != OR_I_REPEAT_START)
{
return status;
}
else
{
status = OR_OK;
}
}
*pdwTimeoutInSeconds = BaseTimeoutInterval;
*pLocalMid = gLocalMID;
// Fill in security parameters.
*pfConnectFlags = 0;
if (gpSecVals->s_fEnableDCOM == FALSE) *pfConnectFlags |= CONNECT_DISABLEDCOM;
if (gpSecVals->s_fMutualAuth) *pfConnectFlags |= CONNECT_MUTUALAUTH;
if (gpSecVals->s_fSecureRefs) *pfConnectFlags |= CONNECT_SECUREREF;
*pAuthnLevel = gpSecVals->s_lAuthnLevel;
*pImpLevel = gpSecVals->s_lImpLevel;
if (status != OR_OK) return status;
CProtectSharedMemory protector; // locks through rest of lexical scope
*pThreadID = (*gpNextThreadID)++;
hProcess = new CProcess(
AllocateId()
);
if (hProcess)
{
gpProcess = *phProcess = hProcess;
status = gpProcessTable->Add(hProcess); // BUGBUG: and rundown an old process,
// if there is one, with the same _processID
}
else
{
status = OR_NOMEM;
}
OrDbgDetailPrint(("OR: Client connected\n"));
CheckORdata();
return(status);
}
void UninitializeGlobals(); // private routine for resources release
error_status_t Disconnect(
IN OUT HPROCESS *phProcess
)
{
ASSERT(*phProcess!=NULL);
CProcess *hProcess = *phProcess;
{
CProtectSharedMemory protector; // locks through rest of lexical scope
// special scope needed since we delete
// the global mutex immediately after
CheckORdata(); // DBG only
// run down context handle for current process
hProcess->Rundown();
gpProcessTable->Remove(*hProcess);
*phProcess = NULL;
// Do this before uninitializing globals!
CheckORdata(); // DBG only
// this does not delete gpMutex since we are holding it
// however, it sets gpMutex to NULL so no other thread can
// take it in this process
UninitializeGlobals(); // release global resources
}
return OR_OK;
}
error_status_t
AllocateReservedIds(
IN LONG cIdsToReserve,
OUT ID *pidReservedBase
)
/*++
Routine Description:
Called by local clients to reserve a range of IDs which will
not conflict with any other local IDs.
Arguments:
cIdsToReserve - Number of IDs to reserve.
pidReservedBase - Starting value of the reserved IDs. The
lower DWORD of this can be increatmented to generate
cIdsToReserve unique IDs.
Return Value:
OR_OK
--*/
{
UINT type;
if (cIdsToReserve > 10 || cIdsToReserve < 0)
{
cIdsToReserve = 10;
}
CProtectSharedMemory protector; // locks through rest of lexical scope
CheckORdata();
*pidReservedBase = AllocateId(cIdsToReserve);
CheckORdata();
return(OR_OK);
}
//
// simple helper
//
// this is needed because if a 16 bit app is the first to initialize DCOM,
// a temporary empty DSA for the local OR is created because remote protocols
// cannot be initialized. The temporary DSA must still be honored after a
// 32 bit app has reinitialized the DSA for the local OR to its true value
//
BOOL IsLocalDSA(
DUALSTRINGARRAY *pdsaServerObjectResolverBindings
)
{
// special case the NULL binding -- this may be left over from before
// remote init and thus may not be in the table
if (dsaCompare(gpLocalDSA,pdsaServerObjectResolverBindings) ||
pdsaServerObjectResolverBindings->wNumEntries == 4) // NULL DSA grandfathered in
{
return TRUE;
}
else
{
return FALSE;
}
}
handle_t remote_resolve_handle; // handle for RPCSS RemoteResolveOXID call
UCHAR * RpcssStringBinding = (UCHAR *) "ncalrpc:[epmapper]\0";
// Helper to initialize the remote_resolve_handle
RPC_STATUS
InitResolveHandleIfNecessary()
{
static BOOL fBindingInitialized = FALSE;
if (fBindingInitialized) return RPC_S_OK;
RPC_STATUS status = RpcBindingFromStringBindingA(
RpcssStringBinding,
&remote_resolve_handle
);
if (status == RPC_S_OK)
{
fBindingInitialized = TRUE;
}
return status;
}
// Assumes that the gpMutex is held
ORSTATUS
FindOrCreateMid(
DUALSTRINGARRAY *pdsaObjectResolverBindings,
USHORT wProtseqId,
CMid * &pMid
)
{
ORSTATUS status = OR_OK;
if (IsLocalDSA(pdsaObjectResolverBindings))
{
pMid = gpLocalMid;
return OR_OK;
}
// Attempt to lookup MID
CMidKey midkey(pdsaObjectResolverBindings);
pMid = gpMidTable->Lookup(midkey);
if (NULL == pMid) // must create one
{
// The CMid constructor releases the shared memory lock, so someone else
// might get in and create the very same MID object at the same time
pMid = new CMid(pdsaObjectResolverBindings, status, wProtseqId);
// We initialize local MID autologically,
// therefore this has to be a remote MID
if (pMid && status == OR_OK)
{
status = gpMidTable->Add(pMid);
if (status == OR_I_DUPLICATE)
{
// someone beat us to the punch, use theirs
delete pMid; // can't use this one
pMid = gpMidTable->Lookup(midkey);
ASSERT(pMid != NULL);
status = OR_OK;
}
else if (status != OR_OK)
{
delete pMid;
pMid = NULL;
return status;
}
ASSERT(status == OR_OK);
}
else
{
status = (status == OR_OK) ? OR_NOMEM : status;
}
}
return status;
}
// Assumes that the gpMutex is held
ORSTATUS
CallRpcssToResolveOxid(
IN OXID Oxid,
IN CMid *pMid,
OUT COxid * &pOxid
)
{
ORSTATUS status = OR_OK;
{
CTempReleaseSharedMemory temp; // release mutex before taking gComLock
HRESULT hr = StartRPCSS();
if (FAILED(hr))
{
return OR_INTERNAL_ERROR;
}
}
status = InitResolveHandleIfNecessary();
// call RPCSS
if (status == RPC_S_OK)
{
CTempReleaseSharedMemory temp;
status = RemoteResolveOXID(Oxid,(DWORD)pMid);
if (status != RPC_S_OK)
{
return status;
}
}
// if OK, then the Oxid is in the table now
pOxid = gpOxidTable->Lookup(CId2Key(Oxid, pMid->GetMID()));
ASSERT(pOxid);
return OR_OK;
}
// Assumes that the gpMutex is held
ORSTATUS
FindOrCreateOxid(
IN OXID Oxid,
IN CMid *pMid,
IN long fApartment,
IN OUT OXID_INFO& OxidInfo,
IN USHORT wProtseqId,
IN BOOL fSCMRequest, // is this a register request from SCM?
OUT COxid * &pOxid
)
{
ORSTATUS status = OR_OK;
MID Mid = pMid->GetMID();
pOxid = gpOxidTable->Lookup(CId2Key(Oxid, Mid));
if (pOxid != NULL)
{
if (fSCMRequest)
{
if (gfThisIsRPCSS)
{
MIDL_user_free(OxidInfo.psa); // free the original
}
else
{
CoTaskMemFree(OxidInfo.psa); // ORPC uses CoTaskMemAlloc
}
}
return OR_OK;
}
else if (pMid->IsLocal())
{
return OR_BADOXID; // local OXID should be registered by server
}
// Not found, and not local MID
// Need to allocate the OXID. First step is to resolve it remotely
if ( !fSCMRequest ) // genuine resolve request
{
if ( !gfThisIsRPCSS )
{
return CallRpcssToResolveOxid(Oxid,pMid,pOxid);
}
else // we are RPCSS
{
OxidInfo.psa = NULL; // just to be sure
// Call remote resolver to resolve the OXID
// This call releases the shared memory lock, so someone else
// might get in and create the very same OXID object at the same time
status = pMid->ResolveRemoteOxid( // This op will also replace the
Oxid, // psa with one in shared memory
&OxidInfo
);
if (status != OR_OK)
{
MIDL_user_free(OxidInfo.psa);
return OR_BADOXID;
}
}
}
ASSERT(status == OR_OK);
DUALSTRINGARRAY *pdsaT = dsaSMCopy(OxidInfo.psa);
if (!pdsaT)
{
return OR_NOMEM;
}
if (gfThisIsRPCSS)
{
MIDL_user_free(OxidInfo.psa); // free the original and replace
}
else
{
CoTaskMemFree(OxidInfo.psa); // ORPC uses CoTaskMemAlloc
}
OxidInfo.psa = pdsaT; // with shared memory compressed copy
wProtseqId = fSCMRequest ? wProtseqId : pMid->ProtseqOfServer();
pOxid = new COxid(
Oxid,
pMid,
wProtseqId,
OxidInfo
);
if (pOxid == NULL) return OR_NOMEM;
// remote OXID belongs to ping process ..
if ((status = gpPingProcess->OwnOxid(pOxid)) == OR_OK)
{
status = gpOxidTable->Add(pOxid);
}
if (status == OR_I_DUPLICATE)
{
// this never got inserted anywhere, so we must delete it
// explicitly because refcounting never got involved
delete pOxid;
// someone beat us to the punch, use theirs
pOxid = gpOxidTable->Lookup(CId2Key(Oxid, Mid));
ASSERT(pOxid != NULL);
status = OR_OK;
}
else if (status != OR_OK)
{
// something else went wrong, back out of the whole thing
OrMemFree(OxidInfo.psa);
gpPingProcess->DisownOxid(pOxid,FALSE);
gpOxidTable->Remove(*pOxid);
pOxid = NULL;
}
return status;
}
error_status_t
GetOXID(
IN HPROCESS hProcess,
IN OXID Oxid,
IN DUALSTRINGARRAY *pdsaServerObjectResolverBindings,
IN long fApartment,
IN USHORT wProtseqId,
IN OUT OXID_INFO& OxidInfo,
OUT MID &Mid,
OPTIONAL IN BOOL fSCMRequest // is this a register request from SCM?
)
/*++
Routine Description:
Discovers the OXID_INFO for an oxid. Will find local
OXIDs without any help from resolver process.
It needs OR bindings in order to resolve remote OXIDs.
REVIEW: Should the resolver process be involved in this?
Arguments:
hProcess - The context handle of the process.
Oxid - The OXID (a uuid) to resolve.
pdsaServerObjectResolverBindings - Compressed string bindings to
the OR on the server's machine.
fApartment - non-zero if the client is aparment model.
OxidInfo - If successful this will contain information about the oxid and
an expanded string binding to the server oxid's process.
Mid - The machine ID assigned locally for the remote machine.
This is obviously meaningful only for remote OXIDs.
Return Value:
OR_NOMEM - Common.
OR_BADOXID - Unable to resolve it.
OR_OK - Success.
--*/
{
ComDebOut((DEB_OXID, "GetOXID OXID = %08x\n",Oxid));
COxid *pOxid;
CMid *pMid;
ORSTATUS status = OR_OK;
if (!pdsaServerObjectResolverBindings)
pdsaServerObjectResolverBindings = gpLocalDSA;
ASSERT(dsaValid(pdsaServerObjectResolverBindings));
CProtectSharedMemory protector; // locks through rest of lexical scope
CheckORdata();
#if DBG
if (hProcess) hProcess->IsValid(); // don't validate for fake SCM calls
#endif
status = FindOrCreateMid(
pdsaServerObjectResolverBindings,
wProtseqId,
pMid
);
if (status != OR_OK) return status;
ASSERT(pMid); // otherwise we would have returned by now
Mid = pMid->GetMID();
status = FindOrCreateOxid(
Oxid,
pMid,
fApartment,
OxidInfo,
wProtseqId,
fSCMRequest,
pOxid
);
ASSERT( (status != OR_OK) || pOxid );
CheckORdata();
if (status == OR_OK)
{
return pOxid->GetInfo(&OxidInfo);
}
else
{
return status;
}
}
error_status_t
ClientAddOID(
IN HPROCESS hProcess,
IN OID Oid,
IN OXID Oxid,
IN MID Mid
)
/*++
Routine Description:
Updates the set of OIDs in use by a process.
Arguments:
hProcess - Context handle for the process.
Oid - OID to add.
Oxid - OXID to which OID belongs.
Mid - MID for location of OXID server.
Return Value:
OR_OK - All updates completed ok.
OR_BADOXID - The Oxid was not found
OR_BADOID - The Oid could not be created or found
Notes:
Unlike the NT resolver, there is no possibility that the Oxid
is not in the gpOxidTable (since client and server Oxid objects
are in the same table).
--*/
{
ComDebOut((DEB_OXID, "ClientAddOID\nOID = %08x\nOXID = %08x\nMID = %08x\n",
Oid,Oxid,Mid));
ORSTATUS status = OR_OK;
BOOL fNeedRpcss = FALSE;
CProtectSharedMemory protector; // locks through rest of lexical scope
CheckORdata();
#if DBG
hProcess->IsValid();
#endif
// Lookup up the oxid owning this new oid.
COxid *pOxid = gpOxidTable->Lookup(CId2Key(Oxid,Mid));
if (NULL == pOxid)
{
return OR_BADOXID;
}
CMid *pMid = pOxid->GetMid();
// Find or create the oid.
COid *pOid = gpOidTable->Lookup(CId2Key(Oid,Mid));
if (NULL == pOid)
{
if (pMid->IsLocal()) // Local OID should be registered by server
{
return OR_BADOID;
}
pOid = new COid(pOxid,Oid);
if (NULL == pOid)
{
return OR_NOMEM;
}
status = gpOidTable->Add(pOid);
if (status != OR_OK)
{
delete pOid;
return status;
}
// Need to lazy start RPCSS
fNeedRpcss = TRUE;
}
ASSERT(status == OR_OK);
// We need to call OwnOid irrespective of whether we found the Oid
// in the gpOidTable because this Oid may be remote, and it may have
// been DisOwned by its Oxid but is now being used by a new client
status = pOxid->OwnOid(pOid);
if (status == OR_OK && !pMid->IsLocal())
{
status = pMid->AddClientOid(pOid);
}
if (status == OR_OK || status == OR_I_DUPLICATE)
{
status = hProcess->AddOid(pOid);
if (status == OR_I_DUPLICATE)
{
status = OR_OK;
}
}
else
{
pOxid->DisownOid(pOid);
}
if ((status == OR_OK) && fNeedRpcss)
{
CTempReleaseSharedMemory temp; // release mutex before taking gComLock
HRESULT hr = StartRPCSS();
if (FAILED(hr))
{
status = OR_INTERNAL_ERROR;
}
}
CheckORdata();
return status;
}
error_status_t
ClientDropOID(
IN HPROCESS hProcess,
IN OID Oid,
IN MID Mid
)
/*++
Routine Description:
Updates the set of remote OIDs in use by a process.
Arguments:
hProcess - Context handle for the process.
Oid - OID to be removed.
Mid - MID to which Oid belongs.
Return Value:
OR_OK - All updates completed ok.
OR_BADOID - The Oid could not be found
--*/
{
ComDebOut((DEB_OXID, "ClientDropOID\nOID = %08x\nMID = %08x\n",
Oid,Mid));
CProtectSharedMemory protector; // locks through rest of lexical scope
CheckORdata();
#if DBG
hProcess->IsValid();
#endif
COid * pOid = gpOidTable->Lookup(CId2Key(Oid,Mid));
if (pOid)
{
COid *pRemove = hProcess->DropOid(pOid);
if (pRemove == NULL)
{
#if DBG
{
GUID Moid;
MOIDFromOIDAndMID(Oid,Mid,&Moid);
ComDebOut((DEB_OXID,"OR: Client process %d tried to remove moid %I which \
it didn't own\n", hProcess->GetProcessID(), &Moid));
}
#endif // DBG
return OR_BADOID;
}
else
{
ASSERT(pRemove == pOid);
CheckORdata();
return OR_OK;
}
}
else
{
#if DBG
{
GUID Moid;
MOIDFromOIDAndMID(Oid,Mid,&Moid);
ComDebOut((DEB_OXID,"OR: Client process %d tried to remove moid %I which \
doesn't exist\n", hProcess->GetProcessID(), &Moid));
}
#endif // DBG
return OR_BADOID;
}
}
error_status_t
ServerAllocateOXID(
IN HPROCESS hProcess,
IN long fApartment,
IN OXID_INFO *pOxidInfo,
IN DUALSTRINGARRAY *pdsaStringBindings,
OUT OXID &Oxid
)
/*++
Routine Description:
Allocates an OXID and 0 or more OIDs from the OR.
Arguments:
hProcess - The context handle of the process containing the OXID.
fApartment - is the server threading model apartment or free
OxidInfo - The OXID_INFO structure for the OXID without bindings.
pdsaStringBindings - Expanded string binding of the server.
Oxid - The OXID registered and returned.
Return Value:
OR_OK - success.
OR_NOMEM - Allocation of OXID failed.
--*/
{
ComDebOut((DEB_OXID, "ServerAllocateOXID\n"));
ORSTATUS status = OR_OK;
COxid *pNewOxid;
// Save the string bindings back to the process
ASSERT(dsaValid(pdsaStringBindings));
CProtectSharedMemory protector; // locks through rest of lexical scope
CheckORdata();
#if DBG
hProcess->IsValid();
#endif
status = hProcess->ProcessBindings(pdsaStringBindings);
if (status != OR_OK)
{
return(status);
}
pNewOxid = new COxid(
hProcess,
*pOxidInfo,
fApartment
);
if (NULL == pNewOxid)
{
return(OR_NOMEM);
}
Oxid = pNewOxid->GetOXID();
// Add to process and lookup table.
status = hProcess->OwnOxid(pNewOxid);
VALIDATE((status, OR_NOMEM, 0));
if (OR_OK == status)
{
status = gpOxidTable->Add(pNewOxid);
if (status != OR_OK)
{
delete pNewOxid;
return status;
}
ComDebOut((DEB_OXID, "OXID successfully allocated: %08x\n", Oxid));
}
CheckORdata();
return(status);
}
error_status_t
ServerAllocateOID(
IN HPROCESS hProcess,
IN OXID Oxid,
OUT OID &Oid
)
/*++
Routine Description:
Registers an OID on behalf of an existing OXID.
Arguments:
hProcess - The context handle of the process containing the OXID and OIDs.
Oxid - The OXID associated with the OID (assumed local of course).
Oid - The OID to be allocated and returned.
Return Value:
OR_OK (0) - Success.
OR_NOMEM - OXID or one or more OIDs
--*/
{
ComDebOut((DEB_OXID, "ServerAllocateOID, OXID = %08x\n", Oxid));
CProtectSharedMemory protector; // locks through rest of lexical scope
CheckORdata();
#if DBG
hProcess->IsValid();
#endif
COxid *pOxid = gpOxidTable->Lookup(CId2Key(Oxid,gLocalMID));
ORSTATUS status;
if (NULL == pOxid)
{
return(OR_BADOXID);
}
COid *pOid = new COid(pOxid);
if (NULL == pOid)
{
return OR_NOMEM;
}
status = pOxid->OwnOid(pOid);
if (status == OR_OK)
{
Oid = pOid->GetOID(); // out parameter
status = gpOidTable->Add(pOid);
if (status != OR_OK)
{
COid *pTemp = pOxid->DisownOid(pOid);
ASSERT(pTemp != NULL);
return status;
}
// If the server doesn't want to keep the OID alive,
// this OID may rundown in six minutes unless
// someone references it in the meantime...
ComDebOut((DEB_OXID, "OID successfully allocated: %08x at offset = %x\n",
Oid,pOid));
pOxid->StartRundownThreadIfNecessary();
CheckORdata();
return OR_OK;
}
else
{
return OR_NOMEM;
}
}
error_status_t
ServerFreeOXID(
IN HPROCESS hProcess,
IN OXID Oxid,
IN ULONG cOids,
IN OID aOids[])
/*++
Routine Description:
Delete an OXID registered by the server, and all OIDs belonging to this OXID.
Arguments:
hProcess - The context handle of the process containing the OXID and OIDs.
Oxid - The OXID to be deleted (assumed local).
cOids - The number of OIDs to be deleted.
aOids - array of OIDs to be deleted.
Return Value:
OR_OK (0) - Success.
OR_BADOXID - OXID does not exist.
OR_NOACCESS - OXID does not belong to this process.
OR_BADOID - OID does not exist or does not belong to this OXID.
--*/
{
ComDebOut((DEB_OXID, "ServerFreeOXID: %08x MID = %x\n",
Oxid,gLocalMID));
CProtectSharedMemory protector; // locks through rest of lexical scope
CheckORdata();
#if DBG
hProcess->IsValid();
#endif
COxid *pOxid = gpOxidTable->Lookup(CId2Key(Oxid,gLocalMID));
if (NULL != pOxid)
{
#if DBG
OXID Oxid = pOxid->GetOXID(); // get this before pOxid potentially disappears
#endif
hProcess->DisownOxid(pOxid,TRUE); // this call is on the server's thread
// in the apartment case and in the server's
// process in both threading cases
ComDebOut((DEB_OXID, "OXID successfully removed: %08x\n",
Oxid));
CheckORdata();
return OR_OK;
}
else
{
return OR_BADOXID;
}
}