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.

1143 lines
38 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: scmrot.hxx
  7. //
  8. // Contents: Implementation of classes for the ROT in the SCM
  9. //
  10. // Functions: RoundTo8 - round size to 8 byte boundary
  11. // CalcIfdSize - calculate size needed for marhaled interface
  12. // SizeMnkEqBufForRotEntry - calculate size for moniker eq buffer
  13. // AllocateAndCopy - create copy of a marshaled interface
  14. // GetEntryFromScmReg - convert SCMREGKEY to ROT entry ptr
  15. //
  16. // History: 20-Jan-95 Ricksa Created
  17. //
  18. //--------------------------------------------------------------------------
  19. #include "act.hxx"
  20. #define DEB_ROT_ADDREMOVE DEB_USER3
  21. //+-------------------------------------------------------------------------
  22. //
  23. // Function: RoundTo8
  24. //
  25. // Synopsis: Round size to next 8 byte boundary
  26. //
  27. // Arguments: [sizeToRound] - Size to round
  28. //
  29. // Returns: Input rounded to the next 8 byte boundary
  30. //
  31. // History: 20-Jan-95 Ricksa Created
  32. //
  33. //--------------------------------------------------------------------------
  34. inline size_t RoundTo8(size_t sizeToRound)
  35. {
  36. return (sizeToRound + 7) & ~7;
  37. }
  38. //+-------------------------------------------------------------------------
  39. //
  40. // Function: CalcIfdSize
  41. //
  42. // Synopsis: Calculate size required by a marshaled interface
  43. //
  44. // Arguments: [pifd] - interface whose size to calculate
  45. //
  46. // Returns: size required for interface
  47. //
  48. // Algorithm: Get size from the interface and round to next 8 bytes so
  49. // data packed following this buffer will be nicely aligned.
  50. //
  51. // History: 20-Jan-95 Ricksa Created
  52. //
  53. //--------------------------------------------------------------------------
  54. size_t CalcIfdSize(InterfaceData *pifd)
  55. {
  56. CairoleDebugOut((DEB_ROT, "%p _IN CalcIfdSize ( %p )\n", NULL,
  57. pifd));
  58. size_t sizeRet = RoundTo8(IFD_SIZE(pifd));
  59. CairoleDebugOut((DEB_ROT, "%p OUT CalcIfdSize ( %lx )\n", NULL,
  60. sizeRet));
  61. return sizeRet;
  62. }
  63. //+-------------------------------------------------------------------------
  64. //
  65. // Function: SizeMnkEqBufForRotEntry
  66. //
  67. // Synopsis: Calculate 8 byte aligned size for moniker equality buffer
  68. //
  69. // Arguments: [pmnkeqbuf] - Moniker equality buffer
  70. //
  71. // Returns: 8 byte aligned size of moniker buffer.
  72. //
  73. // Algorithm: Calculate size for the moniker equality buffer from input
  74. // buffer and then round to next 8 byte boundary
  75. //
  76. // History: 20-Jan-95 Ricksa Created
  77. //
  78. //--------------------------------------------------------------------------
  79. size_t SizeMnkEqBufForRotEntry(MNKEQBUF *pmnkeqbuf)
  80. {
  81. CairoleDebugOut((DEB_ROT, "%p _IN SizeMnkEqBufForRotEntry ( %p )\n", NULL,
  82. pmnkeqbuf));
  83. size_t sizeRet = RoundTo8((sizeof(MNKEQBUF) - 1) + pmnkeqbuf->cdwSize);
  84. CairoleDebugOut((DEB_ROT, "%p OUT SizeMnkEqBufForRotEntry ( %lx )\n", NULL,
  85. sizeRet));
  86. return sizeRet;
  87. }
  88. //+-------------------------------------------------------------------------
  89. //
  90. // Function: AllocateAndCopy
  91. //
  92. // Synopsis: Make a copy of the input marshaled interface
  93. //
  94. // Arguments: [pifdIn] - input marshaled interface.
  95. //
  96. // Returns: Copy of input marshaled interface.
  97. //
  98. // Algorithm: Calculate size required for marshaled interface. Allocate
  99. // memory for the interface and then copy input interface into
  100. // the new buffer.
  101. //
  102. // History: 20-Jan-95 Ricksa Created
  103. //
  104. //--------------------------------------------------------------------------
  105. InterfaceData *AllocateAndCopy(InterfaceData *pifdIn)
  106. {
  107. CairoleDebugOut((DEB_ROT, "%p _IN AllocateAndCopy ( %p )\n", NULL, pifdIn));
  108. size_t cbSizeObj = CalcIfdSize(pifdIn);
  109. InterfaceData *pifd = (InterfaceData *) MIDL_user_allocate(cbSizeObj);
  110. if (pifd)
  111. {
  112. // Copy all the data. Remember that pifdIn was allocated rounded
  113. // to an 8 byte boundary so we will not run off the end of the
  114. // memory buffer
  115. memcpy(pifd, pifdIn, cbSizeObj);
  116. }
  117. CairoleDebugOut((DEB_ROT, "%p OUT AllocateAndCopy ( %lx )\n", NULL, pifd));
  118. return pifd;
  119. }
  120. //+-------------------------------------------------------------------------
  121. //
  122. // Member: CScmRotEntry::CScmRotEntry
  123. //
  124. // Synopsis: Create a ROT entry for a registration
  125. //
  126. // Arguments: [dwScmRotId] - signiture for item
  127. // [pmkeqbuf] - moniker equality buffer to use
  128. // [pfiletime] - file time to use
  129. // [dwProcessID] - process id to use
  130. // [pifdObject] - marshaled interface for the object
  131. // [pifdObjectName] - marshaled moniker for the object
  132. //
  133. // Algorithm: Initialize data and calcualte offsets into the object for
  134. // the variable length data.
  135. //
  136. // History: 20-Jan-95 Ricksa Created
  137. //
  138. //--------------------------------------------------------------------------
  139. CScmRotEntry::CScmRotEntry(
  140. DWORD dwScmRotId,
  141. DWORD dwHash,
  142. MNKEQBUF *pmkeqbuf,
  143. FILETIME *pfiletime,
  144. DWORD dwProcessID,
  145. CToken *pToken,
  146. WCHAR *pwszWinstaDesktop,
  147. InterfaceData *pifdObject,
  148. InterfaceData *pifdObjectName)
  149. : _dwSig(SCMROT_SIG),
  150. _dwScmRotId(dwScmRotId),
  151. _dwHash(dwHash),
  152. _dwProcessID(dwProcessID),
  153. _filetimeLastChange(*pfiletime),
  154. _pifdObject((InterfaceData *) &_ab[0]),
  155. _pProcessNext(NULL),
  156. _cRefs(1)
  157. {
  158. CairoleDebugOut((DEB_ROT, "%p _IN CScmRotEntry::CScmRotEntry "
  159. "( %lx , %p , %p , %lx , %p , %p )\n", this, pmkeqbuf, pfiletime,
  160. dwProcessID, pifdObject, pifdObjectName));
  161. _pToken = pToken;
  162. if ( _pToken )
  163. _pToken->AddRef();
  164. // Copy data for object to preallocated area
  165. _pifdObject->ulCntData = pifdObject->ulCntData;
  166. memcpy(&_pifdObject->abData[0], &pifdObject->abData[0],
  167. _pifdObject->ulCntData);
  168. // Calculate the location of the equality buffer in the allocated data
  169. size_t cbOffsetMnkEqBuf = CalcIfdSize(_pifdObject);
  170. _pmkeqbufKey = (MNKEQBUF *) &_ab[cbOffsetMnkEqBuf];
  171. // Copy data for moniker equality buffer into preallocated area
  172. _pmkeqbufKey->cdwSize = pmkeqbuf->cdwSize;
  173. memcpy(&_pmkeqbufKey->abEqData[0], &pmkeqbuf->abEqData[0],
  174. _pmkeqbufKey->cdwSize);
  175. // Calculate the location of the moniker name buffer
  176. _pifdObjectName = (InterfaceData *)
  177. &_ab[cbOffsetMnkEqBuf + SizeMnkEqBufForRotEntry(_pmkeqbufKey)];
  178. // Copy in the data for the moniker name
  179. _pifdObjectName->ulCntData = pifdObjectName->ulCntData;
  180. memcpy(&_pifdObjectName->abData[0], &pifdObjectName->abData[0],
  181. _pifdObjectName->ulCntData);
  182. if ( pwszWinstaDesktop )
  183. {
  184. _pwszWinstaDesktop = (WCHAR *)
  185. &_ab[cbOffsetMnkEqBuf + SizeMnkEqBufForRotEntry(_pmkeqbufKey) + CalcIfdSize(_pifdObjectName)];
  186. lstrcpyW( _pwszWinstaDesktop, pwszWinstaDesktop );
  187. }
  188. else
  189. {
  190. _pwszWinstaDesktop = NULL;
  191. }
  192. CairoleDebugOut((DEB_ROT, "%p OUT CScmRotEntry::CScmRotEntry \n",
  193. this));
  194. }
  195. //+-------------------------------------------------------------------------
  196. //
  197. // Member: CScmRotEntry::IsEqual
  198. //
  199. // Synopsis: Determine if input key is equal to the ROT entry's key
  200. //
  201. // Arguments: [pKey] - Key to use for the test
  202. // [cbKey] - Count of bytes in key
  203. //
  204. // Returns: TRUE - input key equals this object's key
  205. // FALSE - keys are not equal
  206. //
  207. // Algorithm: If the two sizes are equal then compare the actual data
  208. // buffers and return the result of that compare.
  209. //
  210. // History: 20-Jan-95 Ricksa Created
  211. //
  212. //--------------------------------------------------------------------------
  213. BOOL CScmRotEntry::IsEqual(LPVOID pKey, UINT cbKey)
  214. {
  215. CairoleDebugOut((DEB_ROT, "%p _IN CScmRotEntry::IsEqual "
  216. "( %p , %lx )\n", this, pKey, cbKey));
  217. BOOL fRet = FALSE;
  218. if (cbKey == _pmkeqbufKey->cdwSize)
  219. {
  220. fRet = memcmp(pKey, &_pmkeqbufKey->abEqData[0], cbKey) == 0;
  221. }
  222. CairoleDebugOut((DEB_ROT, "%p OUT CScmRotEntry::IsEqual ( %lx )\n",
  223. this, fRet));
  224. return fRet;
  225. }
  226. //+-------------------------------------------------------------------------
  227. //
  228. // Member: CScmRot::Register
  229. //
  230. // Synopsis: Add entry to the ROT
  231. //
  232. // Arguments: [pmkeqbuf] - moniker equality buffer to use
  233. // [pfiletime] - file time to use
  234. // [dwProcessID] - process id to use
  235. // [pifdObject] - marshaled interface for the object
  236. // [pifdObjectName] - marshaled moniker for the object
  237. //
  238. // Returns: NOERROR - successfully registered
  239. // E_OUTOFMEMORY
  240. //
  241. // Algorithm: Lock the ROT from all other threads. The create a new
  242. // entry and determine if there is an eqivalent entry in
  243. // the ROT. Calculate the hash value and then put the
  244. // entry into our hash table. Finally, build a registration
  245. // key to return to the caller.
  246. //
  247. // History: 20-Jan-95 Ricksa Created
  248. // 07-Mar-02 JohnDoty Hang ROT entries off the process.
  249. //
  250. //--------------------------------------------------------------------------
  251. HRESULT CScmRot::Register(
  252. CProcess *pProcess,
  253. WCHAR *pwszWinstaDesktop,
  254. MNKEQBUF *pmnkeqbuf,
  255. InterfaceData *pifdObject,
  256. InterfaceData *pifdObjectName,
  257. FILETIME *pfiletime,
  258. DWORD dwProcessID,
  259. WCHAR *pwszServerExe,
  260. SCMREGKEY *psrkRegister)
  261. {
  262. CairoleDebugOut((DEB_ROT | DEB_ROT_ADDREMOVE,
  263. "%p _IN CScmRot::Register: Process: %p MNKEQBUF: %p pifdObject: %p pifdObjName: %p\n",
  264. this, pProcess, pifdObject, pifdObjectName));
  265. // Assume that there is a memory problem
  266. HRESULT hr = E_OUTOFMEMORY;
  267. CToken * pToken;
  268. pToken = pProcess->GetToken();
  269. if ( pwszServerExe )
  270. {
  271. HKEY hKey = NULL;
  272. LONG RegStatus;
  273. WCHAR wszAppid[40];
  274. DWORD Size;
  275. RegStatus = ERROR_SUCCESS;
  276. // The pwszServerExe string may contain an AppId string or
  277. // a module name. If it looks like a GUID string, we can bypass
  278. // the AppId lookup. Otherwise, we go to the Registry to
  279. if ( pwszServerExe[0] == L'{' )
  280. {
  281. // Use the given string as the AppId
  282. lstrcpyn(wszAppid, pwszServerExe, sizeof(wszAppid)/sizeof(WCHAR));
  283. }
  284. else
  285. {
  286. // Try to map the Exe name to an AppId
  287. HKEY hAppidMachine = NULL;
  288. DWORD dwDisposition = 0;
  289. // This may fail during GUI mode setup.
  290. RegStatus = RegCreateKeyEx(
  291. HKEY_CLASSES_ROOT,
  292. TEXT("AppID"),
  293. 0,
  294. NULL,
  295. REG_OPTION_NON_VOLATILE,
  296. KEY_READ,
  297. NULL,
  298. &hAppidMachine,
  299. &dwDisposition);
  300. if ( ERROR_SUCCESS == RegStatus )
  301. {
  302. RegStatus = RegOpenKeyEx( hAppidMachine,
  303. pwszServerExe,
  304. NULL,
  305. KEY_READ,
  306. &hKey );
  307. RegCloseKey(hAppidMachine);
  308. }
  309. if ( ERROR_SUCCESS == RegStatus )
  310. {
  311. Size = sizeof(wszAppid);
  312. RegStatus = RegQueryValueEx( hKey,
  313. L"AppId",
  314. NULL,
  315. NULL,
  316. (BYTE *)wszAppid,
  317. &Size );
  318. RegCloseKey( hKey );
  319. }
  320. if ( RegStatus != ERROR_SUCCESS )
  321. return CO_E_WRONG_SERVER_IDENTITY;
  322. }
  323. CAppidData Appid( wszAppid, pToken );
  324. BOOL Access;
  325. Access = FALSE;
  326. // Load appid info
  327. hr = Appid.Load(NULL);
  328. if ( S_OK == hr )
  329. {
  330. // If this is not an activate-as-activator server, then force them to
  331. // pass CertifyServer. You can only register in the ROT if you pass
  332. // CertifyServer.
  333. if ((Appid.GetRunAsType() != RunAsLaunchingUser) ||
  334. (Appid.GetProcessType() == ProcessTypeService))
  335. {
  336. Access = Appid.CertifyServer( pProcess );
  337. }
  338. }
  339. if ( ! Access )
  340. return CO_E_WRONG_SERVER_IDENTITY;
  341. //
  342. // NULL these to indicate that any client can connect to this
  343. // registration.
  344. //
  345. pwszWinstaDesktop = NULL;
  346. pToken = NULL;
  347. }
  348. // Lock to add to the table...
  349. CPortableLock lck(_mxs);
  350. // Bump the id
  351. _dwIdCntr++;
  352. DWORD dwHash = ScmRotHash(&pmnkeqbuf->abEqData[0], pmnkeqbuf->cdwSize, 0);
  353. // Build a record to put into the table
  354. size_t cbExtra = (pwszWinstaDesktop ? (lstrlenW(pwszWinstaDesktop) + 1) : 0) * sizeof(WCHAR);
  355. cbExtra += CalcIfdSize(pifdObject);
  356. cbExtra += SizeMnkEqBufForRotEntry(pmnkeqbuf);
  357. cbExtra += CalcIfdSize(pifdObjectName);
  358. CScmRotEntry *psreNew = new(cbExtra) CScmRotEntry(_dwIdCntr,
  359. dwHash,
  360. pmnkeqbuf,
  361. pfiletime,
  362. dwProcessID,
  363. pToken,
  364. pwszWinstaDesktop,
  365. pifdObject,
  366. pifdObjectName);
  367. if (psreNew != NULL)
  368. {
  369. CScmRotEntry *psreRunning = GetRotEntry( pToken, pwszWinstaDesktop, pmnkeqbuf );
  370. // Put record into the hash table
  371. _sht.SetAt(dwHash, psreNew);
  372. // Update the hint table
  373. _rht.SetIndicator(dwHash);
  374. // Build return value
  375. psreNew->SetScmRegKey(psrkRegister);
  376. // Link to process. The process link owns another reference on the object.
  377. gpServerLock->LockExclusive();
  378. psreNew->SetProcessNext((CScmRotEntry *)pProcess->GetFirstROTEntry());
  379. pProcess->SetFirstROTEntry(psreNew);
  380. psreNew->AddRef();
  381. gpServerLock->UnlockExclusive();
  382. // Map return result based on prior existence of the object.
  383. hr = (psreRunning == NULL)
  384. ? NOERROR : MK_S_MONIKERALREADYREGISTERED;
  385. }
  386. CairoleDebugOut((DEB_ROT | DEB_ROT_ADDREMOVE,
  387. "%p OUT CScmRot::Register: hr: 0x%08x, psrkReg: [ 0x%I64x, %08x, %08x ]\n",
  388. this,
  389. hr,
  390. (SUCCEEDED(hr)) ? psrkRegister->dwEntryLoc : 0,
  391. (SUCCEEDED(hr)) ? psrkRegister->dwHash : 0,
  392. (SUCCEEDED(hr)) ? psrkRegister->dwScmId : 0));
  393. return hr;
  394. }
  395. //+-------------------------------------------------------------------------
  396. //
  397. // Function: CScmRot::GetEntryFromScmReg
  398. //
  399. // Synopsis: Convert SCMREGKEY into a pointer to a ROT entry if possible.
  400. // MUST BE CALLED WITH CScmRot::_mxs HELD!
  401. //
  402. // Arguments: [psrk] - Pointer to a SCMREGKEY
  403. //
  404. // Returns: NULL - psrk not valid
  405. // ROT entry for the given input key
  406. //
  407. // Algorithm: Take the pointer portion of the key, along with the hash
  408. // portion of the key, and search for that entry in _sht.
  409. //
  410. // History: 20-Jan-95 Ricksa Created
  411. // 05-Mar-02 JohnDoty Modified to use _sht in validation.
  412. //
  413. //--------------------------------------------------------------------------
  414. CScmRotEntry *CScmRot::GetEntryFromScmReg(SCMREGKEY *psrk)
  415. {
  416. CairoleDebugOut((DEB_ROT, "%p _IN GetEntryFromScmReg ( %p )\n",
  417. this, psrk));
  418. CScmRotEntry *psreRet = NULL;
  419. CScmRotEntry *psre = (CScmRotEntry *) _sht.Lookup(psrk->dwHash, (CScmRotEntry*)psrk->dwEntryLoc);
  420. if (psre != NULL)
  421. {
  422. if (psre->IsValid(psrk->dwScmId))
  423. {
  424. psreRet = psre;
  425. }
  426. }
  427. CairoleDebugOut((DEB_ROT, "%p OUT GetEntryFromScmReg ( %p )\n",
  428. this, psreRet));
  429. return psreRet;
  430. }
  431. //+-------------------------------------------------------------------------
  432. //
  433. // Member: CScmRot::Revoke
  434. //
  435. // Synopsis: Remove entry from the ROT
  436. //
  437. // Arguments: [psrkRegister] - registration to revoke
  438. // [fServer] - whether this is the object server
  439. // [ppifdObject] - output marshaled interface (optional)
  440. // [ppifdName] - output marshaled moniker (optional)
  441. //
  442. // Returns: NOERROR - successfully removed.
  443. // E_INVALIDARG
  444. //
  445. // Algorithm: Convert SCMREGKEY to anentry in the ROT. Remove the
  446. // entry from the hash table. If this is the object server
  447. // for the entry, then return the marshaled interfaces
  448. // so the object server can release them.
  449. //
  450. // History: 20-Jan-95 Ricksa Created
  451. // 07-Mar-02 JohnDoty Validate most revokes against the process
  452. //
  453. //--------------------------------------------------------------------------
  454. HRESULT CScmRot::Revoke(
  455. CProcess *pProcess,
  456. SCMREGKEY *psrkRegister,
  457. InterfaceData **ppifdObject,
  458. InterfaceData **ppifdName)
  459. {
  460. CairoleDebugOut((DEB_ROT | DEB_ROT_ADDREMOVE,
  461. "%p _IN CScmRot::Revoke: Process: %p psrkRegister: [ 0x%I64x, %08x, %08x ]\n",
  462. this, pProcess,
  463. psrkRegister->dwEntryLoc,
  464. psrkRegister->dwHash,
  465. psrkRegister->dwScmId));
  466. HRESULT hr = E_INVALIDARG;
  467. // Lock for the duration of the call
  468. CPortableLock lck(_mxs);
  469. // Verify registration key
  470. CScmRotEntry *psreToRemove = GetEntryFromScmReg(psrkRegister);
  471. if (psreToRemove != NULL)
  472. {
  473. BOOL fValid;
  474. if (pProcess != NULL)
  475. {
  476. // Make sure that this entry belongs to the specified process.
  477. // If it does not, then ignore the revoke request.
  478. fValid = FALSE;
  479. if (pProcess->GetFirstROTEntry() != NULL)
  480. {
  481. ASSERT( !gpServerLock->HeldExclusive() );
  482. gpServerLock->LockExclusive();
  483. CScmRotEntry *pChase = NULL;
  484. CScmRotEntry *pEntry = (CScmRotEntry *)pProcess->GetFirstROTEntry();
  485. while (pEntry)
  486. {
  487. if (pEntry == psreToRemove)
  488. {
  489. CScmRotEntry *pNext = psreToRemove->GetProcessNext();
  490. // Great! This is valid-- remove it from the list.
  491. fValid = TRUE;
  492. CairoleDebugOut((DEB_ROT | DEB_ROT_ADDREMOVE,
  493. "%p ___ CScmRot::Revoke: Remove from process: Chase %p Next %p\n",
  494. this, pChase, pNext));
  495. if (pChase != NULL)
  496. pChase->SetProcessNext(pNext);
  497. else
  498. pProcess->SetFirstROTEntry(pNext);
  499. // Remove the reference that the list took on us.
  500. psreToRemove->Release();
  501. break;
  502. }
  503. pChase = pEntry;
  504. pEntry = pEntry->GetProcessNext();
  505. }
  506. gpServerLock->UnlockExclusive();
  507. }
  508. }
  509. else
  510. {
  511. // No process specified, just do the revoke.
  512. fValid = TRUE;
  513. }
  514. if (fValid)
  515. {
  516. // Get the hash value
  517. DWORD dwHash = psrkRegister->dwHash;
  518. // Remove object from the list
  519. _sht.RemoveEntry(dwHash, psreToRemove);
  520. // Is this a server doing a revoke?
  521. if (ppifdObject && ppifdName)
  522. {
  523. // Error handling here - suppose these allocations fail, what
  524. // can we do? The bottom line is nothing. This will cause a
  525. // memory leak in the server because they can't release the
  526. // marshaled data. However, this is assumed to be a rare
  527. // occurance and will really only cause the moniker to live
  528. // longer than it ought to which should not be too serious.
  529. *ppifdObject = AllocateAndCopy(psreToRemove->GetObject());
  530. *ppifdName = AllocateAndCopy(psreToRemove->GetMoniker());
  531. }
  532. // Release the table reference on the entry.
  533. // (A reference may still exist in the CProcess list, if we're racing
  534. // a revoke with a rundown. This should never really happen, because
  535. // we should not be running the process down since it's being used as
  536. // a context handle in the IrotRevoke RPC, but still... better safe
  537. // than busy writing QFE fixes.)
  538. psreToRemove->Release();
  539. // See if bucket is empty
  540. if (_sht.IsBucketEmpty(dwHash))
  541. {
  542. // Update the hint table.
  543. _rht.ClearIndicator(dwHash);
  544. }
  545. hr = S_OK;
  546. }
  547. else
  548. {
  549. CairoleDebugOut((DEB_ERROR, "%p ERR CScmRot::Revoke: Attempt to revoke invalid entry 0x%p\n",
  550. this, psreToRemove));
  551. }
  552. }
  553. CairoleDebugOut((DEB_ROT | DEB_ROT_ADDREMOVE,
  554. "%p OUT CScmRot::Revoke: ( %lx ) [ %p, %p ] \n",
  555. this, hr,
  556. (ppifdObject != NULL) ? *ppifdObject : NULL,
  557. (ppifdName != NULL) ? *ppifdName : NULL));
  558. return hr;
  559. }
  560. //+-------------------------------------------------------------------------
  561. //
  562. // Member: CScmRot::IsRunning
  563. //
  564. // Synopsis: Determine if there is a registered entry for an item
  565. //
  566. // Arguments: [pmnkeqbuf] - Moniker equality buffer to search for
  567. //
  568. // Returns: NOERROR - moniker is registered as running
  569. // S_FALSE - moniker is not running.
  570. //
  571. // Algorithm: Get the entry for the moniker equality buffer if there is
  572. // one. If there is one, then return NOERROR otherwise return
  573. // S_FALSE.
  574. //
  575. // History: 20-Jan-95 Ricksa Created
  576. //
  577. //--------------------------------------------------------------------------
  578. HRESULT CScmRot::IsRunning(
  579. CToken *pToken,
  580. WCHAR *pwszWinstaDesktop,
  581. MNKEQBUF *pmnkeqbuf)
  582. {
  583. CairoleDebugOut((DEB_ROT, "%p _IN CScmRot::IsRunning "
  584. "( %p )\n", this, pmnkeqbuf));
  585. // Lock for the duration of the call
  586. CPortableLock lck(_mxs);
  587. CScmRotEntry *psreRunning = GetRotEntry( pToken, pwszWinstaDesktop, pmnkeqbuf );
  588. HRESULT hr = (psreRunning != NULL) ? S_OK : S_FALSE;
  589. CairoleDebugOut((DEB_ROT, "%p OUT CScmRot::IsRunning "
  590. " ( %lx ) \n", this, hr));
  591. return hr;
  592. }
  593. //+-------------------------------------------------------------------------
  594. //
  595. // Member: CScmRot::GetObject
  596. //
  597. // Synopsis: Get running object for input
  598. //
  599. // Arguments: [dwProcessID] - process id of object (optional)
  600. // [pmnkeqbuf] - moniker equality buffer
  601. // [psrkRegister] - output registration id.
  602. // [ppifdObject] - marshaled interface for registration
  603. //
  604. // Returns: NOERROR - got object
  605. // MK_E_UNAVAILABLE - registration could not be found
  606. //
  607. // Algorithm: If not process ID is input, then search for the first
  608. // matching entry that we can find. Otherwise, search the
  609. // hash for the entry with both the same key and the same
  610. // process id.
  611. //
  612. // History: 20-Jan-95 Ricksa Created
  613. //
  614. //--------------------------------------------------------------------------
  615. HRESULT CScmRot::GetObject(
  616. CToken *pToken,
  617. WCHAR *pwszWinstaDesktop,
  618. DWORD dwProcessID,
  619. MNKEQBUF *pmnkeqbuf,
  620. SCMREGKEY *psrkRegister,
  621. InterfaceData **ppifdObject)
  622. {
  623. CairoleDebugOut((DEB_ROT, "%p _IN CScmRot::GetObject "
  624. "( %lx , %p , %p , %p )\n", this, dwProcessID, pmnkeqbuf, psrkRegister,
  625. ppifdObject));
  626. HRESULT hr = MK_E_UNAVAILABLE;
  627. // Lock for the duration of the call
  628. CPortableLock lck(_mxs);
  629. CScmRotEntry *psreRunning;
  630. if (dwProcessID == 0)
  631. {
  632. psreRunning = GetRotEntry( pToken, pwszWinstaDesktop, pmnkeqbuf );
  633. }
  634. else
  635. {
  636. // Special search based on process ID - get the head of the list
  637. // for the bucket
  638. psreRunning = (CScmRotEntry *) _sht.GetBucketList(
  639. ScmRotHash(&pmnkeqbuf->abEqData[0], pmnkeqbuf->cdwSize, 0));
  640. // Search list for a matching entry
  641. while (psreRunning != NULL)
  642. {
  643. if ((psreRunning->GetProcessID() == dwProcessID)
  644. && psreRunning->IsEqual(&pmnkeqbuf->abEqData[0],
  645. pmnkeqbuf->cdwSize))
  646. {
  647. // We found a match so we are done.
  648. break;
  649. }
  650. // Try the next item in the bucket.
  651. psreRunning = (CScmRotEntry *) psreRunning->GetNext();
  652. }
  653. }
  654. if (psreRunning != NULL)
  655. {
  656. hr = E_OUTOFMEMORY;
  657. *ppifdObject = AllocateAndCopy(psreRunning->GetObject());
  658. if (*ppifdObject != NULL)
  659. {
  660. hr = NOERROR;
  661. }
  662. // Build return registration key
  663. psreRunning->SetScmRegKey(psrkRegister);
  664. }
  665. CairoleDebugOut((DEB_ROT, "%p OUT CScmRot::GetObject "
  666. " ( %lx ) [ %p ] \n", this, hr, *ppifdObject));
  667. return hr;
  668. }
  669. //+-------------------------------------------------------------------------
  670. //
  671. // Member: CScmRot::NoteChangeTime
  672. //
  673. // Synopsis: Set the time of last change for a ROT entry
  674. //
  675. // Arguments: [psrkRegister] - ID of entry to change
  676. // [pfiletime] - new time for the entry.
  677. //
  678. // Returns: NOERROR - time set
  679. // E_INVALIDARG - ROT entry could not be found
  680. //
  681. // Algorithm: Convert SCMREGKEY into a pointer to a ROT entry and then
  682. // update the time of that entry.
  683. //
  684. // History: 20-Jan-95 Ricksa Created
  685. //
  686. //--------------------------------------------------------------------------
  687. HRESULT CScmRot::NoteChangeTime(
  688. SCMREGKEY *psrkRegister,
  689. FILETIME *pfiletime)
  690. {
  691. CairoleDebugOut((DEB_ROT, "%p _IN CScmRot::NoteChangeTime "
  692. "( %p , %p )\n", this, psrkRegister, pfiletime));
  693. HRESULT hr = E_INVALIDARG;
  694. // Lock for the duration of the call
  695. CPortableLock lck(_mxs);
  696. CScmRotEntry *psre = GetEntryFromScmReg(psrkRegister);
  697. if (psre != NULL)
  698. {
  699. psre->SetTime(pfiletime);
  700. hr = S_OK;
  701. }
  702. CairoleDebugOut((DEB_ROT, "%p OUT CScmRot::NoteChangeTime "
  703. " ( %lx ) \n", this, hr));
  704. return hr;
  705. }
  706. //+-------------------------------------------------------------------------
  707. //
  708. // Member: CScmRot::GetTimeOfLastChange
  709. //
  710. // Synopsis: Get time of last change for a moniker in the ROT
  711. //
  712. // Arguments: [pmnkeqbuf] - Moniker equality buffer
  713. // [pfiletime] - Where to put the time
  714. //
  715. // Returns: NOERROR - got the time
  716. // MK_E_UNAVAILABLE - couldn't find an entry/
  717. //
  718. // Algorithm: Search the hash for an entry with the same moniker. If
  719. // found, then copy out the time.
  720. //
  721. // History: 20-Jan-95 Ricksa Created
  722. //
  723. //--------------------------------------------------------------------------
  724. HRESULT CScmRot::GetTimeOfLastChange(
  725. CToken *pToken,
  726. WCHAR *pwszWinstaDesktop,
  727. MNKEQBUF *pmnkeqbuf,
  728. FILETIME *pfiletime)
  729. {
  730. CairoleDebugOut((DEB_ROT, "%p _IN CScmRot::GetTimeOfLastChange "
  731. "( %p , %p )\n", this, pmnkeqbuf, pfiletime));
  732. HRESULT hr = MK_E_UNAVAILABLE;
  733. // Lock for the duration of the call
  734. CPortableLock lck(_mxs);
  735. CScmRotEntry *psreRunning = GetRotEntry( pToken, pwszWinstaDesktop, pmnkeqbuf );
  736. if (psreRunning != NULL)
  737. {
  738. psreRunning->GetTime(pfiletime);
  739. hr = S_OK;
  740. }
  741. CairoleDebugOut((DEB_ROT, "%p OUT CScmRot::GetTimeOfLastChange "
  742. " ( %lx ) \n", this, hr));
  743. return hr;
  744. }
  745. //+-------------------------------------------------------------------------
  746. //
  747. // Member: CScmRot::EnumRunning
  748. //
  749. // Synopsis: Get a list of all the monikers that are currently running
  750. //
  751. // Arguments: [ppMkIFList] - Where to put list of monikers running
  752. //
  753. // Returns: NOERROR - got list
  754. // E_OUTOFMEMORY - couldn't allocate space for the list
  755. //
  756. // Algorithm: Loop through the ROT copying out the marshaled moniker buffers
  757. //
  758. // History: 20-Jan-95 Ricksa Created
  759. //
  760. //--------------------------------------------------------------------------
  761. HRESULT CScmRot::EnumRunning(
  762. CToken *pToken,
  763. WCHAR *pwszWinstaDesktop,
  764. MkInterfaceList **ppMkIFList)
  765. {
  766. CairoleDebugOut((DEB_ROT, "%p _IN CScmRot::EnumRunning "
  767. "( %p )\n", this, ppMkIFList));
  768. HRESULT hr = E_OUTOFMEMORY;
  769. // Lock for the duration of the call
  770. CPortableLock lck(_mxs);
  771. *ppMkIFList = NULL;
  772. MkInterfaceList *pMkIFList = NULL;
  773. // This is the upper limit on how much space we'll need.
  774. DWORD dwSize = sizeof(MkInterfaceList) +
  775. (_sht.GetCount() - 1) * sizeof(InterfaceData *);
  776. // Allocate buffer
  777. pMkIFList = (MkInterfaceList *) MIDL_user_allocate(dwSize);
  778. // We use this to keep track fof the number of monikers we are returning
  779. DWORD dwOffset = 0;
  780. if (pMkIFList != NULL)
  781. {
  782. // Iterate list getting the pointers
  783. CScmHashIter shi(&_sht);
  784. CScmRotEntry *psre;
  785. while ((psre = (CScmRotEntry *) shi.GetNext()) != NULL)
  786. {
  787. InterfaceData *pifdForOutput;
  788. if ( psre->WinstaDesktop() &&
  789. (lstrcmpW( pwszWinstaDesktop, psre->WinstaDesktop() ) != 0) )
  790. continue;
  791. if ( S_OK != pToken->MatchToken2(psre->Token(), FALSE) )
  792. continue;
  793. if ( gbSAFERROTChecksEnabled )
  794. {
  795. HRESULT hr = pToken->CompareSaferLevels(psre->Token());
  796. // S_FALSE: pToken is of lesser authorization, i.e., this
  797. // is untrusted code calling into trusted code.
  798. if (hr == S_FALSE)
  799. {
  800. //DbgPrint("RPCSS: SCMROT: SAFER level did not match.\n");
  801. continue;
  802. }
  803. }
  804. pifdForOutput = AllocateAndCopy(psre->GetMoniker());
  805. if (pifdForOutput == NULL)
  806. {
  807. goto Exit;
  808. }
  809. // Put copy in the array
  810. pMkIFList->apIFDList[dwOffset] = pifdForOutput;
  811. // We bump the count because it makes clean up easier
  812. dwOffset++;
  813. }
  814. // Teller caller and cleanup that everything went ok.
  815. hr = S_OK;
  816. // Set the output buffer to the buffer we have allocated.
  817. *ppMkIFList = pMkIFList;
  818. // Set the size of the object to return
  819. pMkIFList->dwSize = dwOffset;
  820. }
  821. Exit:
  822. if (FAILED(hr))
  823. {
  824. // We failed so clean up
  825. if (pMkIFList != NULL)
  826. {
  827. // Clean up the moniker interfaces that were allocated
  828. for (DWORD i = 0; i < dwOffset; i++)
  829. {
  830. MIDL_user_free(pMkIFList->apIFDList[i]);
  831. }
  832. // Clean up the table structure itself
  833. MIDL_user_free(pMkIFList);
  834. }
  835. }
  836. CairoleDebugOut((DEB_ROT, "%p OUT CScmRot::EnumRunning "
  837. " ( %lx ) [ %p ]\n", this, hr, *ppMkIFList));
  838. return hr;
  839. }
  840. //+-------------------------------------------------------------------------
  841. //
  842. // Member: CScmRot::GetRotEntry
  843. //
  844. // Synopsis: Search ROT for entry that matches the equality buffer input.
  845. //
  846. // Arguments: [pmnkeqbuf] - Moniker equality buffer to search for.
  847. //
  848. // Returns: NULL - no entry could be found
  849. // Pointer to ROT entry with matching key
  850. //
  851. // Algorithm: Calculate the hash value for the input buffer. The search
  852. // the hash table for the matching value.
  853. //
  854. // History: 20-Jan-95 Ricksa Created
  855. //
  856. //--------------------------------------------------------------------------
  857. CScmRotEntry *CScmRot::GetRotEntry(
  858. CToken *pToken,
  859. WCHAR *pwszWinstaDesktop,
  860. MNKEQBUF *pmnkeqbuf)
  861. {
  862. CairoleDebugOut((DEB_ROT, "%p _IN CScmRot::GetRotEntry "
  863. "( %p )\n", this, pmnkeqbuf));
  864. DWORD dwHash;
  865. CScmRotEntry * psre;
  866. dwHash = ScmRotHash(&pmnkeqbuf->abEqData[0], pmnkeqbuf->cdwSize, 0);
  867. psre = (CScmRotEntry *) _sht.GetBucketList( dwHash );
  868. for ( ; psre != NULL; psre = (CScmRotEntry *) psre->GetNext() )
  869. {
  870. if ( psre->IsEqual(&pmnkeqbuf->abEqData[0], pmnkeqbuf->cdwSize) )
  871. {
  872. //
  873. // Note that this routine is actually called during a Register
  874. // to see if there is a duplicate moniker and also during a
  875. // client Lookup. This makes things a little complicated.
  876. //
  877. // The winsta\desktop param can only be null in two instances.
  878. // + While doing a Register from a service or RunAs server. The
  879. // pToken will also be null.
  880. // + While doing a ROT lookup during a secure remote activation.
  881. // The pToken will be non-null. We only check that the SIDs
  882. // match in this case.
  883. //
  884. // During an usecure activation the pToken will be NULL. The
  885. // winsta/desktop will actually be "" in this case (see
  886. // Activation) to allow us to distinguish just this case.
  887. //
  888. // The ROT entry's winsta\desktop can be null if a service or RunAs
  889. // server registered a globally available object.
  890. //
  891. // Existing registration is globally available.
  892. if ( ! psre->WinstaDesktop() )
  893. break;
  894. //
  895. // NULL token and winsta/desktop means a server is doing a register
  896. // for a globally available object, return the match.
  897. // NULL token but non-null ("") winsta/desktop is a lookup from a
  898. // remote unsecure client, no match.
  899. //
  900. if ( ! pToken )
  901. {
  902. if ( ! pwszWinstaDesktop )
  903. break;
  904. else
  905. continue;
  906. }
  907. ASSERT( psre->Token() );
  908. if ( pwszWinstaDesktop &&
  909. (lstrcmpW( pwszWinstaDesktop, psre->WinstaDesktop() ) != 0) )
  910. continue;
  911. // Check to make sure the token matches
  912. if(S_OK != pToken->MatchToken2(psre->Token(), FALSE))
  913. continue;
  914. // Check to make sure that the safer token matches
  915. if ( gbSAFERROTChecksEnabled )
  916. {
  917. HRESULT hr = pToken->CompareSaferLevels(psre->Token());
  918. // S_FALSE: pToken is of lesser authorization, i.e., this
  919. // is untrusted code calling into trusted code.
  920. if (hr == S_FALSE)
  921. {
  922. //DbgPrint("RPCSS: SCMROT: SAFER level did not match.\n");
  923. continue;
  924. }
  925. }
  926. break;
  927. }
  928. }
  929. CairoleDebugOut((DEB_ROT, "%p OUT CScmRot::GetRotEntry "
  930. " ( %p )\n", this, psre));
  931. return psre;
  932. }
  933. //+-------------------------------------------------------------------------
  934. //
  935. // Function: SCMCleanupROTEntries
  936. //
  937. // Synopsis: Revoke the ROT entries in the list.
  938. //
  939. // Arguments: pvFirstEntry: First entry in the list.
  940. //
  941. // History: 07-Mar-2002 JohnDoty Created
  942. //
  943. //--------------------------------------------------------------------------
  944. void SCMCleanupROTEntries(
  945. void *pvFirstEntry)
  946. {
  947. CairoleDebugOut((DEB_ROT | DEB_ROT_ADDREMOVE,
  948. "SCMCleanupROTEntries: First entry @ 0x%p\n", pvFirstEntry));
  949. CScmRotEntry *pEntry = (CScmRotEntry *)pvFirstEntry;
  950. while (pEntry)
  951. {
  952. CairoleDebugOut((DEB_ROT | DEB_ROT_ADDREMOVE,
  953. "SCMCleanupROTEntries: Removing entry 0x%p...\n", pEntry));
  954. CScmRotEntry *pEntryNext = pEntry->GetProcessNext();
  955. // Revoke this entry from the ROT. Pass in NULL for the
  956. // CServerOxid, since these entries are no longer associated
  957. // with the OXID.
  958. //
  959. SCMREGKEY srkReg;
  960. pEntry->SetScmRegKey(&srkReg);
  961. gpscmrot->Revoke(NULL, &srkReg, NULL, NULL);
  962. // Remove the reference this list held on me.
  963. pEntry->Release();
  964. pEntry = pEntryNext;
  965. }
  966. CairoleDebugOut((DEB_ROT | DEB_ROT_ADDREMOVE,
  967. "SCMCleanupROTEntries: Done\n", pvFirstEntry));
  968. }