Leaked source code of windows server 2003
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.

2255 lines
58 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. Process.cxx
  5. Abstract:
  6. Process objects represent local clients and servers. These
  7. objects live as context handles.
  8. There are relatively few of these objects in the universe.
  9. Author:
  10. Mario Goertzel [MarioGo]
  11. Revision History:
  12. MarioGo 02-20-95 Bits 'n pieces
  13. Ronans 20-02-97 UseProtseqIfNeeded modified for custom endpoints
  14. Ronans 20-02-97 Added custom endpoints stuff to process object
  15. TarunA 09-Nov-98 Added process handle
  16. --*/
  17. #include <or.hxx>
  18. CRITICAL_SECTION gcsFastProcessLock;
  19. extern HRESULT FreeSPIFromCProcess(void** ppSCMProcessInfo);
  20. const DWORD BINDINGUPDATESTUFF_SIG = 0xFEDCBA01;
  21. typedef struct _BINDINGS_UPDATE_CALLBACK_STUFF
  22. {
  23. DWORD dwSig; // see BINDINGUPDATESTUFF_SIG above
  24. // housekeeping stuff
  25. CProcess* pProcess; // has reference while call is in-flight
  26. RPC_BINDING_HANDLE hBinding;
  27. RPC_ASYNC_STATE async;
  28. // out and in-out params
  29. DWORD64 dwBindingsID;
  30. DUALSTRINGARRAY* pdsaNewBindings;
  31. DUALSTRINGARRAY* pdsaNewSecurity;
  32. } BINDINGS_UPDATE_CALLBACK_STUFF;
  33. const DWORD ASYNCRUNDOWNOID_SIG = 0xFEDCBA02;
  34. typedef struct _ASYNCRUNDOWNOID_STUFF
  35. {
  36. DWORD dwSig; // see ASYNCRUNDOWNOID_SIG above
  37. // housekeeping stuff
  38. CProcess* pProcess; // has reference while call is in-flight
  39. CServerOxid* pOxid; // has reference while call is in-flight
  40. RPC_BINDING_HANDLE hBinding;
  41. RPC_ASYNC_STATE async;
  42. // We keep these for when we process the return
  43. ULONG cOids;
  44. CServerOid* aOids[MAX_OID_RUNDOWNS_PER_CALL];
  45. // The ORPC params are reference pointers, so they must
  46. // stay alive for the life of the call
  47. ORPCTHIS orpcthis;
  48. LOCALTHIS localthis;
  49. ORPCTHAT orpcthat;
  50. INT callIDHint; // need to free this on return
  51. // in-out or out params.
  52. BYTE aRundownStatus[MAX_OID_RUNDOWNS_PER_CALL];
  53. } ASYNCRUNDOWNOID_STUFF;
  54. void
  55. CProcess::Rundown()
  56. /*++
  57. Routine Description:
  58. The client process has rundown. This means there are no more
  59. client refernces which means we are free to clean things up
  60. as long as server OXIDs still holding references won't get
  61. upset. They all use the server lock when accessing the process.
  62. Arguments:
  63. None
  64. Return Value:
  65. None
  66. --*/
  67. {
  68. ORSTATUS status;
  69. gpServerLock->LockExclusive();
  70. ASSERT(_cClientReferences == 0);
  71. KdPrintEx((DPFLTR_DCOMSS_ID,
  72. DPFLTR_INFO_LEVEL,
  73. "OR: Rundown of %p: %d oxids, %d oids and %d roxids left\n",
  74. this,
  75. _blistOxids.Size(),
  76. _blistOids.Size()));
  77. // Release any OXIDs owned by this process. This may destroy the OXID.
  78. // This will release this CProcess, but won't release the last reference as
  79. // the client process still owns one.
  80. if (_blistOxids.Size())
  81. {
  82. CServerOxid *poxid;
  83. CBListIterator oxids(&_blistOxids);
  84. while (poxid = (CServerOxid *)oxids.Next())
  85. {
  86. gpServerOxidTable->Remove(poxid);
  87. poxid->ProcessRelease();
  88. }
  89. }
  90. // Release any OIDs is use by this processes.
  91. // Do this now, rather then waiting for the last server oid
  92. // owned by this process to get invalidated and rundown.
  93. gpClientLock->LockExclusive();
  94. // *** Both client and server lock held here. ***
  95. if (_blistOids.Size())
  96. {
  97. CClientOid *poid;
  98. CBListIterator oids(&_blistOids);
  99. while (poid = (CClientOid *)oids.Next())
  100. {
  101. ASSERT(NULL != poid->GetClientOxid());
  102. poid->GetClientOxid()->Release();
  103. poid->ClientRelease();
  104. }
  105. }
  106. // Cleanup other process state. Note: it is important that the
  107. // release of the process and token handle never happen any later
  108. // than rundown time. If the process handle is released any later, you
  109. // will see bugs like "can't recompile my com server" after they run
  110. // it once. If the token handle is released any later, you will get
  111. // security bugs from the NT security folks since we will hold onto
  112. // the logged-on user's token until many minutes after logoff.
  113. //
  114. // Ask me how I know this...
  115. //
  116. if (_hProcHandle)
  117. {
  118. CloseHandle(_hProcHandle);
  119. _hProcHandle = NULL;
  120. }
  121. if (_pToken)
  122. {
  123. _pToken->Release();
  124. _pToken = 0;
  125. }
  126. // Free the cached SCMProcessInfo if we have one
  127. FreeSPIFromCProcess(&_pSCMProcessInfo);
  128. // Flip the dirty bit
  129. FlagsOn(PROCESS_SPI_DIRTY);
  130. // Cleanup the ROT entries associated with this process outside the lock.
  131. // NULL the list first, though.
  132. void *pvFirstROT = _pvFirstROTEntry;
  133. _pvFirstROTEntry = NULL;
  134. gpClientLock->UnlockExclusive();
  135. if (_cDropTargets != 0) // check if we have any outstanding droptargets to clean up
  136. DragDropRunDown(this);
  137. // Done, release the clients' reference, this may actually delete this
  138. // process. (If an OXID still exists and has OIDs it will not be deleted
  139. // until the OIDs all rundown).
  140. this->Release();
  141. // The this pointer maybe invalid now.
  142. gpServerLock->UnlockExclusive();
  143. // Now actually cleanup the ROT entries.
  144. // Do this outside of the server lock, to avoid deadlocks.
  145. SCMCleanupROTEntries(pvFirstROT);
  146. }
  147. CProcess::CProcess(
  148. IN CToken*& pToken,
  149. IN WCHAR *pwszWinstaDesktop,
  150. IN DWORD procID,
  151. OUT ORSTATUS &status
  152. ) :
  153. _blistOxids(4),
  154. _blistOids(16),
  155. _listClasses()
  156. /*++
  157. Routine Description:
  158. Initalized a process object, members and add it to the
  159. process list.
  160. Arguments:
  161. pToken - The clients token. We assume we have a reference.
  162. pwszWinstaDesktop - The client's windowstation/desktop string.
  163. procID - The client's process ID.
  164. status - Sometimes the C'tor can fail with OR_NOMEM.
  165. Return Value:
  166. None
  167. --*/
  168. {
  169. _cClientReferences = 1;
  170. _hProcess = NULL;
  171. _fCacheFree = FALSE;
  172. _pdsaLocalBindings = NULL;
  173. _pdsaRemoteBindings = NULL;
  174. _pToken = NULL;
  175. _pwszWinstaDesktop = NULL;
  176. _pScmProcessReg = NULL;
  177. _pvRunAsHandle = NULL;
  178. _procID = 0;
  179. _hProcHandle = NULL;
  180. _dwFlags = PROCESS_SPI_DIRTY; // always start out dirty
  181. _pSCMProcessInfo = NULL;
  182. _ulClasses = 0;
  183. _dwCurrentBindingsID = 0;
  184. _dwAsyncUpdatesOutstanding = 0;
  185. _pvFirstROTEntry = NULL;
  186. _cDropTargets = 0;
  187. // Store time of object creation. Note that this is in UTC time.
  188. GetSystemTimeAsFileTime(&_ftCreated);
  189. // Generate a unique guid to represent this process
  190. UuidCreate(&_guidProcessIdentifier);
  191. // ronans - entries for custom protseqs from server
  192. // not used for clients
  193. _fReadCustomProtseqs = FALSE;
  194. _pdsaCustomProtseqs = NULL;
  195. status = OR_OK;
  196. if ( pwszWinstaDesktop == NULL )
  197. {
  198. status = OR_BADPARAM;
  199. }
  200. if (status == OR_OK)
  201. {
  202. _pwszWinstaDesktop = new WCHAR[OrStringLen(pwszWinstaDesktop)+1];
  203. if (! _pwszWinstaDesktop)
  204. status = OR_NOMEM;
  205. else
  206. OrStringCopy(_pwszWinstaDesktop, pwszWinstaDesktop);
  207. }
  208. if (status == OR_OK)
  209. {
  210. _pToken = pToken;
  211. pToken = NULL; // We've taken the token
  212. }
  213. if (status == STATUS_SUCCESS)
  214. {
  215. // Need to check that this is truly a new registration
  216. // before we add it to the list
  217. gpProcessListLock->LockExclusive();
  218. if (VerifyNewProcess(procID))
  219. {
  220. status = gpProcessList->Insert(this);
  221. }
  222. else
  223. {
  224. // bad baby bad
  225. status = OR_NOACCESS;
  226. ASSERT(!"Possible bogus caller");
  227. }
  228. gpProcessListLock->UnlockExclusive();
  229. }
  230. _procID = procID;
  231. #if DBG
  232. _cRundowns = 0;
  233. #endif
  234. }
  235. CProcess::~CProcess(void)
  236. // You probably should be looking in the ::Rundown method.
  237. // This process object stays alive until the last server oxid dies.
  238. {
  239. ASSERT(gpServerLock->HeldExclusive());
  240. ASSERT(_hProcHandle == 0);
  241. ASSERT(_pSCMProcessInfo == 0);
  242. delete _pdsaLocalBindings;
  243. delete _pdsaRemoteBindings;
  244. MIDL_user_free( _pdsaCustomProtseqs );
  245. delete _pwszWinstaDesktop;
  246. if (_hProcess)
  247. {
  248. RPC_STATUS status = RpcBindingFree(&_hProcess);
  249. ASSERT(status == RPC_S_OK);
  250. ASSERT(_hProcess == 0);
  251. }
  252. extern void RunAsRelease(void*);
  253. RunAsRelease(_pvRunAsHandle);
  254. return;
  255. }
  256. //
  257. // SetSCMProcessInfo
  258. //
  259. // Swaps our old cached SCMProcessInfo* for a new one.
  260. //
  261. HRESULT CProcess::SetSCMProcessInfo(void* pSPI)
  262. {
  263. ASSERT(gpServerLock->HeldExclusive());
  264. ASSERT(!(_dwFlags & PROCESS_RUNDOWN));
  265. if (_dwFlags & PROCESS_RUNDOWN)
  266. return E_UNEXPECTED;
  267. FreeSPIFromCProcess(&_pSCMProcessInfo);
  268. // set the new one
  269. _pSCMProcessInfo = pSPI;
  270. // this means we're no longer dirty
  271. FlagsOff(PROCESS_SPI_DIRTY);
  272. return S_OK;
  273. }
  274. void CProcess::SetProcessReadyState(DWORD dwState)
  275. {
  276. ASSERT(_pScmProcessReg);
  277. gpServerLock->LockExclusive();
  278. _pScmProcessReg->ReadinessStatus = dwState;
  279. // we're now dirty
  280. FlagsOn(PROCESS_SPI_DIRTY);
  281. gpServerLock->UnlockExclusive();
  282. }
  283. void CProcess::Retire()
  284. {
  285. // A process can (or should be) only retired once
  286. ASSERT(!IsRetired());
  287. // Mark ourselves as retired
  288. FlagsOn(PROCESS_RETIRED | PROCESS_SPI_DIRTY);
  289. }
  290. void CProcess::SetRunAsHandle(void *pvRunAsHandle)
  291. {
  292. ASSERT(!_pvRunAsHandle);
  293. _pvRunAsHandle = pvRunAsHandle;
  294. }
  295. BOOL CProcess::SetProcessHandle(HANDLE hProcHandle, DWORD dwLaunchedPID)
  296. {
  297. /*++
  298. Routine Description:
  299. Store the handle of the process only if the process launched by
  300. us and the process registering back are the same. Otherwise
  301. we might kill a process not launched by us on receiving certain
  302. error conditions (notably RPC_E_SERVERFAULT)
  303. Arguments:
  304. hProcHandle - Handle of the process launched
  305. dwLaunchedPID - PID of the process launched
  306. Return Value:
  307. TRUE - If handle is set
  308. FALSE - otherwise
  309. --*/
  310. BOOL fRet = FALSE;
  311. if (dwLaunchedPID == _procID)
  312. {
  313. // if the server registers the same class twice, this handle will be non-zero if the
  314. // the waiting activation thread has not NULL'd the CServerTableEntry's _hProcess yet.
  315. if (_hProcHandle)
  316. {
  317. CloseHandle(_hProcHandle);
  318. _hProcHandle = 0;
  319. }
  320. // This should fail only we are out of pool.
  321. // If this fails, we cannot kill off servers we started
  322. // nor can we test them for deadness.
  323. if ( (fRet = DuplicateHandle(GetCurrentProcess(), hProcHandle,
  324. GetCurrentProcess(), &_hProcHandle,
  325. 0, FALSE, DUPLICATE_SAME_ACCESS)) == 0)
  326. {
  327. KdPrintEx((DPFLTR_DCOMSS_ID,
  328. DPFLTR_WARNING_LEVEL,
  329. "OR: DuplicateHandle failed 0x%x\n", GetLastError()));
  330. }
  331. }
  332. return fRet;
  333. }
  334. RPC_STATUS
  335. CProcess::ProcessBindings(
  336. IN DUALSTRINGARRAY *pdsaStringBindings,
  337. IN DUALSTRINGARRAY *pdsaSecurityBindings
  338. )
  339. /*++
  340. Routine Description:
  341. Updates the string and optionally the security
  342. bindings associated with this process.
  343. Arguments:
  344. psaStringBindings - The expanded string bindings of the process
  345. psaSecurityBindings - compressed security bindings of the process.
  346. If NULL, the current security bindings are reused.
  347. Environment:
  348. Server lock held during call or called from an OXID with an extra
  349. reference owned by the process and keeping this process alive.
  350. Return Value:
  351. OR_NOMEM - unable to allocate storage for the new string arrays.
  352. OR_OK - normally.
  353. --*/
  354. {
  355. CMutexLock lock(&gcsFastProcessLock);
  356. USHORT wSecSize;
  357. PWSTR pwstrSecPointer;
  358. // NULL security bindings means we should use the existing bindings.
  359. if (0 == pdsaSecurityBindings)
  360. {
  361. ASSERT(_pdsaLocalBindings);
  362. wSecSize = _pdsaLocalBindings->wNumEntries - _pdsaLocalBindings->wSecurityOffset;
  363. pwstrSecPointer = _pdsaLocalBindings->aStringArray
  364. + _pdsaLocalBindings->wSecurityOffset;
  365. }
  366. else
  367. {
  368. wSecSize = pdsaSecurityBindings->wNumEntries - pdsaSecurityBindings->wSecurityOffset;
  369. pwstrSecPointer = &pdsaSecurityBindings->aStringArray[pdsaSecurityBindings->wSecurityOffset];
  370. }
  371. DUALSTRINGARRAY *pdsaT = CompressStringArrayAndAddIPAddrs(pdsaStringBindings);
  372. if (!pdsaT)
  373. {
  374. return(OR_NOMEM);
  375. }
  376. // ignore security on string binding parameter
  377. pdsaT->wNumEntries = pdsaT->wSecurityOffset;
  378. DUALSTRINGARRAY *pdsaResult = new((pdsaT->wNumEntries + wSecSize) * sizeof(WCHAR)) DUALSTRINGARRAY;
  379. if (0 == pdsaResult)
  380. {
  381. delete pdsaT;
  382. return(OR_NOMEM);
  383. }
  384. pdsaResult->wNumEntries = pdsaT->wNumEntries + wSecSize;
  385. pdsaResult->wSecurityOffset = pdsaT->wSecurityOffset;
  386. OrMemoryCopy(pdsaResult->aStringArray,
  387. pdsaT->aStringArray,
  388. pdsaT->wSecurityOffset*sizeof(WCHAR));
  389. OrMemoryCopy(pdsaResult->aStringArray + pdsaResult->wSecurityOffset,
  390. pwstrSecPointer,
  391. wSecSize*sizeof(WCHAR));
  392. ASSERT(dsaValid(pdsaResult));
  393. delete pdsaT;
  394. delete _pdsaLocalBindings;
  395. _pdsaLocalBindings = pdsaResult;
  396. delete _pdsaRemoteBindings;
  397. _pdsaRemoteBindings = 0;
  398. return(RPC_S_OK);
  399. }
  400. DUALSTRINGARRAY *
  401. CProcess::GetLocalBindings(void)
  402. // Server lock held or called within an
  403. // OXID with an extra reference.
  404. {
  405. CMutexLock lock(&gcsFastProcessLock);
  406. if (0 == _pdsaLocalBindings)
  407. {
  408. return(0);
  409. }
  410. DUALSTRINGARRAY *T = (DUALSTRINGARRAY *)MIDL_user_allocate(sizeof(DUALSTRINGARRAY)
  411. + sizeof(USHORT) * _pdsaLocalBindings->wNumEntries);
  412. if (0 != T)
  413. {
  414. dsaCopy(T, _pdsaLocalBindings);
  415. }
  416. return(T);
  417. }
  418. DUALSTRINGARRAY *
  419. CProcess::GetRemoteBindings(void)
  420. // Server lock held.
  421. {
  422. CMutexLock lock(&gcsFastProcessLock);
  423. ORSTATUS Status;
  424. if (0 == _pdsaRemoteBindings)
  425. {
  426. if (0 == _pdsaLocalBindings)
  427. {
  428. return(0);
  429. }
  430. Status = ConvertToRemote(_pdsaLocalBindings, &_pdsaRemoteBindings);
  431. if (Status != OR_OK)
  432. {
  433. ASSERT(Status == OR_NOMEM);
  434. return(0);
  435. }
  436. ASSERT(dsaValid(_pdsaRemoteBindings));
  437. }
  438. DUALSTRINGARRAY *T = (DUALSTRINGARRAY *)MIDL_user_allocate(sizeof(DUALSTRINGARRAY)
  439. + sizeof(USHORT) * _pdsaRemoteBindings->wNumEntries);
  440. if (0 != T)
  441. {
  442. dsaCopy(T, _pdsaRemoteBindings);
  443. }
  444. ASSERT(dsaValid(T));
  445. return(T);
  446. }
  447. ORSTATUS
  448. CProcess::AddOxid(CServerOxid *pOxid)
  449. {
  450. ASSERT(gpServerLock->HeldExclusive());
  451. pOxid->Reference();
  452. ASSERT(_blistOxids.Member(pOxid) == FALSE);
  453. ORSTATUS status = _blistOxids.Insert(pOxid);
  454. if (status != OR_OK)
  455. {
  456. pOxid->ProcessRelease();
  457. return(status);
  458. }
  459. gpServerOxidTable->Add(pOxid);
  460. return(OR_OK);
  461. }
  462. BOOL
  463. CProcess::RemoveOxid(CServerOxid *poxid)
  464. {
  465. ASSERT(gpServerLock->HeldExclusive());
  466. CServerOxid *pit = (CServerOxid *)_blistOxids.Remove(poxid);
  467. if (pit)
  468. {
  469. ASSERT(pit == poxid);
  470. gpServerOxidTable->Remove(poxid);
  471. poxid->ProcessRelease();
  472. return(TRUE);
  473. }
  474. return(FALSE);
  475. }
  476. BOOL
  477. CProcess::IsOwner(CServerOxid *poxid)
  478. {
  479. ASSERT(gpServerLock->HeldExclusive());
  480. return(_blistOxids.Member(poxid));
  481. }
  482. ORSTATUS
  483. CProcess::AddOid(CClientOid *poid)
  484. /*++
  485. Routine Description:
  486. Adds a new oid to the list of OIDs owned by this process and
  487. increments the reference count of the associated OXID
  488. Arguments:
  489. poid - the oid to add. It's reference is transferred to this
  490. function. If this function fails, it must dereference the oid.
  491. The caller passed a client reference to this process. The
  492. process must eventually call ClientRelease() on the parameter.
  493. Return Value:
  494. OR_OK - normally
  495. OR_NOMEM - out of memory.
  496. --*/
  497. {
  498. ORSTATUS status;
  499. ASSERT(gpClientLock->HeldExclusive());
  500. status = _blistOids.Insert(poid);
  501. if (status != OR_OK)
  502. {
  503. ASSERT(status == OR_NOMEM);
  504. poid->ClientRelease();
  505. }
  506. else
  507. {
  508. ASSERT(NULL != poid->GetClientOxid());
  509. poid->GetClientOxid()->Reference();
  510. }
  511. return(status);
  512. }
  513. CClientOid *
  514. CProcess::RemoveOid(CClientOid *poid)
  515. /*++
  516. Routine Description:
  517. Removes an OID from this list of OID in use by this process.
  518. Arguments:
  519. poid - The OID to remove.
  520. Return Value:
  521. non-zero - the pointer actually remove. (ASSERT(retval == poid))
  522. It will be released by the process before return,
  523. so you should not use the pointer unless you know you
  524. have another reference.
  525. 0 - not in the list
  526. --*/
  527. {
  528. ASSERT(gpClientLock->HeldExclusive());
  529. CClientOid *pit = (CClientOid *)_blistOids.Remove(poid);
  530. if (pit)
  531. {
  532. ASSERT(pit == poid);
  533. pit->ClientRelease();
  534. ASSERT(NULL != poid->GetClientOxid());
  535. poid->GetClientOxid()->Release();
  536. return(pit);
  537. }
  538. return(0);
  539. }
  540. void
  541. CProcess::AddClassReg(GUID & Guid, DWORD Reg)
  542. {
  543. CClassReg * pReg;
  544. pReg = new CClassReg( Guid, Reg );
  545. if (pReg)
  546. {
  547. gpServerLock->LockExclusive();
  548. _listClasses.Insert( pReg );
  549. // flip the dirty bit
  550. FlagsOn(PROCESS_SPI_DIRTY);
  551. _ulClasses++;
  552. gpServerLock->UnlockExclusive();
  553. }
  554. }
  555. void
  556. CProcess::RemoveClassReg(DWORD Reg)
  557. {
  558. CClassReg * pReg;
  559. gpServerLock->LockExclusive();
  560. pReg = (CClassReg *)_listClasses.First();
  561. while ( (pReg != NULL) && (pReg->_Reg != Reg) )
  562. pReg = (CClassReg *)pReg->Next();
  563. if (pReg)
  564. {
  565. (void)_listClasses.Remove( pReg );
  566. delete pReg;
  567. // flip the dirty bit
  568. FlagsOn(PROCESS_SPI_DIRTY);
  569. _ulClasses--;
  570. }
  571. gpServerLock->UnlockExclusive();
  572. }
  573. void
  574. CProcess::Cleanup()
  575. {
  576. SCMProcessCleanup(this);
  577. }
  578. void
  579. CProcess::RevokeClassRegs()
  580. {
  581. if (_pScmProcessReg)
  582. {
  583. // This is a unified surrogate (COM+) server
  584. SCMRemoveRegistration(_pScmProcessReg);
  585. _pScmProcessReg = NULL;
  586. }
  587. // This is for legacy local or custom surrogate servers -- however,
  588. // nothing prevents someone from calling CoRegisterClassObject in
  589. // user code even in a COM+ (surrogate) server
  590. CClassReg * pReg;
  591. // This is only called during rundown so we don't have to take a lock.
  592. while ( (pReg = (CClassReg *)_listClasses.First()) != 0 )
  593. {
  594. (void)_listClasses.Remove((CListElement *)pReg);
  595. SCMRemoveRegistration( this,
  596. pReg->_Guid,
  597. pReg->_Reg );
  598. delete pReg;
  599. }
  600. }
  601. void CProcess::SetProcessReg(ScmProcessReg *pProcessReg)
  602. /*++
  603. Routine Description:
  604. Called by SCM to set COM+ process registration.
  605. This is also used as a cache during the startup protocol
  606. to query and set the readiness state of the server process.
  607. There is exactly one such registration per COM+ server process.
  608. CODEWORK: these should be inlined
  609. Arguments:
  610. registration struct
  611. Return Value:
  612. none.
  613. --*/
  614. {
  615. gpServerLock->LockExclusive();
  616. _pScmProcessReg = pProcessReg;
  617. gpServerLock->UnlockExclusive();
  618. }
  619. ScmProcessReg* CProcess::GetProcessReg()
  620. /*++
  621. Routine Description:
  622. Called by SCM to lookup COM+ process registration.
  623. Arguments:
  624. None
  625. Return Value:
  626. registration struct, if any.
  627. --*/
  628. {
  629. gpServerLock->LockShared();
  630. ScmProcessReg *pResult = _pScmProcessReg;
  631. gpServerLock->UnlockShared();
  632. return pResult;
  633. }
  634. ScmProcessReg*
  635. CProcess::RemoveProcessReg()
  636. /*++
  637. Routine Description:
  638. Called by SCM when COM+ process revokes its activator registration.
  639. Arguments:
  640. None
  641. Return Value:
  642. none.
  643. --*/
  644. {
  645. gpServerLock->LockExclusive();
  646. ScmProcessReg *pResult = _pScmProcessReg;
  647. // Even if this process was a new-style surrogate process, _pScmProcessReg
  648. // may already be NULL here. See bug 26676. So we don't assert anymore
  649. // that _pScmProcessReg is non-NULL.
  650. // ASSERT(_pScmProcessReg);
  651. _pScmProcessReg = NULL;
  652. gpServerLock->UnlockExclusive();
  653. return pResult;
  654. }
  655. void CProcess::RevokeProcessReg()
  656. /*++
  657. Routine Description:
  658. Called during rundown to let SCM know that the COM+ process has died.
  659. CODEWORK: This needs to be defined.
  660. Arguments:
  661. None
  662. Return Value:
  663. none.
  664. --*/
  665. {
  666. }
  667. RPC_BINDING_HANDLE
  668. CProcess::CreateBindingHandle(
  669. void
  670. )
  671. /*++
  672. Routine Description:
  673. Creates a new binding handle back to the process.
  674. Arguments:
  675. None
  676. Return Value:
  677. Binding Handle, NULL if no valid handle.
  678. --*/
  679. {
  680. RPC_STATUS status;
  681. CMutexLock lock(&gcsFastProcessLock);
  682. // Find ncalrpc binding.
  683. PWSTR pwstr = _pdsaLocalBindings->aStringArray;
  684. while (*pwstr)
  685. {
  686. if (*pwstr == ID_LPC)
  687. {
  688. break;
  689. }
  690. pwstr = OrStringSearch(pwstr, 0) + 1;
  691. }
  692. if (*pwstr == 0)
  693. {
  694. KdPrintEx((DPFLTR_DCOMSS_ID,
  695. DPFLTR_WARNING_LEVEL,
  696. "OR: Unable to find ncalrpc binding to server: %p %p\n",
  697. _pdsaLocalBindings,
  698. this));
  699. ASSERT(0);
  700. return NULL;
  701. }
  702. HANDLE hRpc = GetBinding(pwstr);
  703. if (!hRpc)
  704. return NULL;
  705. // Set mutual auth on the binding handle
  706. RPC_SECURITY_QOS_V3 qos;
  707. ZeroMemory(&qos, sizeof(RPC_SECURITY_QOS_V3));
  708. qos.Version = RPC_C_SECURITY_QOS_VERSION_3;
  709. qos.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH |
  710. RPC_C_QOS_CAPABILITIES_LOCAL_MA_HINT;
  711. qos.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC;
  712. qos.ImpersonationType = RPC_C_IMP_LEVEL_IDENTIFY;
  713. qos.AdditionalSecurityInfoType = 0;
  714. qos.Sid = _pToken->GetSid();
  715. status = RpcBindingSetAuthInfoEx(hRpc,
  716. NULL, // pass sid in QOS instead
  717. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  718. RPC_C_AUTHN_WINNT,
  719. NULL,
  720. RPC_C_AUTHZ_NONE,
  721. (RPC_SECURITY_QOS*)&qos);
  722. if (status != RPC_S_OK)
  723. {
  724. status = RpcBindingFree(&hRpc);
  725. ASSERT(status == RPC_S_OK);
  726. hRpc = NULL;
  727. }
  728. return hRpc;
  729. }
  730. BOOL
  731. CProcess::EnsureBindingHandle()
  732. {
  733. if (_hProcess)
  734. return TRUE;
  735. CMutexLock lock(&gcsFastProcessLock);
  736. // Fault in a handle back to the process
  737. // if we haven't already
  738. if (0 == _hProcess)
  739. {
  740. ASSERT(!_fCacheFree);
  741. _hProcess = CreateBindingHandle();
  742. if (!_hProcess)
  743. return FALSE;
  744. _fCacheFree = TRUE;
  745. }
  746. return TRUE;
  747. }
  748. RPC_BINDING_HANDLE
  749. CProcess::AllocateBinding(
  750. void
  751. )
  752. /*++
  753. Routine Description:
  754. Allocates a unique binding handle for a call back
  755. to the process. This binding handle will not be
  756. used by another thread until it is freed.
  757. Arguments:
  758. None
  759. Return Value:
  760. 0 - failure
  761. non-zero - a binding handle to use.
  762. --*/
  763. {
  764. if (!EnsureBindingHandle())
  765. return NULL;
  766. CMutexLock lock(&gcsFastProcessLock);
  767. // If the master copy is available, let
  768. // the caller use it.
  769. if (_fCacheFree)
  770. {
  771. _fCacheFree = FALSE;
  772. return _hProcess;
  773. }
  774. // Otherwise, create a copy
  775. RPC_BINDING_HANDLE hCopy;
  776. RPC_STATUS status;
  777. status = RpcBindingCopy(_hProcess, &hCopy);
  778. if (status != RPC_S_OK)
  779. {
  780. return NULL;
  781. }
  782. return hCopy;
  783. }
  784. void
  785. CProcess::FreeBinding(
  786. IN RPC_BINDING_HANDLE hBinding
  787. )
  788. /*++
  789. Routine Description:
  790. Frees a binding back to the process.
  791. Arguments:
  792. hBinding - A binding back to the process previously
  793. allocated with AllocateBinding().
  794. Return Value:
  795. None
  796. --*/
  797. {
  798. if (hBinding == _hProcess)
  799. {
  800. _fCacheFree = TRUE;
  801. }
  802. else
  803. {
  804. RPC_STATUS status = RpcBindingFree(&hBinding);
  805. ASSERT(status == RPC_S_OK);
  806. }
  807. }
  808. RPC_BINDING_HANDLE CProcess::GetBindingHandle()
  809. /*++
  810. Routine Description:
  811. Creates and returns a binding handle that can be
  812. used to call back to the process. Caller owns the
  813. binding handle and should clean it up by calling
  814. RpcBindingFree.
  815. Arguments:
  816. None
  817. Return Value:
  818. 0 - failure
  819. non-zero - a binding handle to use.
  820. --*/
  821. {
  822. if (!EnsureBindingHandle())
  823. return NULL;
  824. RPC_BINDING_HANDLE hCopy;
  825. RPC_STATUS status;
  826. status = RpcBindingCopy(_hProcess, &hCopy);
  827. if (status != RPC_S_OK)
  828. {
  829. return NULL;
  830. }
  831. return hCopy;
  832. }
  833. RPC_STATUS
  834. CProcess::RundownOids(
  835. IN RPC_BINDING_HANDLE hRpc,
  836. IN CServerOxid* pOwningOxid,
  837. IN ULONG cOids,
  838. IN CServerOid* aOids[]
  839. )
  840. /*++
  841. Routine Description:
  842. Issues an async call to the process which will rundown the OIDs.
  843. This is called from an OXID which will be kept alive during the
  844. whole call. Multiple calls maybe made to this function by
  845. one or more OXIDs at the same time. The callback itself is
  846. an ORPC call, ie is must have THIS and THAT pointers.
  847. Arguments:
  848. hRpc -- rpc binding handle with which to make the call. Caller owns.
  849. pOwningOxid - oxid that owns the specified oids. This oxid should
  850. be registered from this process.
  851. cOids - The number of entries in aOids and afRundownOk
  852. aOids - An array of CServerOid's to rundown. The OIDs must
  853. all be owned by pOwningOxid. The caller will have already
  854. called SetRundown(TRUE) on each one.
  855. Return Value:
  856. RPC_S_OK - the async call was issued successfully
  857. other -- error occurred. call was not issued.
  858. --*/
  859. {
  860. ULONG i;
  861. error_status_t status = OR_OK;
  862. RPC_BINDING_HANDLE hBinding;
  863. OID aScalarOids[MAX_OID_RUNDOWNS_PER_CALL];
  864. ASSERT(hRpc);
  865. ASSERT(cOids > 0 && aOids);
  866. ASSERT(cOids <= MAX_OID_RUNDOWNS_PER_CALL);
  867. ASSERT(IsOwner(pOwningOxid));
  868. // Callers must be aware that the lock will be released upon return
  869. ASSERT(gpServerLock->HeldExclusive());
  870. gpServerLock->UnlockExclusive();
  871. // This process will be held alive by the OXID calling
  872. // us since it has an extra reference.
  873. //
  874. // Allocate async structure and zero it out
  875. //
  876. ASYNCRUNDOWNOID_STUFF* pArgs = new ASYNCRUNDOWNOID_STUFF;
  877. if (!pArgs)
  878. return OR_NOMEM;
  879. ZeroMemory(pArgs, sizeof(ASYNCRUNDOWNOID_STUFF));
  880. //
  881. // Initialize RPC async state
  882. //
  883. status = RpcAsyncInitializeHandle(&(pArgs->async), sizeof(pArgs->async));
  884. if (status != RPC_S_OK)
  885. {
  886. delete pArgs;
  887. return status;
  888. }
  889. //
  890. // Initialize async structure
  891. //
  892. pArgs->dwSig = ASYNCRUNDOWNOID_SIG;
  893. pArgs->pProcess = this; // we take a reference further below
  894. pArgs->pOxid = pOwningOxid; // we take a reference further below
  895. pArgs->cOids = cOids;
  896. CopyMemory(pArgs->aOids, aOids, cOids * sizeof(CServerOid*));
  897. //
  898. // Fill in the numeric oid values
  899. //
  900. ZeroMemory(aScalarOids, sizeof(OID) * MAX_OID_RUNDOWNS_PER_CALL);
  901. for (i = 0; i < cOids; i++)
  902. {
  903. ASSERT(pArgs->aOids[i]);
  904. ASSERT(pArgs->aOids[i]->IsRunningDown());
  905. ASSERT(pArgs->aOids[i]->GetOxid() == pOwningOxid);
  906. aScalarOids[i] = pArgs->aOids[i]->Id();
  907. }
  908. //
  909. // Save the binding handle. This is not strictly necessary now that
  910. // the soxid supplies the handle and owns its lifetime, but might be
  911. // useful in a debugging situation.
  912. //
  913. pArgs->hBinding = hRpc;
  914. //
  915. // Init parts of the RPC_ASYNC_STATE struct that we care about
  916. //
  917. pArgs->async.Flags = 0; // the absence of RPC_C_NOTIFY_ON_SEND_COMPLETE flag means
  918. // notify us on call completion, and no sooner.
  919. pArgs->async.UserInfo = pArgs;
  920. pArgs->async.NotificationType = RpcNotificationTypeCallback;
  921. pArgs->async.u.NotificationRoutine = CProcess::AsyncRundownReturnNotification;
  922. //
  923. // Initialize other params
  924. //
  925. pArgs->orpcthis.version.MajorVersion = COM_MAJOR_VERSION;
  926. pArgs->orpcthis.version.MinorVersion = COM_MINOR_VERSION;
  927. pArgs->orpcthis.flags = ORPCF_LOCAL;
  928. pArgs->orpcthis.reserved1 = 0;
  929. pArgs->orpcthis.extensions = NULL;
  930. pArgs->callIDHint = AllocateCallId(pArgs->orpcthis.cid);
  931. pArgs->localthis.dwClientThread = 0;
  932. pArgs->localthis.dwFlags = LOCALF_NONE;
  933. pArgs->orpcthat.flags = 0;
  934. pArgs->orpcthat.extensions = 0;
  935. //
  936. // Take an extra reference on the owning oxid and ourself.
  937. // These references will be released either on the call
  938. // return notification, or on the failure path below.
  939. //
  940. pOwningOxid->Reference();
  941. this->Reference(); // non-client ref, will not stop rundown
  942. //
  943. // Finally, issue the call. Note that this is an async call
  944. // from our perspective, but is a synchronous ORPC call from
  945. // the server's perspective.
  946. //
  947. status = RawRundownOid(
  948. &(pArgs->async),
  949. pArgs->hBinding,
  950. &(pArgs->orpcthis),
  951. &(pArgs->localthis),
  952. &(pArgs->orpcthat),
  953. pArgs->cOids,
  954. aScalarOids,
  955. pArgs->aRundownStatus
  956. );
  957. if (status != RPC_S_OK)
  958. {
  959. // If we get anything other than RPC_S_OK back, that
  960. // means we will not receive a call completion notif-
  961. // ication. So, we need to cleanup everything up
  962. // right here in that case.
  963. // Call failed, so cleanup before returning. Caller will
  964. // handle the failure semantics for the oids.
  965. FreeCallId(pArgs->callIDHint);
  966. delete pArgs;
  967. //
  968. // Must hold gpServerLock in order to call Release.
  969. //
  970. ASSERT(!gpServerLock->HeldExclusive());
  971. gpServerLock->LockExclusive();
  972. pOwningOxid->Release();
  973. this->Release();
  974. gpServerLock->UnlockExclusive();
  975. ASSERT(!gpServerLock->HeldExclusive());
  976. }
  977. return status;
  978. }
  979. void
  980. CProcess::RundownOidNotify(CServerOxid* pOwningOxid,
  981. ULONG cOids,
  982. CServerOid* aOids[],
  983. BYTE aRundownStatus[],
  984. HRESULT hrReturn)
  985. /*++
  986. Routine Description:
  987. This is the callback notification function that is invoked when
  988. async oid rundown calls are completed.
  989. Arguments:
  990. pOwningOxid -- owning oxid of the oids we tried to rundown.
  991. cOids -- count of oids
  992. aOids -- array of oids
  993. aRundownStatus -- array of individual status rundowns for each oid
  994. hrReturn -- return value from the function
  995. Return Value:
  996. void
  997. --*/
  998. {
  999. ULONG i;
  1000. error_status_t status = OR_OK;
  1001. ASSERT(pOwningOxid);
  1002. ASSERT((cOids > 0) && aOids && aRundownStatus);
  1003. //
  1004. // If destination oxid\apartment was not found, mark all
  1005. // oids for rundown.
  1006. //
  1007. if (hrReturn == RPC_E_DISCONNECTED)
  1008. {
  1009. KdPrintEx((DPFLTR_DCOMSS_ID,
  1010. DPFLTR_WARNING_LEVEL,
  1011. "OR: Rundown returned disconnected\n"));
  1012. for (i = 0; i < cOids; i++)
  1013. {
  1014. aRundownStatus[i] = ORS_OK_TO_RUNDOWN;
  1015. }
  1016. hrReturn = RPC_S_OK;
  1017. }
  1018. //
  1019. // In case of any other error, don't rundown the oids
  1020. //
  1021. if (hrReturn != S_OK)
  1022. {
  1023. for (i = 0; i < cOids; i++)
  1024. {
  1025. aRundownStatus[i] = ORS_DONTRUNDOWN;
  1026. }
  1027. }
  1028. //
  1029. // Notify the server oxid of the results
  1030. //
  1031. gpServerLock->LockExclusive();
  1032. pOwningOxid->ProcessRundownResults(
  1033. cOids,
  1034. aOids,
  1035. aRundownStatus
  1036. );
  1037. ASSERT(!gpServerLock->HeldExclusive());
  1038. return;
  1039. }
  1040. void
  1041. CProcess::ExamineRpcAsyncCompleteCallReturnCode(RPC_STATUS status)
  1042. /*++
  1043. Routine Description:
  1044. This function adds some diagnostic asserts for the various return
  1045. values we might get back from RpcAsyncCompleteCall. It is still
  1046. the caller's responsibility to appropriately handle any errors.
  1047. ++*/
  1048. {
  1049. switch (status)
  1050. {
  1051. case RPC_S_OK:
  1052. // Normal case
  1053. break;
  1054. case RPC_S_OUT_OF_MEMORY:
  1055. // This means that an internal RPC operation failed. Kamenm
  1056. // says in this case we can't depend on the state of the call's
  1057. // out-params, but all rpc-runtime allocated resources should
  1058. // be cleaned up, so no leaks.
  1059. break;
  1060. case RPC_S_ASYNC_CALL_PENDING:
  1061. case RPC_S_INVALID_ASYNC_HANDLE:
  1062. case RPC_S_INVALID_ASYNC_CALL:
  1063. case RPC_S_INVALID_ARG:
  1064. // Any of these error codes usually signify a caller coding error. So
  1065. // we assert. Unfortunately there is not much else we can do; also RPC
  1066. // will likely leak resources.
  1067. ASSERT(!"Got error back from RpcAsyncCompleteCall, possible COM bug");
  1068. break;
  1069. default:
  1070. // No clue. Most often this is because the server process died (0x6be)
  1071. break;
  1072. };
  1073. return;
  1074. }
  1075. void RPC_ENTRY
  1076. CProcess::AsyncRundownReturnNotification(
  1077. IN RPC_ASYNC_STATE* pAsync,
  1078. IN void* pContext,
  1079. IN RPC_ASYNC_EVENT Event
  1080. )
  1081. /*++
  1082. Routine Description:
  1083. This is the callback notification function that is invoked when
  1084. async rundown calls are completed. It unpacks the necessary
  1085. stuff from the async args struct, forwards them on to
  1086. RundownOidNotify, and does other necessary cleanup.
  1087. Arguments:
  1088. pAsync -- pointer to the async rpc state struct
  1089. pContext -- rpc thingy, we ignore it
  1090. Event -- should always be RpcCallComplete
  1091. Return Value:
  1092. void
  1093. --*/
  1094. {
  1095. RPC_STATUS status;
  1096. HRESULT hrRetVal;
  1097. ASYNCRUNDOWNOID_STUFF* pArgs;
  1098. pArgs = (ASYNCRUNDOWNOID_STUFF*)
  1099. (((char*)pAsync) - offsetof(ASYNCRUNDOWNOID_STUFF, async));
  1100. ASSERT(pArgs->async.UserInfo = pArgs);
  1101. ASSERT(pArgs->dwSig == ASYNCRUNDOWNOID_SIG);
  1102. ASSERT(pArgs->hBinding);
  1103. ASSERT(pArgs->pProcess);
  1104. ASSERT(pArgs->pOxid);
  1105. ASSERT(pArgs->cOids > 0);
  1106. ASSERT(pAsync->Event == RpcCallComplete);
  1107. ASSERT(Event == RpcCallComplete);
  1108. //
  1109. // Free the call id
  1110. //
  1111. FreeCallId(pArgs->callIDHint);
  1112. //
  1113. // Complete the call. Even on successful call completion,
  1114. // hrRetVal is not necessarily S_OK.
  1115. //
  1116. status = RpcAsyncCompleteCall(&(pArgs->async), &hrRetVal);
  1117. ExamineRpcAsyncCompleteCallReturnCode(status);
  1118. //
  1119. // Notify the process object that the call has returned
  1120. //
  1121. pArgs->pProcess->RundownOidNotify(
  1122. pArgs->pOxid,
  1123. pArgs->cOids,
  1124. pArgs->aOids,
  1125. pArgs->aRundownStatus,
  1126. (status == RPC_S_OK) ? hrRetVal : E_FAIL
  1127. );
  1128. //
  1129. // Cleanup other stuff from the call
  1130. //
  1131. if (status == RPC_S_OK && pArgs->orpcthat.extensions)
  1132. {
  1133. for (ULONG i = 0; i < pArgs->orpcthat.extensions->size; i++)
  1134. {
  1135. MIDL_user_free(pArgs->orpcthat.extensions->extent[i]);
  1136. }
  1137. MIDL_user_free(pArgs->orpcthat.extensions->extent);
  1138. MIDL_user_free(pArgs->orpcthat.extensions);
  1139. }
  1140. //
  1141. // Release the references on ourselves and the server
  1142. // oxid. Must hold gpServerLock while calling Release.
  1143. //
  1144. gpServerLock->LockExclusive();
  1145. pArgs->pProcess->Release();
  1146. pArgs->pOxid->Release();
  1147. gpServerLock->UnlockExclusive();
  1148. delete pArgs;
  1149. return;
  1150. }
  1151. ORSTATUS
  1152. CProcess::UseProtseqIfNeeded(
  1153. IN USHORT cClientProtseqs,
  1154. IN USHORT aClientProtseqs[]
  1155. )
  1156. {
  1157. ORSTATUS status;
  1158. RPC_BINDING_HANDLE hBinding;
  1159. UUID NullUuid = {0};
  1160. USHORT wProtseqTowerId;
  1161. KdPrintEx((DPFLTR_DCOMSS_ID,
  1162. DPFLTR_WARNING_LEVEL,
  1163. "OR: UseProtseqIfNeeded ==> %d\n",
  1164. cClientProtseqs));
  1165. // This process will be held alive by the OXID calling
  1166. // us since it has an extra reference.
  1167. CMutexLock process(&gcsFastProcessLock);
  1168. // Another thread may have used the protseq in the mean time.
  1169. ASSERT(_pdsaLocalBindings);
  1170. KdPrintEx((DPFLTR_DCOMSS_ID,
  1171. DPFLTR_WARNING_LEVEL,
  1172. "OR: FindMatchingProtSeq from local bindings\n"));
  1173. // ronans - initially _pdsaLocalBindings will hold bindings which have been set
  1174. // by when the server called ServerAllocateOxidAndOids .. usually only local
  1175. // protseqs LRPC or WMSG at that point.
  1176. wProtseqTowerId = FindMatchingProtseq(cClientProtseqs,
  1177. aClientProtseqs,
  1178. _pdsaLocalBindings->aStringArray
  1179. );
  1180. if (0 != wProtseqTowerId)
  1181. {
  1182. KdPrintEx((DPFLTR_DCOMSS_ID,
  1183. DPFLTR_WARNING_LEVEL,
  1184. "OR: Found protseq in local bindings\n"));
  1185. return(OR_OK);
  1186. }
  1187. // No protseq shared between the client and the OXIDs' server.
  1188. // Find a matching protseq.
  1189. // check if its a solitary local protocol sequence LRPC or WMSG
  1190. if (cClientProtseqs == 1 && IsLocal(aClientProtseqs[0]))
  1191. {
  1192. // if so - get it
  1193. wProtseqTowerId = aClientProtseqs[0];
  1194. ASSERT(wProtseqTowerId);
  1195. }
  1196. else
  1197. // we have multiple protseqs - presumed to be nonlocal
  1198. {
  1199. // ensure we have custom protseq information
  1200. if (!_fReadCustomProtseqs)
  1201. {
  1202. // use local temporary to avoid holding process lock
  1203. DUALSTRINGARRAY *pdsaCustomProtseqs = NULL;
  1204. // Release the lock before we call the server
  1205. process.Unlock();
  1206. hBinding = AllocateBinding();
  1207. if (0 == hBinding)
  1208. return(OR_NOMEM);
  1209. status = RpcBindingSetObject(hBinding, &NullUuid);
  1210. // get the information from the Object server
  1211. if (status == RPC_S_OK)
  1212. {
  1213. status = ::GetCustomProtseqInfo(hBinding,cMyProtseqs, aMyProtseqs, &pdsaCustomProtseqs);
  1214. KdPrintEx((DPFLTR_DCOMSS_ID,
  1215. DPFLTR_WARNING_LEVEL,
  1216. "GetCustomProtseqInfo - status : %ld\n",
  1217. status));
  1218. }
  1219. FreeBinding(hBinding);
  1220. if (status == RPC_S_OK)
  1221. {
  1222. // relock the process object
  1223. process.Lock();
  1224. // Make sure another thread didn't beat us. Note that we're
  1225. // assuming that the server (ole32) will give us back the same
  1226. // answer each time. If they don't, then shame on them.
  1227. if (!_fReadCustomProtseqs)
  1228. {
  1229. // Don't make any more calls to the server
  1230. _fReadCustomProtseqs = TRUE;
  1231. if (pdsaCustomProtseqs)
  1232. {
  1233. ASSERT(dsaValid(pdsaCustomProtseqs));
  1234. }
  1235. _pdsaCustomProtseqs = pdsaCustomProtseqs;
  1236. }
  1237. else
  1238. {
  1239. // We got beat. Free our copy
  1240. MIDL_user_free( pdsaCustomProtseqs );
  1241. }
  1242. }
  1243. // else keep going.
  1244. // CODEWORK: this error path should be tightened up in future --
  1245. // ie, return an error at this point, and then re-try the
  1246. // GetCustomProtseqInfo call until it succeeds.
  1247. }
  1248. USHORT i,j;
  1249. // if there is custom protseq information - scan it for a match
  1250. if (_pdsaCustomProtseqs)
  1251. {
  1252. KdPrintEx((DPFLTR_DCOMSS_ID,
  1253. DPFLTR_WARNING_LEVEL,
  1254. "OR: Using custom protseq information\n"));
  1255. wProtseqTowerId = FindMatchingProtseq(cClientProtseqs,
  1256. aClientProtseqs,
  1257. _pdsaCustomProtseqs->aStringArray);
  1258. if (wProtseqTowerId)
  1259. {
  1260. ASSERT(FALSE == IsLocal(wProtseqTowerId));
  1261. }
  1262. }
  1263. else
  1264. // we don't have custom protseqs so use
  1265. // the standard ones
  1266. {
  1267. KdPrintEx((DPFLTR_DCOMSS_ID,
  1268. DPFLTR_WARNING_LEVEL,
  1269. "OR: Using standard protseq information\n"));
  1270. for (i = 0; i < cClientProtseqs && wProtseqTowerId == 0; i++)
  1271. {
  1272. for (j = 0; j < cMyProtseqs; j++)
  1273. {
  1274. if (aMyProtseqs[j] == aClientProtseqs[i])
  1275. {
  1276. ASSERT(FALSE == IsLocal(aMyProtseqs[j]));
  1277. wProtseqTowerId = aMyProtseqs[j];
  1278. break;
  1279. }
  1280. }
  1281. }
  1282. }
  1283. }
  1284. if (0 == wProtseqTowerId)
  1285. {
  1286. // No shared protseq, must be a bug since the client managed to call us.
  1287. ASSERT(0 && "No shared protseq, must be a bug since the client managed to call us");
  1288. #if DBG
  1289. if (cClientProtseqs == 0)
  1290. KdPrintEx((DPFLTR_DCOMSS_ID,
  1291. DPFLTR_WARNING_LEVEL,
  1292. "OR: Client OR not configured to use remote protseqs\n"));
  1293. else
  1294. KdPrintEx((DPFLTR_DCOMSS_ID,
  1295. DPFLTR_WARNING_LEVEL,
  1296. "OR: Client called on an unsupported protocol:"
  1297. "%d %p %p \n",
  1298. cClientProtseqs,
  1299. aClientProtseqs,
  1300. aMyProtseqs));
  1301. #endif
  1302. return(OR_NOSERVER);
  1303. }
  1304. process.Unlock();
  1305. DUALSTRINGARRAY *pdsaBinding = 0;
  1306. DUALSTRINGARRAY *pdsaSecurity = 0;
  1307. hBinding = AllocateBinding();
  1308. if (0 == hBinding)
  1309. {
  1310. return(OR_NOMEM);
  1311. }
  1312. status = RpcBindingSetObject(hBinding, &NullUuid);
  1313. if (status == RPC_S_OK)
  1314. {
  1315. status = ::UseProtseq(hBinding,
  1316. wProtseqTowerId,
  1317. &pdsaBinding,
  1318. &pdsaSecurity);
  1319. }
  1320. KdPrintEx((DPFLTR_DCOMSS_ID,
  1321. DPFLTR_WARNING_LEVEL,
  1322. "OR: Lazy use protseq: %S (from towerid) in process %p - %d\n",
  1323. GetProtseq(wProtseqTowerId),
  1324. this,
  1325. status));
  1326. // Update this process' state to include the new bindings.
  1327. if (!dsaValid(pdsaBinding))
  1328. {
  1329. if (pdsaBinding)
  1330. {
  1331. KdPrintEx((DPFLTR_DCOMSS_ID,
  1332. DPFLTR_WARNING_LEVEL,
  1333. "OR: Use protseq returned an invalid dsa: %p\n",
  1334. pdsaBinding));
  1335. }
  1336. status = OR_NOMEM;
  1337. }
  1338. else
  1339. {
  1340. ASSERT(_pdsaLocalBindings);
  1341. ASSERT(status == RPC_S_OK);
  1342. status = ProcessBindings(pdsaBinding, pdsaSecurity);
  1343. }
  1344. if (pdsaBinding != NULL)
  1345. MIDL_user_free(pdsaBinding);
  1346. if (pdsaSecurity != NULL)
  1347. MIDL_user_free(pdsaSecurity);
  1348. FreeBinding(hBinding);
  1349. return(status);
  1350. }
  1351. ORSTATUS CProcess::UpdateResolverBindings(DWORD64 dwBindingsID, DUALSTRINGARRAY* pdsaResolverBindings)
  1352. /*++
  1353. Routine Description:
  1354. This function does the work of calling back into the server process
  1355. to tell it to update its local OR bindings. It also updates our
  1356. cached local\remote bindings for this process object.
  1357. Arguments:
  1358. dwBindingsID -- unique id of pdsaResolverBindings. We use this
  1359. to resolve what to do when async calls arrive\return in an
  1360. out-of-order fashion.
  1361. pdsaResolverBindings -- ptr to the new resolver bindings
  1362. Return Value:
  1363. OR_OK -- success
  1364. OR_NOMEM -- out of memory
  1365. other -- unexpected error
  1366. --*/
  1367. {
  1368. ORSTATUS status;
  1369. RPC_BINDING_HANDLE hBinding;
  1370. UUID NullUuid = {0};
  1371. DUALSTRINGARRAY* pdsaBinding = NULL;
  1372. DUALSTRINGARRAY* pdsaSecurity = NULL;
  1373. BINDINGS_UPDATE_CALLBACK_STUFF* pArgs = NULL;
  1374. CMutexLock process(&gcsFastProcessLock);
  1375. if (dwBindingsID <= _dwCurrentBindingsID)
  1376. {
  1377. // The supplied bindings are the same or older than
  1378. // what we already have, so ignore them.
  1379. return OR_OK;
  1380. }
  1381. // if the server has not yet called _ServerAllocateOxidAndOids
  1382. // then we will not yet have cached binding info for them, and
  1383. // hence will be unable to construct a binding handle. In
  1384. // this case we simply do not update that process. If this
  1385. // happens we will give them the new bindings later, if and
  1386. // when they do call _SAOAO.
  1387. if (!_pdsaLocalBindings)
  1388. {
  1389. FlagsOn(PROCESS_NEEDSBINDINGS);
  1390. return OR_OK;
  1391. }
  1392. // Done with the lock.
  1393. process.Unlock();
  1394. pArgs = new BINDINGS_UPDATE_CALLBACK_STUFF;
  1395. if (!pArgs)
  1396. return OR_NOMEM;
  1397. ZeroMemory(pArgs, sizeof(BINDINGS_UPDATE_CALLBACK_STUFF));
  1398. // Allocate binding. We must hold onto the binding handle
  1399. // until the async call has completed.
  1400. status = OR_NOMEM;
  1401. hBinding = AllocateBinding();
  1402. if (hBinding)
  1403. {
  1404. status = RpcBindingSetObject(hBinding, &NullUuid);
  1405. if (status == RPC_S_OK)
  1406. {
  1407. status = RpcAsyncInitializeHandle(&(pArgs->async), sizeof(pArgs->async));
  1408. }
  1409. }
  1410. // Check for errors
  1411. if (status != RPC_S_OK)
  1412. {
  1413. if (hBinding) FreeBinding(hBinding);
  1414. delete pArgs;
  1415. return status;
  1416. }
  1417. // Init parts of the RPC_ASYNC_STATE struct that we care about
  1418. pArgs->async.Flags = 0; // the absence of RPC_C_NOTIFY_ON_SEND_COMPLETE flag means
  1419. // notify us on call completion, and no sooner.
  1420. pArgs->async.UserInfo = pArgs;
  1421. pArgs->async.NotificationType = RpcNotificationTypeCallback;
  1422. pArgs->async.u.NotificationRoutine = CProcess::AsyncRpcNotification;
  1423. // Init other stuff
  1424. pArgs->dwSig = BINDINGUPDATESTUFF_SIG;
  1425. pArgs->pProcess = this;
  1426. pArgs->dwBindingsID = dwBindingsID;
  1427. pArgs->hBinding = hBinding;
  1428. // Take a non-client reference (will not stop rundown) on
  1429. // ourselves, to be owned implicitly by the async call
  1430. this->Reference();
  1431. // Issue async call
  1432. status = ::UpdateResolverBindings(
  1433. &(pArgs->async),
  1434. _hProcess,
  1435. pdsaResolverBindings,
  1436. &(pArgs->dwBindingsID),
  1437. &(pArgs->pdsaNewBindings),
  1438. &(pArgs->pdsaNewSecurity));
  1439. if (status != RPC_S_OK)
  1440. {
  1441. // If we get anything other than RPC_S_OK back, that
  1442. // means we will not receive a call completion notif-
  1443. // ication. So, we need to cleanup everything up
  1444. // right here in that case.
  1445. FreeBinding(hBinding);
  1446. this->Release();
  1447. delete pArgs;
  1448. }
  1449. else
  1450. {
  1451. DWORD dwAUO = (DWORD)InterlockedIncrement((PLONG)&_dwAsyncUpdatesOutstanding);
  1452. // This assert is somewhat arbitrary, if it fires there are
  1453. // one of two things wrong: 1) the machine is so totally
  1454. // overstressed that the async calls are piling up and are not
  1455. // getting enough cpu time to complete; or 2) more likely, the
  1456. // process in question is deadlocked somehow.
  1457. ASSERT(dwAUO < 5000);
  1458. }
  1459. return status;
  1460. }
  1461. void
  1462. CProcess::BindingsUpdateNotify(RPC_BINDING_HANDLE hBinding,
  1463. DWORD64 dwBindingsID,
  1464. DUALSTRINGARRAY* pdsaNewBindings,
  1465. DUALSTRINGARRAY* pdsaSecBindings,
  1466. HRESULT hrReturn)
  1467. /*++
  1468. Routine Description:
  1469. Private helper function. This function is used to process a
  1470. successful return from an async call to the process to update
  1471. the bindings.
  1472. Arguments:
  1473. hBinding -- binding handle used to make the call. We now own it,
  1474. either to keep or to cleanup.
  1475. dwBindingsID -- unique id of the updated bindings. We use this
  1476. to resolve what to do when async calls arrive\return in an
  1477. out-of-order fashion.
  1478. pdsaNewBindings -- new bindings in use by the process. We now own
  1479. it, either to keep or to cleanup
  1480. pdsaSecBindings -- new security bindings in use by the process. We
  1481. now own it, either to keep or to cleanup.
  1482. hrReturn -- the result of the operation.
  1483. Return Value:
  1484. void
  1485. --*/
  1486. {
  1487. RPC_STATUS status;
  1488. // Always free the binding
  1489. FreeBinding(hBinding);
  1490. // Only process the out-params if the operation was a success; otherwise
  1491. // ignore everthing.
  1492. if (hrReturn == S_OK)
  1493. {
  1494. // Take lock while looking at _dwCurrentBindingsID
  1495. CMutexLock process(&gcsFastProcessLock);
  1496. // Only process the out-params if they contain newer bindings
  1497. // than what we currently have cached.
  1498. if ((dwBindingsID > _dwCurrentBindingsID) &&
  1499. pdsaNewBindings &&
  1500. pdsaSecBindings)
  1501. {
  1502. // The process has the right bindings, so update our counter
  1503. // no matter what happens in ProcessBindings.
  1504. _dwCurrentBindingsID = dwBindingsID;
  1505. status = ProcessBindings(pdsaNewBindings, pdsaSecBindings);
  1506. }
  1507. // No lock needed from here on out
  1508. process.Unlock();
  1509. // Cleanup allocated out-params
  1510. if (pdsaNewBindings != NULL)
  1511. MIDL_user_free(pdsaNewBindings);
  1512. if (pdsaSecBindings != NULL)
  1513. MIDL_user_free(pdsaSecBindings);
  1514. }
  1515. else
  1516. {
  1517. // Assert that on an error path we are not leaking memory.
  1518. ASSERT(NULL == pdsaNewBindings);
  1519. ASSERT(NULL == pdsaSecBindings);
  1520. }
  1521. InterlockedDecrement((PLONG)&_dwAsyncUpdatesOutstanding);
  1522. return;
  1523. }
  1524. void RPC_ENTRY
  1525. CProcess::AsyncRpcNotification(RPC_ASYNC_STATE* pAsync,
  1526. void* pContext,
  1527. RPC_ASYNC_EVENT Event)
  1528. /*++
  1529. Routine Description:
  1530. RPC calls this static function when an async call to a server
  1531. process returns.
  1532. Arguments:
  1533. pAsync -- pointer to the async rpc state struct
  1534. pContext -- rpc thingy, we ignore it
  1535. Event -- should always be RpcCallComplete
  1536. Return Value:
  1537. void
  1538. --*/
  1539. {
  1540. RPC_STATUS status;
  1541. HRESULT hrRetVal;
  1542. BINDINGS_UPDATE_CALLBACK_STUFF* pArgs;
  1543. pArgs = (BINDINGS_UPDATE_CALLBACK_STUFF*)
  1544. (((char*)pAsync) - offsetof(BINDINGS_UPDATE_CALLBACK_STUFF, async));
  1545. ASSERT(pArgs->async.UserInfo = pArgs);
  1546. ASSERT(pArgs->dwSig == BINDINGUPDATESTUFF_SIG);
  1547. ASSERT(pArgs->hBinding);
  1548. ASSERT(pArgs->pProcess);
  1549. ASSERT(pArgs->dwBindingsID > 0);
  1550. ASSERT(pAsync->Event == RpcCallComplete);
  1551. ASSERT(Event == RpcCallComplete);
  1552. // Complete the call. Since we've asked for a direct callback upon
  1553. // completion, we should never get back RPC_S_ASYNC_CALL_PENDING, so
  1554. // we assert on this. Otherwise, both RPC and the server need to
  1555. // return success before we do further processing.
  1556. status = RpcAsyncCompleteCall(&(pArgs->async), &hrRetVal);
  1557. ExamineRpcAsyncCompleteCallReturnCode(status);
  1558. // Deliver notification to process object. Process may have
  1559. // already been rundown, that's okay. BindingsUpdateNotify will
  1560. // own/cleanup the params, see code.
  1561. pArgs->pProcess->BindingsUpdateNotify(pArgs->hBinding,
  1562. pArgs->dwBindingsID,
  1563. pArgs->pdsaNewBindings,
  1564. pArgs->pdsaNewSecurity,
  1565. (status == RPC_S_OK) ? hrRetVal : E_FAIL);
  1566. gpServerLock->LockExclusive();
  1567. // This may be the last release on the process object
  1568. pArgs->pProcess->Release();
  1569. gpServerLock->UnlockExclusive();
  1570. delete pArgs;
  1571. return;
  1572. }
  1573. void
  1574. CProcess::FlagsOn(DWORD dwOn)
  1575. {
  1576. for (;;)
  1577. {
  1578. DWORD dwCurrent = _dwFlags;
  1579. DWORD dwNew = dwCurrent | dwOn;
  1580. if (dwCurrent == (ULONG)InterlockedCompareExchange(
  1581. (LONG*)&_dwFlags,
  1582. dwNew,
  1583. dwCurrent))
  1584. {
  1585. break;
  1586. }
  1587. }
  1588. }
  1589. void
  1590. CProcess::FlagsOff(DWORD dwOff)
  1591. {
  1592. for (;;)
  1593. {
  1594. DWORD dwCurrent = _dwFlags;
  1595. DWORD dwNew = dwCurrent & ~dwOff;
  1596. if (dwCurrent == (ULONG)InterlockedCompareExchange(
  1597. (LONG*)&_dwFlags,
  1598. dwNew,
  1599. dwCurrent))
  1600. {
  1601. break;
  1602. }
  1603. }
  1604. }
  1605. CBList *gpProcessList = 0;
  1606. CProcess *
  1607. ReferenceProcess(
  1608. IN PVOID key,
  1609. IN BOOL fNotContext)
  1610. /*++
  1611. Routine Description:
  1612. Used to find a CProcess and get a reference on it
  1613. Arguments:
  1614. key - The dword key of the process allocated in _Connect.
  1615. fNotContext - Normally the key is stored as a context handle
  1616. which means locking is unnecessary. There is an extra
  1617. refernce which is released buring context rundown which
  1618. means managers using the key as a context handle
  1619. a) Don't need to lock the process and
  1620. b) Don't need to call ReleaseProcess()
  1621. Return Value:
  1622. 0 - invalid key
  1623. non-zero - The process.
  1624. --*/
  1625. {
  1626. ASSERT(gpProcessList != 0);
  1627. CProcess *pProcess;
  1628. if (!key)
  1629. return NULL;
  1630. gpProcessListLock->LockShared();
  1631. if (gpProcessList->Member(key) == FALSE)
  1632. {
  1633. gpProcessListLock->UnlockShared();
  1634. return(0);
  1635. }
  1636. pProcess = (CProcess *)key;
  1637. if (fNotContext)
  1638. {
  1639. pProcess->ClientReference();
  1640. }
  1641. gpProcessListLock->UnlockShared();
  1642. return(pProcess);
  1643. }
  1644. void ReleaseProcess(CProcess *pProcess)
  1645. /*++
  1646. Routine Description:
  1647. Releases a pProcess object. This should only be called when
  1648. a process object has been referenced with the fNotContext == TRUE.
  1649. Arguments:
  1650. pProcess - the process to release. May actually be deleted.
  1651. Return Value:
  1652. None
  1653. --*/
  1654. {
  1655. gpProcessListLock->LockExclusive();
  1656. if (pProcess->ClientRelease() == 0)
  1657. {
  1658. // Process has been completely released,
  1659. // we'll remove it from the list now since we
  1660. // already have the lock. It may not have been
  1661. // added, so this may fail.
  1662. PVOID t = gpProcessList->Remove(pProcess);
  1663. ASSERT(t == pProcess || t == 0);
  1664. gpProcessListLock->UnlockExclusive();
  1665. // The client process owns one real reference which will be
  1666. // released in Rundown().
  1667. pProcess->Rundown();
  1668. }
  1669. else
  1670. {
  1671. gpProcessListLock->UnlockExclusive();
  1672. }
  1673. }
  1674. BOOL VerifyNewProcess(DWORD dwPID)
  1675. /*++
  1676. Routine Description:
  1677. Checks to see if we already have a registered active
  1678. process with the specified pid.
  1679. Arguments:
  1680. dwPID - pid of the new client
  1681. Return Value:
  1682. TRUE - the process is not known to us
  1683. FALSE - an existing entry already exists for this pid
  1684. Notes: there is a tiny race between the time a process dies
  1685. an abnormal death and the time we receive the rundown. To
  1686. try to account for this, we allow up to MAX_ENTRIES_PER_PID
  1687. registrations for a single pid.
  1688. --*/
  1689. {
  1690. ASSERT(gpProcessListLock->HeldExclusive());
  1691. CProcess* pProcess;
  1692. CBListIterator itor(gpProcessList);
  1693. DWORD dwCurrentEntries = 0;
  1694. const DWORD MAX_ENTRIES_PER_PID = 10;
  1695. while (pProcess = (CProcess*)itor.Next())
  1696. {
  1697. if ((pProcess->GetPID() == dwPID) &&
  1698. (!pProcess->HasBeenRundown()))
  1699. {
  1700. dwCurrentEntries++;
  1701. }
  1702. }
  1703. return (dwCurrentEntries <= MAX_ENTRIES_PER_PID);
  1704. }