//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1995. // // File: // remact.cxx, Chicago version // // Contents: // // History: Created 24 June 96 SatishT // //-------------------------------------------------------------------------- #include "act.hxx" // Cached RPCSS proxies static IRemoteActivator *gpRpcssSTAProxy = NULL; static IRemoteActivator *gpRpcssMTAProxy = NULL; // flag to remind us whether gRpcssLock was initialized static gfRpcssLockInitialized = FALSE; // // Helper function to release RPCSS proxy -- in ChannelProcessUninitialize // INTERNAL ReleaseRPCSSProxy() { HRESULT hr = S_OK; if (NULL != gpRpcssSTAProxy) { hr = gpRpcssSTAProxy->Release(); gpRpcssSTAProxy = NULL; } if (NULL != gpRpcssMTAProxy) { hr = gpRpcssMTAProxy->Release(); gpRpcssMTAProxy = NULL; } return hr; } // // Helper function to initialize RPCSS proxy // This does a song-and-dance to avoid leaking proxies // in a multithreaded environment // inline IRemoteActivator*& SelectProxy() { if (IsSTAThread()) { return gpRpcssSTAProxy; } else { return gpRpcssMTAProxy; } } inline void InitRpcssLockIfNecessary() { if (!gfRpcssLockInitialized) { NTSTATUS status = RtlInitializeCriticalSection(&gRpcssLock); if (NT_SUCCESS(status)) gfRpcssLockInitialized = TRUE; else { ASSERT(FALSE); gfRpcssLockInitialized = FALSE; } } } HRESULT InitRPCSSProxyIfNecessary() { IRemoteActivator* &pRpcssProxy = SelectProxy(); if (pRpcssProxy != NULL) return S_OK; IRemoteActivator *pTempProxy = NULL; HRESULT hr = MakeRPCSSProxy((LPVOID*) &pTempProxy); if (SUCCEEDED(hr)) { LOCK(gComLock) if (IsSTAThread()) { InitRpcssLockIfNecessary(); } if (pRpcssProxy == NULL) { pRpcssProxy = pTempProxy; } UNLOCK(gComLock) if (pRpcssProxy != pTempProxy) { hr = pTempProxy->Release(); } } return hr; } // // Helper function for outgoing remote activation calls. // HRESULT ForwardToRPCSS( ACTIVATION_PARAMS * pActParams, WCHAR * pwszServerName, WCHAR * pwszPathForServer ) { HRESULT hr = StartRPCSS(); if (FAILED(hr)) { return hr; } hr = InitRPCSSProxyIfNecessary(); if (FAILED(hr)) { return hr; } COMVERSION ServerVersion; // We need a lock to prevent multiple STA threads from simultaneously // using the same STA proxy if (IsSTAThread()) { EnterCriticalSection(&gRpcssLock); } // need different status since hr is being used as a parameter HRESULT status = SelectProxy()->ActivateOnRemoteMachine( &pActParams->Clsid, pwszServerName, pwszPathForServer, pActParams->pAuthInfo, pActParams->pIFDStorage, RPC_C_IMP_LEVEL_IDENTIFY, pActParams->Mode, pActParams->Interfaces, pActParams->pIIDs, &pActParams->ProtseqId, pActParams->pOxidServer, &pActParams->pOxidInfo->psa, &pActParams->pOxidInfo->ipidRemUnknown, &pActParams->pOxidInfo->dwAuthnHint, &hr, pActParams->ppIFD, pActParams->pResults ); if (IsSTAThread()) { LeaveCriticalSection(&gRpcssLock); } // This is a remote OXID -- no Tid or Pid is relevant -- // in fact, if these are nonzero, the channel will treat // it as local, with unfortunate consequences. pActParams->pOxidInfo->dwTid = 0; pActParams->pOxidInfo->dwPid = 0; if (SUCCEEDED(status)) { return hr; } else { return status; } } // // Helper function that decides if a remote activation failed // due to security problems // inline BOOL SecurityError(RPC_STATUS status) { switch (status) { case RPC_S_UNKNOWN_AUTHN_SERVICE: case RPC_S_UNKNOWN_AUTHZ_SERVICE: case RPC_S_UNKNOWN_AUTHN_LEVEL: case RPC_S_INVALID_AUTH_IDENTITY: case RPC_S_SEC_PKG_ERROR: case ERROR_ACCESS_DENIED: case SEC_E_UNSUPPORTED_FUNCTION: case SEC_E_INVALID_TOKEN: case SEC_E_NO_IMPERSONATION: case SEC_E_LOGON_DENIED: case SEC_E_UNKNOWN_CREDENTIALS: case SEC_E_NO_CREDENTIALS: case SEC_E_NO_AUTHENTICATING_AUTHORITY: return TRUE; } return FALSE; } // // Function that actually makes the call to the SCM on the remote machine // RPC_STATUS CallRemoteSCM( handle_t hRemoteSCM, USHORT ProtseqId, ACTIVATION_PARAMS * pActParams, WCHAR * pwszPathForServer, HRESULT * phr ) { RPC_STATUS Status; //BUGBUG: type mismatch? COMVERSION ServerVersion; pActParams->ORPCthis->flags = ORPCF_NULL; Status = RemoteActivation( hRemoteSCM, pActParams->ORPCthis, pActParams->ORPCthat, &pActParams->Clsid, pwszPathForServer, pActParams->pIFDStorage, RPC_C_IMP_LEVEL_IDENTIFY, pActParams->Mode, pActParams->Interfaces, pActParams->pIIDs, 1, &ProtseqId, pActParams->pOxidServer, &pActParams->pOxidInfo->psa, &pActParams->pOxidInfo->ipidRemUnknown, &pActParams->pOxidInfo->dwAuthnHint, &ServerVersion, phr, pActParams->ppIFD, pActParams->pResults ); // // Note that this will only give us a bad status if there is a // communication failure. If the binding handle is stale (the // SCM on the other side has been restarted for instance), we // will get HRESULT_FROM_WIN32(RPC_S_UNKNOWN_IF) in *phr. // pActParams->ProtseqId = ProtseqId; return Status; } // // Entry point for outgoing remote activation calls. // HRESULT RemoteActivationCall( ACTIVATION_PARAMS * pActParams, WCHAR * pwszServerName ) { COAUTHINFO * pAuthInfo = pActParams->pAuthInfo; WCHAR wszPathForServer[MAX_PATH+1]; WCHAR * pwszPathForServer; int ProtseqIndex; USHORT Protseq; BOOL NoEndpoint; RPC_STATUS Status = RPC_S_OK; HRESULT hr = S_OK; // No remote activation for 16-bit apps // We can do this check here because on Win95 we're inproc if (IsWOWProcess()) { return HRESULT_FROM_WIN32(RPC_E_REMOTE_DISABLED); } Win4Assert( pwszServerName ); pwszPathForServer = 0; if ( pActParams->pwszPath ) { // BUGBUG : this stuff needs to be re-examined. hr = GetPathForServer( pActParams->pwszPath, wszPathForServer, &pwszPathForServer ); if ( hr != S_OK ) return hr; } // if we are not RPCSS, forward the call to RPCSS if (!gfThisIsRPCSS) { return ForwardToRPCSS(pActParams,pwszServerName,pwszPathForServer); } RPC_BINDING_HANDLE hRemoteSCM = NULL; // The iterator object, including its ctor and dtor, manages // the cache of SCM binding handles, setting, removing and // replacing handles as necessary CScmBindingIterator BindIter(pwszServerName); for ( hRemoteSCM = BindIter.First(Protseq, hr); hRemoteSCM != NULL && SUCCEEDED(hr); hRemoteSCM = BindIter.Next(Protseq, hr) ) { // try talking to remote scm on each protseq in order if (pAuthInfo) { // This makes a copy of the binding handle // so that the cached handle never has // specialized authentication info hRemoteSCM = BindIter.SetAuthInfo(pAuthInfo); if (hRemoteSCM == NULL) continue; } BOOL fRetry; do { fRetry = FALSE; Status = CallRemoteSCM( hRemoteSCM, Protseq, pActParams, pwszPathForServer, &hr ); if (Status == RPC_S_OK) { break; } else if (Status == RPC_S_UNKNOWN_IF) { fRetry = BindIter.TryDynamic(); } else if (SecurityError(Status)) { // this make a copy of the binding fRetry = BindIter.TryUnsecure(hRemoteSCM); } } while (fRetry); if ( Status != RPC_S_OK || // comm problems HRESULT_CODE(hr) == RPC_S_UNKNOWN_IF // Server-side problems ) { continue; // try next protseq } else { return hr; } } // None of the bindings worked, we could not reach the remote server if (hr == S_OK) { return HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE); } else { return hr; } } extern "C" { error_status_t _ActivateOnRemoteMachine( IN handle_t hRpc, IN ORPCTHIS *ORPCthis, IN LOCALTHIS *localthis, OUT ORPCTHAT *ORPCthat, IN const GUID *Clsid, IN WCHAR *pwszServerName, IN WCHAR *pwszPathForServer, IN COAUTHINFO *pAuthInfo, IN MInterfacePointer *pObjectStorage, IN DWORD ClientImpLevel, IN DWORD Mode, IN DWORD Interfaces, IN IID *pIIDs, OUT USHORT *pProtseqId, OUT OXID *pOxid, OUT DUALSTRINGARRAY **ppdsaOxidBindings, OUT IPID *pipidRemUnknown, OUT DWORD *pAuthnHint, OUT HRESULT *phr, OUT MInterfacePointer **ppInterfaceData, OUT HRESULT *pResults ) /*++ Routine Description: Local API for the client to perform a remote activation. Return Value: RPC_S_OK --*/ { PACTIVATION_PARAMS pActParams = (PACTIVATION_PARAMS) PrivMemAlloc(sizeof(ACTIVATION_PARAMS)); if (NULL == pActParams) { return RPC_S_OUT_OF_RESOURCES; } OXID_INFO info; pActParams->ORPCthis = ORPCthis; pActParams->ORPCthat = ORPCthat; pActParams->pAuthInfo = pAuthInfo; pActParams->Clsid = *Clsid; pActParams->pIFDStorage = pObjectStorage; pActParams->Mode = Mode; pActParams->pwszPath = pwszPathForServer; pActParams->Interfaces = Interfaces; pActParams->pIIDs = pIIDs; pActParams->pOxidServer = pOxid; pActParams->ppIFD = ppInterfaceData; pActParams->pResults = pResults; pActParams->pOxidInfo = &info; pActParams->pOxidInfo->psa = NULL; *phr = RemoteActivationCall( pActParams, pwszServerName ); *pProtseqId = pActParams->ProtseqId; *ppdsaOxidBindings = pActParams->pOxidInfo->psa; *pipidRemUnknown = pActParams->pOxidInfo->ipidRemUnknown; *pAuthnHint = pActParams->pOxidInfo->dwAuthnHint; PrivMemFree(pActParams); return RPC_S_OK; } } // extern "C"