Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

483 lines
12 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995.
  5. //
  6. // File:
  7. // remact.cxx, Chicago version
  8. //
  9. // Contents:
  10. //
  11. // History: Created 24 June 96 SatishT
  12. //
  13. //--------------------------------------------------------------------------
  14. #include "act.hxx"
  15. // Cached RPCSS proxies
  16. static IRemoteActivator *gpRpcssSTAProxy = NULL;
  17. static IRemoteActivator *gpRpcssMTAProxy = NULL;
  18. // flag to remind us whether gRpcssLock was initialized
  19. static gfRpcssLockInitialized = FALSE;
  20. //
  21. // Helper function to release RPCSS proxy -- in ChannelProcessUninitialize
  22. //
  23. INTERNAL ReleaseRPCSSProxy()
  24. {
  25. HRESULT hr = S_OK;
  26. if (NULL != gpRpcssSTAProxy)
  27. {
  28. hr = gpRpcssSTAProxy->Release();
  29. gpRpcssSTAProxy = NULL;
  30. }
  31. if (NULL != gpRpcssMTAProxy)
  32. {
  33. hr = gpRpcssMTAProxy->Release();
  34. gpRpcssMTAProxy = NULL;
  35. }
  36. return hr;
  37. }
  38. //
  39. // Helper function to initialize RPCSS proxy
  40. // This does a song-and-dance to avoid leaking proxies
  41. // in a multithreaded environment
  42. //
  43. inline IRemoteActivator*&
  44. SelectProxy()
  45. {
  46. if (IsSTAThread())
  47. {
  48. return gpRpcssSTAProxy;
  49. }
  50. else
  51. {
  52. return gpRpcssMTAProxy;
  53. }
  54. }
  55. inline
  56. void InitRpcssLockIfNecessary()
  57. {
  58. if (!gfRpcssLockInitialized)
  59. {
  60. NTSTATUS status = RtlInitializeCriticalSection(&gRpcssLock);
  61. if (NT_SUCCESS(status))
  62. gfRpcssLockInitialized = TRUE;
  63. else
  64. {
  65. ASSERT(FALSE);
  66. gfRpcssLockInitialized = FALSE;
  67. }
  68. }
  69. }
  70. HRESULT InitRPCSSProxyIfNecessary()
  71. {
  72. IRemoteActivator* &pRpcssProxy = SelectProxy();
  73. if (pRpcssProxy != NULL) return S_OK;
  74. IRemoteActivator *pTempProxy = NULL;
  75. HRESULT hr = MakeRPCSSProxy((LPVOID*) &pTempProxy);
  76. if (SUCCEEDED(hr))
  77. {
  78. LOCK(gComLock)
  79. if (IsSTAThread())
  80. {
  81. InitRpcssLockIfNecessary();
  82. }
  83. if (pRpcssProxy == NULL)
  84. {
  85. pRpcssProxy = pTempProxy;
  86. }
  87. UNLOCK(gComLock)
  88. if (pRpcssProxy != pTempProxy)
  89. {
  90. hr = pTempProxy->Release();
  91. }
  92. }
  93. return hr;
  94. }
  95. //
  96. // Helper function for outgoing remote activation calls.
  97. //
  98. HRESULT
  99. ForwardToRPCSS(
  100. ACTIVATION_PARAMS * pActParams,
  101. WCHAR * pwszServerName,
  102. WCHAR * pwszPathForServer )
  103. {
  104. HRESULT hr = StartRPCSS();
  105. if (FAILED(hr))
  106. {
  107. return hr;
  108. }
  109. hr = InitRPCSSProxyIfNecessary();
  110. if (FAILED(hr))
  111. {
  112. return hr;
  113. }
  114. COMVERSION ServerVersion;
  115. // We need a lock to prevent multiple STA threads from simultaneously
  116. // using the same STA proxy
  117. if (IsSTAThread())
  118. {
  119. EnterCriticalSection(&gRpcssLock);
  120. }
  121. // need different status since hr is being used as a parameter
  122. HRESULT status = SelectProxy()->ActivateOnRemoteMachine(
  123. &pActParams->Clsid,
  124. pwszServerName,
  125. pwszPathForServer,
  126. pActParams->pAuthInfo,
  127. pActParams->pIFDStorage,
  128. RPC_C_IMP_LEVEL_IDENTIFY,
  129. pActParams->Mode,
  130. pActParams->Interfaces,
  131. pActParams->pIIDs,
  132. &pActParams->ProtseqId,
  133. pActParams->pOxidServer,
  134. &pActParams->pOxidInfo->psa,
  135. &pActParams->pOxidInfo->ipidRemUnknown,
  136. &pActParams->pOxidInfo->dwAuthnHint,
  137. &hr,
  138. pActParams->ppIFD,
  139. pActParams->pResults );
  140. if (IsSTAThread())
  141. {
  142. LeaveCriticalSection(&gRpcssLock);
  143. }
  144. // This is a remote OXID -- no Tid or Pid is relevant --
  145. // in fact, if these are nonzero, the channel will treat
  146. // it as local, with unfortunate consequences.
  147. pActParams->pOxidInfo->dwTid = 0;
  148. pActParams->pOxidInfo->dwPid = 0;
  149. if (SUCCEEDED(status))
  150. {
  151. return hr;
  152. }
  153. else
  154. {
  155. return status;
  156. }
  157. }
  158. //
  159. // Helper function that decides if a remote activation failed
  160. // due to security problems
  161. //
  162. inline BOOL
  163. SecurityError(RPC_STATUS status)
  164. {
  165. switch (status)
  166. {
  167. case RPC_S_UNKNOWN_AUTHN_SERVICE:
  168. case RPC_S_UNKNOWN_AUTHZ_SERVICE:
  169. case RPC_S_UNKNOWN_AUTHN_LEVEL:
  170. case RPC_S_INVALID_AUTH_IDENTITY:
  171. case RPC_S_SEC_PKG_ERROR:
  172. case ERROR_ACCESS_DENIED:
  173. case SEC_E_UNSUPPORTED_FUNCTION:
  174. case SEC_E_INVALID_TOKEN:
  175. case SEC_E_NO_IMPERSONATION:
  176. case SEC_E_LOGON_DENIED:
  177. case SEC_E_UNKNOWN_CREDENTIALS:
  178. case SEC_E_NO_CREDENTIALS:
  179. case SEC_E_NO_AUTHENTICATING_AUTHORITY:
  180. return TRUE;
  181. }
  182. return FALSE;
  183. }
  184. //
  185. // Function that actually makes the call to the SCM on the remote machine
  186. //
  187. RPC_STATUS CallRemoteSCM(
  188. handle_t hRemoteSCM,
  189. USHORT ProtseqId,
  190. ACTIVATION_PARAMS * pActParams,
  191. WCHAR * pwszPathForServer,
  192. HRESULT * phr
  193. )
  194. {
  195. RPC_STATUS Status; //BUGBUG: type mismatch?
  196. COMVERSION ServerVersion;
  197. pActParams->ORPCthis->flags = ORPCF_NULL;
  198. Status = RemoteActivation(
  199. hRemoteSCM,
  200. pActParams->ORPCthis,
  201. pActParams->ORPCthat,
  202. &pActParams->Clsid,
  203. pwszPathForServer,
  204. pActParams->pIFDStorage,
  205. RPC_C_IMP_LEVEL_IDENTIFY,
  206. pActParams->Mode,
  207. pActParams->Interfaces,
  208. pActParams->pIIDs,
  209. 1,
  210. &ProtseqId,
  211. pActParams->pOxidServer,
  212. &pActParams->pOxidInfo->psa,
  213. &pActParams->pOxidInfo->ipidRemUnknown,
  214. &pActParams->pOxidInfo->dwAuthnHint,
  215. &ServerVersion,
  216. phr,
  217. pActParams->ppIFD,
  218. pActParams->pResults );
  219. //
  220. // Note that this will only give us a bad status if there is a
  221. // communication failure. If the binding handle is stale (the
  222. // SCM on the other side has been restarted for instance), we
  223. // will get HRESULT_FROM_WIN32(RPC_S_UNKNOWN_IF) in *phr.
  224. //
  225. pActParams->ProtseqId = ProtseqId;
  226. return Status;
  227. }
  228. //
  229. // Entry point for outgoing remote activation calls.
  230. //
  231. HRESULT
  232. RemoteActivationCall(
  233. ACTIVATION_PARAMS * pActParams,
  234. WCHAR * pwszServerName )
  235. {
  236. COAUTHINFO * pAuthInfo = pActParams->pAuthInfo;
  237. WCHAR wszPathForServer[MAX_PATH+1];
  238. WCHAR * pwszPathForServer;
  239. int ProtseqIndex;
  240. USHORT Protseq;
  241. BOOL NoEndpoint;
  242. RPC_STATUS Status = RPC_S_OK;
  243. HRESULT hr = S_OK;
  244. // No remote activation for 16-bit apps
  245. // We can do this check here because on Win95 we're inproc
  246. if (IsWOWProcess())
  247. {
  248. return HRESULT_FROM_WIN32(RPC_E_REMOTE_DISABLED);
  249. }
  250. Win4Assert( pwszServerName );
  251. pwszPathForServer = 0;
  252. if ( pActParams->pwszPath )
  253. {
  254. // BUGBUG : this stuff needs to be re-examined.
  255. hr = GetPathForServer( pActParams->pwszPath, wszPathForServer, &pwszPathForServer );
  256. if ( hr != S_OK )
  257. return hr;
  258. }
  259. // if we are not RPCSS, forward the call to RPCSS
  260. if (!gfThisIsRPCSS)
  261. {
  262. return ForwardToRPCSS(pActParams,pwszServerName,pwszPathForServer);
  263. }
  264. RPC_BINDING_HANDLE hRemoteSCM = NULL;
  265. // The iterator object, including its ctor and dtor, manages
  266. // the cache of SCM binding handles, setting, removing and
  267. // replacing handles as necessary
  268. CScmBindingIterator BindIter(pwszServerName);
  269. for (
  270. hRemoteSCM = BindIter.First(Protseq, hr);
  271. hRemoteSCM != NULL && SUCCEEDED(hr);
  272. hRemoteSCM = BindIter.Next(Protseq, hr)
  273. )
  274. { // try talking to remote scm on each protseq in order
  275. if (pAuthInfo)
  276. {
  277. // This makes a copy of the binding handle
  278. // so that the cached handle never has
  279. // specialized authentication info
  280. hRemoteSCM = BindIter.SetAuthInfo(pAuthInfo);
  281. if (hRemoteSCM == NULL) continue;
  282. }
  283. BOOL fRetry;
  284. do
  285. {
  286. fRetry = FALSE;
  287. Status = CallRemoteSCM( hRemoteSCM,
  288. Protseq,
  289. pActParams,
  290. pwszPathForServer,
  291. &hr );
  292. if (Status == RPC_S_OK)
  293. {
  294. break;
  295. }
  296. else if (Status == RPC_S_UNKNOWN_IF)
  297. {
  298. fRetry = BindIter.TryDynamic();
  299. }
  300. else if (SecurityError(Status))
  301. {
  302. // this make a copy of the binding
  303. fRetry = BindIter.TryUnsecure(hRemoteSCM);
  304. }
  305. }
  306. while (fRetry);
  307. if (
  308. Status != RPC_S_OK || // comm problems
  309. HRESULT_CODE(hr) == RPC_S_UNKNOWN_IF // Server-side problems
  310. )
  311. {
  312. continue; // try next protseq
  313. }
  314. else
  315. {
  316. return hr;
  317. }
  318. }
  319. // None of the bindings worked, we could not reach the remote server
  320. if (hr == S_OK)
  321. {
  322. return HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
  323. }
  324. else
  325. {
  326. return hr;
  327. }
  328. }
  329. extern "C"
  330. {
  331. error_status_t
  332. _ActivateOnRemoteMachine(
  333. IN handle_t hRpc,
  334. IN ORPCTHIS *ORPCthis,
  335. IN LOCALTHIS *localthis,
  336. OUT ORPCTHAT *ORPCthat,
  337. IN const GUID *Clsid,
  338. IN WCHAR *pwszServerName,
  339. IN WCHAR *pwszPathForServer,
  340. IN COAUTHINFO *pAuthInfo,
  341. IN MInterfacePointer *pObjectStorage,
  342. IN DWORD ClientImpLevel,
  343. IN DWORD Mode,
  344. IN DWORD Interfaces,
  345. IN IID *pIIDs,
  346. OUT USHORT *pProtseqId,
  347. OUT OXID *pOxid,
  348. OUT DUALSTRINGARRAY **ppdsaOxidBindings,
  349. OUT IPID *pipidRemUnknown,
  350. OUT DWORD *pAuthnHint,
  351. OUT HRESULT *phr,
  352. OUT MInterfacePointer **ppInterfaceData,
  353. OUT HRESULT *pResults
  354. )
  355. /*++
  356. Routine Description:
  357. Local API for the client to perform a remote activation.
  358. Return Value:
  359. RPC_S_OK
  360. --*/
  361. {
  362. PACTIVATION_PARAMS pActParams = (PACTIVATION_PARAMS)
  363. PrivMemAlloc(sizeof(ACTIVATION_PARAMS));
  364. if (NULL == pActParams)
  365. {
  366. return RPC_S_OUT_OF_RESOURCES;
  367. }
  368. OXID_INFO info;
  369. pActParams->ORPCthis = ORPCthis;
  370. pActParams->ORPCthat = ORPCthat;
  371. pActParams->pAuthInfo = pAuthInfo;
  372. pActParams->Clsid = *Clsid;
  373. pActParams->pIFDStorage = pObjectStorage;
  374. pActParams->Mode = Mode;
  375. pActParams->pwszPath = pwszPathForServer;
  376. pActParams->Interfaces = Interfaces;
  377. pActParams->pIIDs = pIIDs;
  378. pActParams->pOxidServer = pOxid;
  379. pActParams->ppIFD = ppInterfaceData;
  380. pActParams->pResults = pResults;
  381. pActParams->pOxidInfo = &info;
  382. pActParams->pOxidInfo->psa = NULL;
  383. *phr = RemoteActivationCall(
  384. pActParams,
  385. pwszServerName );
  386. *pProtseqId = pActParams->ProtseqId;
  387. *ppdsaOxidBindings = pActParams->pOxidInfo->psa;
  388. *pipidRemUnknown = pActParams->pOxidInfo->ipidRemUnknown;
  389. *pAuthnHint = pActParams->pOxidInfo->dwAuthnHint;
  390. PrivMemFree(pActParams);
  391. return RPC_S_OK;
  392. }
  393. } // extern "C"