1059 lines
35 KiB
C++
1059 lines
35 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
// activate.cxx
|
|
//
|
|
// Main dcom activation service routines.
|
|
//
|
|
// History: VinayKr Created
|
|
// 06-Nov-98 TarunA Changed remote/local activation logic
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "act.hxx"
|
|
|
|
HRESULT GetProcessInfoFromActProps(IActivationPropertiesIn* pActPropsIn, DWORD* ppid, DWORD* pdwProcessReqType);
|
|
LPWSTR GetOrigSrvrName( PACTIVATION_PARAMS pActParams );
|
|
|
|
// Global counter
|
|
LONG gThreadToken = 0;
|
|
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
// CalculateActParamsClassInfo
|
|
//
|
|
// Re-calculate the classinfo in the ACTIVATION_PARAMS structure.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CalculateActParamsClassInfo(
|
|
IN OUT PACTIVATION_PARAMS pActParams
|
|
)
|
|
{
|
|
IComClassInfo *pComClassInfo = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pActParams->pToken)
|
|
{
|
|
//
|
|
// I'm a little worried about this. Why do we do this?
|
|
//
|
|
if (!(pActParams->ClsContext & CLSCTX_INPROC_SERVER))
|
|
{
|
|
hr = gpCatalogSCM->GetClassInfo ( pActParams->ClsContext,
|
|
pActParams->pToken,
|
|
pActParams->Clsid,
|
|
IID_IComClassInfo,
|
|
(void**) &pComClassInfo );
|
|
}
|
|
}
|
|
else
|
|
hr = gpCatalog->GetClassInfo ( pActParams->Clsid,
|
|
IID_IComClassInfo,
|
|
(void**) &pComClassInfo );
|
|
|
|
if (SUCCEEDED(hr) && (pComClassInfo))
|
|
{
|
|
if (pActParams->pComClassInfo)
|
|
pActParams->pComClassInfo->Release();
|
|
|
|
// Copy the reference, do not release.
|
|
pActParams->pComClassInfo = pComClassInfo;
|
|
|
|
if (pActParams->pActPropsIn)
|
|
hr = pActParams->pActPropsIn->SetClassInfo(pComClassInfo);
|
|
}
|
|
|
|
|
|
if (hr == REGDB_E_CLASSNOTREG)
|
|
{
|
|
// It's OK for us to have no registration information.
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
LONG ActivationExceptionFilter(LPEXCEPTION_POINTERS lpep)
|
|
{
|
|
ASSERT(NULL && "Unexpected exception thrown");
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
// Activation
|
|
//
|
|
// Main entry point for both local and remote activations.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
Activation(
|
|
IN OUT PACTIVATION_PARAMS pActParams
|
|
)
|
|
{
|
|
CServerTableEntry* pServerTableEntry = NULL;
|
|
CClsidData* pClsidData = NULL;
|
|
CServerListEntry* pServerListEntry;
|
|
CNamedObject* pLaunchMutex = NULL;
|
|
HRESULT hr;
|
|
RPC_STATUS Status;
|
|
BOOL bStatus;
|
|
BOOL bFirstTime = TRUE;
|
|
CToken* pTkn;
|
|
|
|
// NT #294385
|
|
// If REMOTE_SERVER is set, and LOCAL_SERVER is not,
|
|
// and we have a server name, and the server name is us,
|
|
// then we need to turn the LOCAL_SERVER flag on
|
|
|
|
if ( (CLSCTX_REMOTE_SERVER == (pActParams->ClsContext & ( CLSCTX_REMOTE_SERVER | CLSCTX_LOCAL_SERVER ))) &&
|
|
pActParams->pwszServer != NULL &&
|
|
gpMachineName->Compare (pActParams->pwszServer) )
|
|
{
|
|
pActParams->ClsContext |= CLSCTX_LOCAL_SERVER;
|
|
|
|
#ifdef _WIN64
|
|
// On Win64, this might change the classinfo.
|
|
hr = CalculateActParamsClassInfo(pActParams);
|
|
if (FAILED(hr))
|
|
goto ActivationDone;
|
|
#endif
|
|
}
|
|
|
|
#ifdef SECURITY_DBG
|
|
{
|
|
WCHAR dbgwszUser[MAX_PATH];
|
|
if ( pActParams->pToken != NULL )
|
|
{
|
|
pActParams->pToken->Impersonate();
|
|
ULONG cchSize = MAX_PATH;
|
|
GetUserName( dbgwszUser, &cchSize );
|
|
pActParams->pToken->Revert();
|
|
}
|
|
else
|
|
{
|
|
lstrcpyW( dbgwszUser, L"Anonymous" );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( pActParams->pwszServer )
|
|
{
|
|
//
|
|
// Some apps may unnecessarily put slashes before their
|
|
// server names. We'll allow this and strip them off.
|
|
//
|
|
if ( pActParams->pwszServer[0] == L'\\' &&
|
|
pActParams->pwszServer[1] == L'\\' )
|
|
pActParams->pwszServer += 2;
|
|
|
|
if ( 0 == *pActParams->pwszServer )
|
|
{
|
|
hr = CO_E_BAD_SERVER_NAME;
|
|
goto ActivationDone;
|
|
}
|
|
|
|
if ( ! gpMachineName->Compare( pActParams->pwszServer ) )
|
|
{
|
|
//
|
|
// When a client specifies a remote server name we go straight to the
|
|
// source, there is no need to check local configuration information.
|
|
//
|
|
// The CLSCTX_REMOTE_SERVER bit does not need to be specified by the
|
|
// client, it is implied.
|
|
//
|
|
|
|
//
|
|
// the remote activation call will null out the pointer in the ActivationPropertiesIn
|
|
// object which caused the memory that pActParams->pwszServer is pointing to to be
|
|
// freed. We need this name later on to pass to the oxid resoluton phase, so
|
|
// we copy it to some memory on the stack
|
|
//
|
|
|
|
WCHAR *pszTemp = (WCHAR *)_alloca( ( lstrlenW(pActParams->pwszServer) + 1 ) * sizeof(WCHAR) );
|
|
lstrcpyW(pszTemp, pActParams->pwszServer);
|
|
hr = RemoteActivationCall( pActParams, pActParams->pwszServer );
|
|
pActParams->pwszServer = pszTemp;
|
|
|
|
goto ActivationDone;
|
|
}
|
|
}
|
|
|
|
//
|
|
// First search for a running object.
|
|
//
|
|
if ( pActParams->pwszPath )
|
|
{
|
|
//
|
|
// This call returns TRUE if we found a ROT object and are now done.
|
|
// When handling a remote activation it's possible we'll find a ROT
|
|
// object, but we still need to continue in this case to get a remote
|
|
// marshalled interface.
|
|
//
|
|
if ( LookupObjectInROT( pActParams, &hr ) )
|
|
goto ActivationDone;
|
|
}
|
|
|
|
//
|
|
// Try to get a CClsidData using the supplied pComClassInfo
|
|
//
|
|
pTkn = pActParams->RemoteActivation ? NULL : pActParams->pToken;
|
|
|
|
hr = LookupClsidData( pActParams->Clsid,
|
|
pActParams->pComClassInfo,
|
|
pTkn,
|
|
LOAD_NORMAL,
|
|
&pClsidData );
|
|
if (hr == REGDB_E_CLASSNOTREG)
|
|
{
|
|
ASSERT(!pClsidData);
|
|
|
|
// No registration info for this clsid. If the client is interested
|
|
// in a local server activation, we still need to check the class
|
|
// table in case of unsolicited registrations. For COM+ components
|
|
// we should never get here.
|
|
if(pActParams->ClsContext & CLSCTX_LOCAL_SERVER)
|
|
{
|
|
pServerTableEntry = gpClassTable->Lookup(pActParams->Clsid);
|
|
if (pServerTableEntry)
|
|
{
|
|
// Somebody on the machine registered a classfac for this
|
|
// clsid; give it a shot:
|
|
bStatus = pServerTableEntry->CallRunningServer( pActParams,
|
|
0,
|
|
0,
|
|
NULL,
|
|
&hr);
|
|
if (bStatus)
|
|
goto ActivationDone;
|
|
}
|
|
}
|
|
|
|
//
|
|
// As a last resort we always try an atstorage activation.
|
|
//
|
|
ActivateAtStorage( pActParams, NULL, &hr );
|
|
goto ActivationDone;
|
|
}
|
|
else if (FAILED(hr))
|
|
goto ActivationDone;
|
|
|
|
ASSERT(pClsidData && "Registration lookup succeeded but returned nothing");
|
|
|
|
//
|
|
// If this is a remote activation, make sure that the ClassInfo we got
|
|
// can be activated.
|
|
//
|
|
if (pActParams->RemoteActivation)
|
|
{
|
|
hr = pClsidData->IsEnabledRemote();
|
|
if (FAILED(hr))
|
|
{
|
|
// Log it to the event log.
|
|
if (hr == CO_E_CLASS_DISABLED)
|
|
LogComPlusRemoteDisabled(pActParams->ClsContext, pActParams->Clsid);
|
|
|
|
goto ActivationDone;
|
|
}
|
|
}
|
|
|
|
// Look up an appropriate table entry if the client is interested in a
|
|
// local activation
|
|
if(pActParams->ClsContext & CLSCTX_LOCAL_SERVER)
|
|
{
|
|
if (pClsidData->DllHostOrComPlusProcess())
|
|
{
|
|
GUID* pAppidGuid = pClsidData->AppidGuid();
|
|
ASSERT(pAppidGuid);
|
|
pServerTableEntry = gpProcessTable->Lookup(*pAppidGuid);
|
|
}
|
|
else
|
|
pServerTableEntry = gpClassTable->Lookup( pActParams->Clsid );
|
|
}
|
|
|
|
if ( !pServerTableEntry )
|
|
{
|
|
// At this point we have the class data but no running servers. If the
|
|
// client wants remote activation only then go straight to do a remote activation
|
|
// NOTE We '&' with flags CLSCTX_REMOTE_SERVER | CLSCTX_LOCAL_SERVER to
|
|
// filter out any other bits like CLSCTX_INPROC etc
|
|
if( (pActParams->ClsContext & (CLSCTX_REMOTE_SERVER | CLSCTX_LOCAL_SERVER)) == CLSCTX_REMOTE_SERVER)
|
|
{
|
|
// This call returns TRUE if a remote ActivateAtStorage call was
|
|
// made, whether successful or not.
|
|
if ( ActivateAtStorage( pActParams, pClsidData, &hr ) )
|
|
goto ActivationDone;
|
|
else
|
|
goto ActivationDoneLocal;
|
|
}
|
|
|
|
// Figure out which table to create the table entry in
|
|
if (pClsidData->DllHostOrComPlusProcess())
|
|
{
|
|
GUID* pAppidGuid = pClsidData->AppidGuid();
|
|
ASSERT(pAppidGuid);
|
|
pServerTableEntry = gpProcessTable->Create(*pAppidGuid);
|
|
}
|
|
else
|
|
pServerTableEntry = gpClassTable->Create(pActParams->Clsid);
|
|
|
|
if (!pServerTableEntry)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto ActivationDone;
|
|
}
|
|
}
|
|
|
|
ASSERT(pServerTableEntry);
|
|
|
|
hr = GetProcessInfoFromActProps(pActParams->pActPropsIn, &(pActParams->dwPID), &(pActParams->dwProcessReqType));
|
|
if (FAILED(hr))
|
|
goto ActivationDone;
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// Now check for a running server for the CLSID
|
|
// NOTE: The fact that we reached here implies that the client wants at least a
|
|
// local activation
|
|
//
|
|
CairoleDebugOut((DEB_SCM, "Calling ServerTableEntry at 0x%p\n", pServerTableEntry));
|
|
|
|
// We reach here only when we are interested in at least a local activation
|
|
ASSERT(pActParams->ClsContext & CLSCTX_LOCAL_SERVER);
|
|
|
|
// We always try to use an existing running server, unless a custom
|
|
// activator has told us specifically to create a new server.
|
|
if (pActParams->dwProcessReqType != PRT_CREATE_NEW)
|
|
{
|
|
bStatus = pServerTableEntry->CallRunningServer( pActParams,
|
|
0,
|
|
0,
|
|
pClsidData,
|
|
&hr);
|
|
if ( bStatus )
|
|
goto ActivationDone;
|
|
else
|
|
{
|
|
if (pActParams->dwProcessReqType == PRT_USE_THIS_ONLY)
|
|
{
|
|
// A custom activator specified a specific server which was not
|
|
// found. No need to continue further.
|
|
hr = E_UNEXPECTED; // REVIEW for better error code!
|
|
goto ActivationDone;
|
|
}
|
|
else if(pActParams->dwProcessReqType == PRT_USE_THIS)
|
|
{
|
|
// A custom activator hinted at a specific process, which was not
|
|
// found. Eg, the process in question was killed, died, etc. Although
|
|
// this should not happen much in the normal case, it would be nice if
|
|
// we could somehow save the client from getting an error. So what we
|
|
// do is re-try the activation using any compatible server. If it works
|
|
// great, if not then we're done (we won't start a new server).
|
|
|
|
// note we're only resetting the pertinent flags in the actparams struct,
|
|
// not the actprops object, but everybody downstream from here only looks
|
|
// at the actparams so this is okay.
|
|
pActParams->dwProcessReqType = PRT_IGNORE;
|
|
pActParams->dwPID = 0;
|
|
bStatus = pServerTableEntry->CallRunningServer( pActParams,
|
|
0,
|
|
0,
|
|
pClsidData,
|
|
&hr);
|
|
goto ActivationDone;
|
|
}
|
|
// else { keep going }
|
|
}
|
|
}
|
|
|
|
if (bFirstTime)
|
|
{
|
|
bFirstTime = FALSE;
|
|
|
|
//
|
|
// Try to do at-storage first
|
|
//
|
|
if (ActivateAtStorage(pActParams, pClsidData, &hr))
|
|
goto ActivationDone;
|
|
|
|
// Try a remote activation if
|
|
// (1a) Class is configured to be activated remotely
|
|
// AND
|
|
// (1b) Client will accept a remote activation
|
|
// OR
|
|
// (2)SERVERTYPE_NONE
|
|
if( (((pClsidData->GetAcceptableContext() & (CLSCTX_REMOTE_SERVER | CLSCTX_LOCAL_SERVER)) == CLSCTX_REMOTE_SERVER)
|
|
&&
|
|
(pActParams->ClsContext & CLSCTX_REMOTE_SERVER))
|
|
||
|
|
(pClsidData->ServerType() == SERVERTYPE_NONE) )
|
|
goto ActivationDoneLocal;
|
|
}
|
|
|
|
if ( ! pLaunchMutex )
|
|
{
|
|
pLaunchMutex = pClsidData->ServerLaunchMutex();
|
|
if (!pLaunchMutex)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto ActivationDone;
|
|
}
|
|
}
|
|
else
|
|
WaitForSingleObject( pLaunchMutex->Handle(), INFINITE );
|
|
|
|
// At this point we now hold the launch mutex
|
|
|
|
// If we've been told explicitly to launch a new server process, then
|
|
// there's no reason to check for one already running.
|
|
if (pActParams->dwProcessReqType != PRT_CREATE_NEW)
|
|
{
|
|
// If server exists, release launch mutex and try
|
|
// to call server
|
|
BOOL fExists;
|
|
hr = pServerTableEntry->ServerExists(pActParams, &fExists);
|
|
if (hr != S_OK)
|
|
{
|
|
ReleaseMutex( pLaunchMutex->Handle() );
|
|
goto ActivationDone;
|
|
}
|
|
|
|
if (fExists)
|
|
{
|
|
ReleaseMutex( pLaunchMutex->Handle() );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ASSERT(pActParams->dwProcessReqType == PRT_IGNORE ||
|
|
pActParams->dwProcessReqType == PRT_CREATE_NEW);
|
|
|
|
RpcTryExcept
|
|
{
|
|
LONG lLaunchThreadToken;
|
|
//
|
|
// This returns when the server has registered the requested CLSID or
|
|
// we give up.
|
|
//
|
|
CairoleDebugOut((DEB_SCM, "Starting ServerTableEntry at 0x%p\n", pServerTableEntry));
|
|
|
|
// Grab a non-zero token for the launch that we will
|
|
// use to associate the server with on the call
|
|
do {
|
|
lLaunchThreadToken = InterlockedIncrement(&gThreadToken);
|
|
}
|
|
while (lLaunchThreadToken == 0);
|
|
|
|
// Use the token to launch
|
|
// Note that StartServerAndWait could reset the token
|
|
// to zero in some cases.
|
|
hr = pServerTableEntry->StartServerAndWait( pActParams,
|
|
pClsidData,
|
|
lLaunchThreadToken);
|
|
|
|
// Now call the server with the LaunchMutex held but
|
|
// with the threadtoken to guarantee first access to
|
|
// the class in the server we launched. This takes
|
|
// care of SINGLEUSE as well as transient error cases.
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// NOTE: if the server we just launched was an "extra" one (ie, on
|
|
// behalf of some custom activator), it's not guaranteed that this
|
|
// activation will use the just-launched server. It may get an old one.
|
|
bStatus = pServerTableEntry->CallRunningServer(pActParams,
|
|
0,
|
|
lLaunchThreadToken,
|
|
pClsidData,
|
|
&hr);
|
|
if (!bStatus)
|
|
hr = CO_E_SERVER_EXEC_FAILURE;
|
|
}
|
|
}
|
|
RpcExcept(ActivationExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
Status = RpcExceptionCode();
|
|
hr = HRESULT_FROM_WIN32(Status);
|
|
}
|
|
RpcEndExcept
|
|
|
|
ReleaseMutex( pLaunchMutex->Handle() );
|
|
|
|
break;
|
|
|
|
}// end for(;;)
|
|
|
|
goto ActivationDone;
|
|
|
|
ActivationDoneLocal:
|
|
|
|
hr = REGDB_E_CLASSNOTREG;
|
|
|
|
//
|
|
// Server name will only be non-null if its our machine name.
|
|
//
|
|
if ( !pActParams->pwszServer &&
|
|
pClsidData->RemoteServerNames() )
|
|
{
|
|
//
|
|
// the remote activation call will null out the pointer in the ActivationPropertiesIn
|
|
// object which caused the memory that pActParams->pwszServer is pointing to to be
|
|
// freed. We need this name later on to pass to the oxid resoluton phase, so
|
|
// we copy it to some memory on the stack
|
|
//
|
|
// We don't care here since pActParams->pwszServer==NULL if we are here.
|
|
|
|
if (!ActivateRemote( pActParams, pClsidData, &hr ))
|
|
{
|
|
hr = (CLSCTX_REMOTE_SERVER == pActParams->ClsContext) ?
|
|
CO_E_CANT_REMOTE : REGDB_E_CLASSNOTREG;
|
|
}
|
|
}
|
|
|
|
ActivationDone:
|
|
|
|
if (pLaunchMutex)
|
|
pLaunchMutex->Release();
|
|
|
|
// Registry data is not cached in any way.
|
|
if ( pClsidData )
|
|
delete pClsidData;
|
|
|
|
if ( pServerTableEntry )
|
|
pServerTableEntry->Release();
|
|
|
|
// Don't need to resolve if we're return an inproc server.
|
|
if ( (S_OK == hr) && ! *pActParams->ppwszDllServer )
|
|
hr = ResolveORInfo( pActParams);
|
|
if (pActParams->ulMarshaledTargetInfoLength)
|
|
{
|
|
MIDL_user_free(pActParams->pMarshaledTargetInfo);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
// ResolveORInfo
|
|
//
|
|
// On the server side of a remote activation, gets the OXID in the
|
|
// marshalled interface pointer.
|
|
//
|
|
// For a client side activation (local or remote), calls revolve OXID.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
ResolveORInfo(
|
|
IN OUT PACTIVATION_PARAMS pActParams
|
|
)
|
|
{
|
|
MInterfacePointer * pIFD;
|
|
OBJREF * pObjRef;
|
|
STDOBJREF * pStdObjRef;
|
|
DUALSTRINGARRAY * pORBindings;
|
|
DWORD DataSize;
|
|
RPC_STATUS sc;
|
|
DWORD n;
|
|
BOOL ActivatedRemote = pActParams->activatedRemote;
|
|
|
|
// Don't resolve if we are servicing a remote activation and
|
|
// we also did a remote activation(i.e LB router)
|
|
if (pActParams->RemoteActivation && ActivatedRemote)
|
|
return S_OK;
|
|
|
|
//
|
|
// This routine probes the interface data returned from the server's
|
|
// OLE during a successfull activation, but we're still going to
|
|
// protect ourself from bogus data.
|
|
//
|
|
|
|
if (pActParams->pActPropsOut)
|
|
{
|
|
HRESULT hr;
|
|
pActParams->pIIDs = 0;
|
|
pActParams->pResults = 0;
|
|
pActParams->ppIFD = 0;
|
|
hr = pActParams->pActPropsOut->GetMarshalledResults(&pActParams->Interfaces,
|
|
&pActParams->pIIDs,
|
|
&pActParams->pResults,
|
|
&pActParams->ppIFD);
|
|
if (hr != S_OK)
|
|
return hr;
|
|
}
|
|
|
|
pIFD = 0;
|
|
for ( n = 0; n < pActParams->Interfaces; n++ )
|
|
{
|
|
pIFD = pActParams->ppIFD[n];
|
|
if ( pIFD )
|
|
break;
|
|
}
|
|
|
|
ASSERT( pIFD );
|
|
|
|
if ( pIFD->ulCntData < 2*sizeof(ULONG) )
|
|
{
|
|
ASSERT( !"Bad interface data returned from server" );
|
|
return S_OK;
|
|
}
|
|
|
|
pObjRef = (OBJREF *)pIFD->abData;
|
|
|
|
if ( (pObjRef->signature != OBJREF_SIGNATURE) ||
|
|
(pObjRef->flags & ~(OBJREF_STANDARD | OBJREF_HANDLER |
|
|
OBJREF_CUSTOM | OBJREF_EXTENDED)) ||
|
|
(pObjRef->flags == 0) )
|
|
{
|
|
ASSERT( !"Bad interface data returned from server" );
|
|
return S_OK;
|
|
}
|
|
|
|
// No OR info sent back for custom marshalled interfaces.
|
|
if ( pObjRef->flags == OBJREF_CUSTOM )
|
|
return S_OK;
|
|
|
|
DataSize = 2*sizeof(ULONG) + sizeof(GUID);
|
|
pStdObjRef = (STDOBJREF *)(pIFD->abData + DataSize);
|
|
|
|
DataSize += sizeof(STDOBJREF);
|
|
if ( pObjRef->flags == OBJREF_HANDLER )
|
|
DataSize += sizeof(CLSID);
|
|
else if( pObjRef->flags == OBJREF_EXTENDED)
|
|
DataSize += sizeof(DWORD);
|
|
|
|
pORBindings = (DUALSTRINGARRAY *)(pIFD->abData + DataSize);
|
|
DataSize += 2 * sizeof(USHORT);
|
|
|
|
if ( pIFD->ulCntData < DataSize )
|
|
{
|
|
ASSERT( !"Bad interface data returned from server" );
|
|
return S_OK;
|
|
}
|
|
|
|
// If we activated the server on this machine, we need the OXID of the server.
|
|
if ( ! ActivatedRemote )
|
|
*pActParams->pOxidServer = *((OXID UNALIGNED *)&pStdObjRef->oxid);
|
|
|
|
//
|
|
// If we're servicing a remote activation, all we need is the server's OXID.
|
|
// The client will call ResolveClientOXID from its ResolveORInfo.
|
|
//
|
|
if ( pActParams->RemoteActivation )
|
|
return S_OK;
|
|
|
|
DataSize += pORBindings->wNumEntries * sizeof(USHORT);
|
|
|
|
if ( (pIFD->ulCntData < DataSize) ||
|
|
(pORBindings->wNumEntries != 0 &&
|
|
(pORBindings->wSecurityOffset >= pORBindings->wNumEntries)) )
|
|
{
|
|
ASSERT( !"Bad interface data returned from server" );
|
|
// Bug 658576 - don't send back a non-zero oxid if
|
|
// server bindings are empty or corrupt.
|
|
*pActParams->pOxidServer = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// If empty OR bindings were supplied then the server and client are
|
|
// both local to this machine, so use the local OR bindings.
|
|
//
|
|
if (pORBindings->wNumEntries == 0)
|
|
{
|
|
sc = CopyMyOrBindings(pActParams->ppServerORBindings, NULL);
|
|
if (sc != RPC_S_OK)
|
|
return HRESULT_FROM_WIN32(sc);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This was a local activation so use our string bindings for the OR
|
|
// binding string.
|
|
//
|
|
*pActParams->ppServerORBindings = (DUALSTRINGARRAY *)
|
|
MIDL_user_allocate( sizeof(DUALSTRINGARRAY) +
|
|
pORBindings->wNumEntries*sizeof(USHORT) );
|
|
|
|
if ( ! *pActParams->ppServerORBindings )
|
|
return E_OUTOFMEMORY;
|
|
|
|
dsaCopy( *pActParams->ppServerORBindings, pORBindings );
|
|
}
|
|
|
|
//
|
|
// If we did a remote activation then we already have the server's OXID and
|
|
// OR string bindings from the RemoteActivation call and pieces of the OXID
|
|
// info have been filled in.
|
|
//
|
|
|
|
// Could we optimize this at all for the local case?
|
|
USHORT usAuthnSvc;
|
|
sc = ResolveClientOXID( pActParams->hRpc,
|
|
pActParams->pOxidServer,
|
|
*pActParams->ppServerORBindings,
|
|
pActParams->Apartment,
|
|
pActParams->ProtseqId,
|
|
pActParams->pwszServer,
|
|
pActParams->pOxidInfo,
|
|
pActParams->pLocalMidOfRemote,
|
|
pActParams->UnsecureActivation,
|
|
pActParams->AuthnSvc,
|
|
pActParams->ulMarshaledTargetInfoLength,
|
|
pActParams->pMarshaledTargetInfo,
|
|
&pActParams->IsLocalOxid,
|
|
NULL,
|
|
NULL,
|
|
&usAuthnSvc);
|
|
|
|
return HRESULT_FROM_WIN32(sc);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
// ActivateAtStorage
|
|
//
|
|
// If the given CLSID is marked with ActivateAtStorage, do a remote
|
|
// activation to the machine where the path points.
|
|
//
|
|
// Returns TRUE if a remote activation was tried or a wierd error was
|
|
// encoutered. Returns FALSE if the CLSID is not marked with
|
|
// ActivateAtStorage or the file path is determined to be local.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
BOOL
|
|
ActivateAtStorage(
|
|
IN OUT ACTIVATION_PARAMS * pActParams,
|
|
IN CClsidData * pClsidData,
|
|
OUT HRESULT * phr
|
|
)
|
|
{
|
|
//
|
|
// See if we need to do a remote ActivateAtStorage activation. If
|
|
// a server name is given, then we either made a remote activation
|
|
// already or the server name is for the local machine in which case
|
|
// ActivateAtStorage is ignored.
|
|
LPWSTR pwszOrigSrvrName=NULL;
|
|
pwszOrigSrvrName = GetOrigSrvrName(pActParams);
|
|
|
|
if ( pActParams->RemoteActivation ||
|
|
pActParams->pwszServer ||
|
|
pwszOrigSrvrName ||
|
|
!pActParams->pwszPath )
|
|
return FALSE;
|
|
|
|
// Note that if we have no information at all for a CLSID, we try a
|
|
// atstorage activation. Part of initial dcom spec.
|
|
//
|
|
if ( pClsidData && ! pClsidData->ActivateAtStorage() )
|
|
return FALSE;
|
|
|
|
|
|
HRESULT hr;
|
|
WCHAR wszMachineName[MAX_COMPUTERNAME_LENGTH+1];
|
|
|
|
//
|
|
|
|
#ifdef DFSACTIVATION
|
|
//
|
|
// This is for DFS support. If the file hasn't been opened yet, we must
|
|
// open it before trying to resolve the DFS pathname in GetMachineName.
|
|
// This is just how DFS works. FindFirstFile results in the fewest number
|
|
// of network packets.
|
|
//
|
|
if ( ! pActParams->FileWasOpened )
|
|
{
|
|
HANDLE hFile;
|
|
WIN32_FIND_DATA Data;
|
|
|
|
if (pActParams->pToken != NULL)
|
|
pActParams->pToken->Impersonate();
|
|
|
|
hFile = FindFirstFile( pActParams->pwszPath, &Data );
|
|
|
|
if ( hFile != INVALID_HANDLE_VALUE )
|
|
(void) FindClose( hFile );
|
|
|
|
if (pActParams->pToken != NULL)
|
|
pActParams->pToken->Revert();
|
|
|
|
if ( INVALID_HANDLE_VALUE == hFile )
|
|
{
|
|
*phr = CO_E_BAD_PATH;
|
|
return TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
hr = GetMachineName(
|
|
pActParams->pwszPath,
|
|
wszMachineName
|
|
#ifdef DFSACTIVATION
|
|
,TRUE
|
|
#endif
|
|
);
|
|
|
|
if ( hr == S_FALSE )
|
|
{
|
|
// We couldn't get the machine name, path must be local.
|
|
return FALSE;
|
|
}
|
|
else if ( hr != S_OK )
|
|
{
|
|
// We got an error while trying to find the UNC machine name.
|
|
*phr = hr;
|
|
return TRUE;
|
|
}
|
|
|
|
if ( gpMachineName->Compare( wszMachineName ) )
|
|
return FALSE;
|
|
|
|
*phr = RemoteActivationCall( pActParams, wszMachineName );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
// ActivateRemote
|
|
//
|
|
// Does a remote activation based off of the RemoteServerName registry key
|
|
// for the given CLSID.
|
|
//
|
|
// Returns TRUE if a remote activation was tried, FALSE if not.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
BOOL
|
|
ActivateRemote(
|
|
IN OUT ACTIVATION_PARAMS * pActParams,
|
|
IN CClsidData * pClsidData,
|
|
OUT HRESULT * phr
|
|
)
|
|
{
|
|
WCHAR * pwszServerName;
|
|
BOOL bBadServerName;
|
|
BOOL bMyServerName;
|
|
|
|
*phr = S_OK;
|
|
|
|
//
|
|
// The CClsidData class puts the remote server name(s) into a REG_MULTI_SZ
|
|
// format.
|
|
//
|
|
pwszServerName = pClsidData->RemoteServerNames();
|
|
|
|
// jsimmons 3/11/00 prefix bug fix. We would crash below if RemoteServerNames
|
|
// returned NULL (which is possible). The only caller of this function checks
|
|
// that before calling us, though. However, it doesn't hurt to make sure.
|
|
if (!pwszServerName)
|
|
{
|
|
ASSERT(0);
|
|
*phr = E_UNEXPECTED;
|
|
return FALSE;
|
|
}
|
|
|
|
bBadServerName = TRUE;
|
|
bMyServerName = TRUE;
|
|
|
|
for ( ; *pwszServerName; pwszServerName += lstrlenW(pwszServerName) + 1 )
|
|
{
|
|
if ( pwszServerName[0] == L'\\' && pwszServerName[1] == L'\\' )
|
|
pwszServerName += 2;
|
|
|
|
while ( *pwszServerName &&
|
|
(*pwszServerName == L' ' || *pwszServerName == L'\t') )
|
|
pwszServerName++;
|
|
|
|
if ( pwszServerName[0] == L'\0' )
|
|
continue;
|
|
|
|
bBadServerName = FALSE;
|
|
|
|
if ( gpMachineName->Compare( pwszServerName ) )
|
|
continue;
|
|
|
|
bMyServerName = FALSE;
|
|
|
|
*phr = RemoteActivationCall( pActParams, pwszServerName );
|
|
|
|
if ( S_OK == *phr )
|
|
break;
|
|
}
|
|
|
|
if ( bBadServerName || bMyServerName )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
// LookupObjectInROT
|
|
//
|
|
// Looks for an object (file path in this activation) in the Running Object
|
|
// Table.
|
|
//
|
|
// Returns TRUE if we found the object in the ROT and can pass its
|
|
// marshalled interface pointer directly back to the client.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
BOOL
|
|
LookupObjectInROT(
|
|
IN PACTIVATION_PARAMS pActParams,
|
|
OUT HRESULT * phr )
|
|
{
|
|
SCMREGKEY Key;
|
|
MNKEQBUF * pMnkEqBuf;
|
|
BYTE Buffer[sizeof(DWORD)+ROT_COMPARE_MAX];
|
|
|
|
pMnkEqBuf = (MNKEQBUF *) Buffer;
|
|
|
|
*phr = CreateFileMonikerComparisonBuffer(
|
|
pActParams->pwszPath,
|
|
&pMnkEqBuf->abEqData[0],
|
|
ROT_COMPARE_MAX,
|
|
&pMnkEqBuf->cdwSize );
|
|
|
|
if ( *phr != S_OK )
|
|
return FALSE;
|
|
|
|
*phr = gpscmrot->GetObject(
|
|
pActParams->pToken,
|
|
pActParams->pProcess ? pActParams->pProcess->WinstaDesktop() : NULL,
|
|
0,
|
|
pMnkEqBuf,
|
|
&Key,
|
|
(InterfaceData **)&pActParams->pIFDROT );
|
|
|
|
if ( *phr != S_OK )
|
|
return FALSE;
|
|
|
|
//
|
|
// If our activation call is from a local client and for a single
|
|
// interface then we can return success. Otherwise we return failure
|
|
// because we must call the server either to get more interface
|
|
// pointers or because we are servicing a remote activation and must get
|
|
// a normal marshalled interface pointer rather than the table marshalled
|
|
// interface pointer sitting in the ROT.
|
|
//
|
|
if ( ! pActParams->RemoteActivation && (1 == pActParams->Interfaces) )
|
|
{
|
|
// Return the marshaled interface from the ROT to the caller.
|
|
pActParams->ppIFD = (MInterfacePointer **)
|
|
MIDL_user_allocate(sizeof(MInterfacePointer *));
|
|
pActParams->pResults = (HRESULT*) MIDL_user_allocate(sizeof(HRESULT));
|
|
|
|
if ((pActParams->ppIFD==NULL) || (pActParams->pResults==NULL))
|
|
{
|
|
MIDL_user_free(pActParams->ppIFD);
|
|
MIDL_user_free(pActParams->pResults);
|
|
*phr = E_OUTOFMEMORY;
|
|
return FALSE;
|
|
}
|
|
|
|
*pActParams->ppIFD = pActParams->pIFDROT;
|
|
pActParams->pResults[0] = S_OK;
|
|
|
|
// So we remember not to clean up the buffer
|
|
pActParams->pIFDROT = NULL;
|
|
|
|
// Let caller know that we got this from the ROT so
|
|
// if it doesn't work they should try again.
|
|
pActParams->FoundInROT = TRUE;
|
|
*pActParams->pFoundInROT = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// REVIEW REVIEW. Can we return success if the ROT object was marshalled
|
|
// strong? Do we really have to call the server if the object was
|
|
// marshalled weak? Is the resulting race condition any worse then for a
|
|
// normal activation?
|
|
//
|
|
|
|
//
|
|
// We can't use a tabled marshalled interface pointer to send back to a
|
|
// remote client, so we return failure here, but keep the ROT interface
|
|
// data in pIFDROT.
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Get the COSERVERINFO supplied by the client. We'll use this to decide
|
|
// whether we want to do remote ActivateAtStorage.
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
LPWSTR GetOrigSrvrName(
|
|
PACTIVATION_PARAMS pActParams
|
|
)
|
|
{
|
|
LPWSTR pwszOrigSrvrName = NULL;
|
|
|
|
if (pActParams->pActPropsIn)
|
|
{
|
|
SecurityInfo* pLegacyInfo = pActParams->pActPropsIn->GetSecurityInfo();
|
|
if (pLegacyInfo)
|
|
{
|
|
COSERVERINFO* pServerInfo = NULL;
|
|
pLegacyInfo->GetCOSERVERINFO(&pServerInfo);
|
|
if (pServerInfo)
|
|
{
|
|
pwszOrigSrvrName = pServerInfo->pwszName;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pwszOrigSrvrName;
|
|
}
|
|
|
|
|
|
//
|
|
// Helper function. ppid and pdwProcessReqType may be NULL if caller does not care about them.
|
|
//
|
|
HRESULT GetProcessInfoFromActProps(IActivationPropertiesIn* pActPropsIn, DWORD* ppid, DWORD* pdwProcessReqType)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
ASSERT(pActPropsIn);
|
|
|
|
if (pActPropsIn != NULL)
|
|
{
|
|
IServerLocationInfo *pSLInfo = NULL;
|
|
|
|
hr = pActPropsIn->QueryInterface(IID_IServerLocationInfo, (void**) &pSLInfo);
|
|
ASSERT(SUCCEEDED(hr) && pSLInfo);
|
|
if (SUCCEEDED(hr) && pSLInfo != NULL)
|
|
{
|
|
DWORD dwPRT;
|
|
DWORD dwPid;
|
|
hr = pSLInfo->GetProcess(&dwPid, &dwPRT);
|
|
ASSERT(SUCCEEDED(hr));
|
|
ASSERT(dwPRT == PRT_IGNORE ||
|
|
dwPRT == PRT_CREATE_NEW ||
|
|
dwPRT == PRT_USE_THIS ||
|
|
dwPRT == PRT_USE_THIS_ONLY);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (ppid)
|
|
*ppid = dwPid;
|
|
|
|
if (pdwProcessReqType)
|
|
*pdwProcessReqType = dwPRT;
|
|
}
|
|
pSLInfo->Release();
|
|
pSLInfo = NULL;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|