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

1343 lines
44 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: sidname.cpp
  3. Description: Implements the SID-to-NAME resolver. It is anticipated that
  4. resolving a user's SID to it's corresponding name can be a lengthy
  5. process. We don't want the quota controller's client to experience
  6. slow user enumerations just because it takes a long time to resolve
  7. a name. Therefore, this object was created to perform the
  8. SID-to-name resolutions on a background thread and notify the
  9. client whenever a name has been resolved. That way, the client
  10. can display a list of users then fill in the names as names
  11. are resolved.
  12. Revision History:
  13. Date Description Programmer
  14. -------- --------------------------------------------------- ----------
  15. 06/12/96 Initial creation. BrianAu
  16. */
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include "pch.h" // PCH
  19. #pragma hdrstop
  20. #include "control.h"
  21. #include "guidsp.h" // Private GUIDs.
  22. #include "registry.h"
  23. #include "sidname.h"
  24. #include "sidcache.h"
  25. //
  26. // Verify that build is UNICODE.
  27. //
  28. #if !defined(UNICODE)
  29. # error This module must be compiled UNICODE.
  30. #endif
  31. //
  32. // SID/Name resolver messages (SNRM_XXXXXXXX).
  33. //
  34. #define SNRM_CLEAR_INPUT_QUEUE (WM_USER + 1)
  35. #define SNRM_EXIT_THREAD (WM_USER + 2)
  36. ///////////////////////////////////////////////////////////////////////////////
  37. /* Function: SidNameResolver::SidNameResolver
  38. Description: SidNameResolver constructor.
  39. Arguments:
  40. rQuotaController - Reference to quota controller that this resolver is
  41. working for.
  42. Returns: Nothing.
  43. Revision History:
  44. Date Description Programmer
  45. -------- --------------------------------------------------- ----------
  46. 06/12/96 Initial creation. BrianAu
  47. */
  48. ///////////////////////////////////////////////////////////////////////////////
  49. SidNameResolver::SidNameResolver(
  50. DiskQuotaControl& rQuotaController)
  51. : m_cRef(0),
  52. m_rQuotaController(rQuotaController),
  53. m_hsemQueueNotEmpty(NULL),
  54. m_hMutex(NULL),
  55. m_dwResolverThreadId(0),
  56. m_hResolverThread(NULL),
  57. m_heventResolverThreadReady(NULL)
  58. {
  59. DBGTRACE((DM_RESOLVER, DL_MID, TEXT("SidNameResolver::SidNameResolver")));
  60. }
  61. ///////////////////////////////////////////////////////////////////////////////
  62. /* Function: SidNameResolver::~SidNameResolver
  63. Description: SidNameResolver destructor.
  64. Arguments: None.
  65. Returns: Nothing.
  66. Revision History:
  67. Date Description Programmer
  68. -------- --------------------------------------------------- ----------
  69. 06/12/96 Initial creation. BrianAu
  70. */
  71. ///////////////////////////////////////////////////////////////////////////////
  72. SidNameResolver::~SidNameResolver(void)
  73. {
  74. DBGTRACE((DM_RESOLVER, DL_MID, TEXT("SidNameResolver::~SidNameResolver")));
  75. if (NULL != m_hsemQueueNotEmpty)
  76. {
  77. CloseHandle(m_hsemQueueNotEmpty);
  78. }
  79. if (NULL != m_hMutex)
  80. {
  81. CloseHandle(m_hMutex);
  82. }
  83. if (NULL != m_hResolverThread)
  84. {
  85. CloseHandle(m_hResolverThread);
  86. }
  87. if (NULL != m_heventResolverThreadReady)
  88. {
  89. CloseHandle(m_heventResolverThreadReady);
  90. }
  91. }
  92. ///////////////////////////////////////////////////////////////////////////////
  93. /* Function: SidNameResolver::QueryInterface
  94. Description: Returns an interface pointer to the object's IUnknown or
  95. ISidNameResolver interface.
  96. Only IID_IUnknown, IID_ISidNameResolver are recognized.
  97. The object referenced by the returned interface pointer is uninitialized.
  98. The recipient of the pointer must call Initialize() before the object
  99. is usable.
  100. Arguments:
  101. riid - Reference to requested interface ID.
  102. ppvOut - Address of interface pointer variable to accept interface ptr.
  103. Returns:
  104. NO_ERROR - Success.
  105. E_NOINTERFACE - Requested interface not supported.
  106. E_INVALIDARG - ppvOut argument was NULL.
  107. Revision History:
  108. Date Description Programmer
  109. -------- --------------------------------------------------- ----------
  110. 06/07/96 Initial creation. BrianAu
  111. */
  112. ///////////////////////////////////////////////////////////////////////////////
  113. STDMETHODIMP
  114. SidNameResolver::QueryInterface(
  115. REFIID riid,
  116. LPVOID *ppvOut
  117. )
  118. {
  119. DBGTRACE((DM_RESOLVER, DL_MID, TEXT("SidNameResolver::QueryInterface")));
  120. DBGPRINTIID(DM_RESOLVER, DL_MID, riid);
  121. HRESULT hResult = E_NOINTERFACE;
  122. if (NULL == ppvOut)
  123. return E_INVALIDARG;
  124. *ppvOut = NULL;
  125. if (IID_IUnknown == riid || IID_ISidNameResolver == riid)
  126. {
  127. *ppvOut = this;
  128. ((LPUNKNOWN)*ppvOut)->AddRef();
  129. hResult = NOERROR;
  130. }
  131. return hResult;
  132. }
  133. ///////////////////////////////////////////////////////////////////////////////
  134. /* Function: SidNameResolver::AddRef
  135. Description: Increments object reference count.
  136. Arguments: None.
  137. Returns: New reference count value.
  138. Revision History:
  139. Date Description Programmer
  140. -------- --------------------------------------------------- ----------
  141. 05/22/96 Initial creation. BrianAu
  142. */
  143. ///////////////////////////////////////////////////////////////////////////////
  144. STDMETHODIMP_(ULONG)
  145. SidNameResolver::AddRef(
  146. VOID
  147. )
  148. {
  149. DBGTRACE((DM_RESOLVER, DL_LOW, TEXT("SidNameResolver::AddRef")));
  150. DBGPRINT((DM_RESOLVER, DL_LOW, TEXT("\t0x%08X %d -> %d"),
  151. this, m_cRef, m_cRef + 1));
  152. ULONG ulReturn = m_cRef + 1;
  153. InterlockedIncrement(&m_cRef);
  154. return ulReturn;
  155. }
  156. ///////////////////////////////////////////////////////////////////////////////
  157. /* Function: SidNameResolver::Release
  158. Description: Decrements object reference count. If count drops to 0,
  159. object is deleted.
  160. Arguments: None.
  161. Returns: New reference count value.
  162. Revision History:
  163. Date Description Programmer
  164. -------- --------------------------------------------------- ----------
  165. 05/22/96 Initial creation. BrianAu
  166. */
  167. ///////////////////////////////////////////////////////////////////////////////
  168. STDMETHODIMP_(ULONG)
  169. SidNameResolver::Release(
  170. VOID
  171. )
  172. {
  173. DBGTRACE((DM_RESOLVER, DL_LOW, TEXT("SidNameResolver::Release")));
  174. DBGPRINT((DM_RESOLVER, DL_LOW, TEXT("\t0x%08X %d -> %d"),
  175. this, m_cRef, m_cRef - 1));
  176. ULONG ulReturn = m_cRef - 1;
  177. if (InterlockedDecrement(&m_cRef) == 0)
  178. {
  179. delete this;
  180. ulReturn = 0;
  181. }
  182. return ulReturn;
  183. }
  184. ///////////////////////////////////////////////////////////////////////////////
  185. /* Function: SidNameResolver::Initialize
  186. Description: Initializes a SidNameResolver object.
  187. This function performs lot's of initialization steps so I chose to
  188. use the "jump to label on failure" approach. It avoids a lot of
  189. deeply nested "ifs".
  190. Arguments: None.
  191. Returns:
  192. NO_ERROR - Success.
  193. E_FAIL - Initialization failed.
  194. Revision History:
  195. Date Description Programmer
  196. -------- --------------------------------------------------- ----------
  197. 06/11/96 Initial creation. BrianAu
  198. 08/14/96 Moved SID/Name cache initialization to BrianAu
  199. FindCachedUserName() method. Only initialize cache
  200. when it is truly needed.
  201. */
  202. ///////////////////////////////////////////////////////////////////////////////
  203. STDMETHODIMP
  204. SidNameResolver::Initialize(
  205. VOID
  206. )
  207. {
  208. DBGTRACE((DM_RESOLVER, DL_HIGH, TEXT("SidNameResolver::Initialize")));
  209. HRESULT hResult = NO_ERROR;
  210. DWORD dwThreadId = 0;
  211. //
  212. // Configure the user queue so it grows in chunks of 100.
  213. //
  214. m_UserQueue.SetSize(100);
  215. m_UserQueue.SetGrow(100);
  216. //
  217. // IMPORTANT: There is code in the QuotaControl object that
  218. // counts on the thread being created LAST in this function.
  219. // See DiskQuotaControl::CreateEnumUsers.
  220. // Thread creation must be the last thing performed in this
  221. // function. The caller assumes that if this function returns
  222. // E_FAIL, no thread was created.
  223. //
  224. m_hMutex = CreateMutex(NULL, FALSE, NULL);
  225. if (NULL == m_hMutex)
  226. goto InitFailed;
  227. m_hsemQueueNotEmpty = CreateSemaphore(NULL, // No security.
  228. 0, // Initially empty queue.
  229. 0x7FFFFFFF, // Max count (a lot).
  230. NULL); // No name.
  231. if (NULL == m_hsemQueueNotEmpty)
  232. goto InitFailed;
  233. m_heventResolverThreadReady = CreateEvent(NULL, // No security.
  234. TRUE, // Manual reset.
  235. FALSE, // Initially non-signaled.
  236. NULL); // No name.
  237. if (NULL == m_heventResolverThreadReady)
  238. goto InitFailed;
  239. hResult = CreateResolverThread(&m_hResolverThread, &m_dwResolverThreadId);
  240. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("Resolver thread. hThread = 0x%08X, idThread = %d"),
  241. m_hResolverThread, m_dwResolverThreadId));
  242. if (FAILED(hResult))
  243. goto InitFailed;
  244. InitFailed:
  245. //
  246. // Failure only returns E_FAIL.
  247. //
  248. if (FAILED(hResult))
  249. hResult = E_FAIL;
  250. return hResult;
  251. }
  252. ///////////////////////////////////////////////////////////////////////////////
  253. /* Function: SidNameResolver::Shutdown
  254. Description: Commands the resolver to terminate its activities.
  255. When the resolver's client is through with the resolver's services,
  256. it should call Shutdown() followed by IUnknown::Release(). The function
  257. sends a WM_QUIT message to the resolver thread.
  258. Arguments: None.
  259. Returns:
  260. NO_ERROR - Success
  261. E_FAIL - Failed to send WM_QUIT message.
  262. Revision History:
  263. Date Description Programmer
  264. -------- --------------------------------------------------- ----------
  265. 06/29/96 Initial creation. BrianAu
  266. */
  267. ///////////////////////////////////////////////////////////////////////////////
  268. STDMETHODIMP
  269. SidNameResolver::Shutdown(
  270. BOOL bWait
  271. )
  272. {
  273. DBGTRACE((DM_RESOLVER, DL_HIGH, TEXT("SidNameResolver::Shutdown")));
  274. DBGPRINT((DM_RESOLVER, DL_HIGH, TEXT("\tThread ID = %d"), m_dwResolverThreadId));
  275. BOOL bResult = FALSE;
  276. if (0 != m_dwResolverThreadId)
  277. {
  278. bResult = PostThreadMessage(m_dwResolverThreadId, WM_QUIT, 0, 0);
  279. if (bResult && bWait && NULL != m_hResolverThread)
  280. {
  281. //
  282. // Wait for thread to terminate normally.
  283. //
  284. DBGPRINT((DM_RESOLVER, DL_HIGH, TEXT("Resolver waiting for thread to exit...")));
  285. WaitForSingleObject(m_hResolverThread, INFINITE);
  286. }
  287. }
  288. return bResult ? NO_ERROR : E_FAIL;
  289. }
  290. ///////////////////////////////////////////////////////////////////////////////
  291. /* Function: SidNameResolver::GetUserSid
  292. Description: Private method that allocates a SID buffer and retrieves
  293. the user's SID into that buffer. The caller must free the returned
  294. buffer when done with it.
  295. Arguments:
  296. pUser - Pointer to user's IDiskQuotaUser interface.
  297. ppSid - Address of a PSID variable to receive the address of the
  298. allocated SID buffer.
  299. Returns:
  300. NO_ERROR - Success.
  301. Exceptions: OutOfMemory.
  302. Revision History:
  303. Date Description Programmer
  304. -------- --------------------------------------------------- ----------
  305. 07/08/96 Initial creation. BrianAu
  306. */
  307. ///////////////////////////////////////////////////////////////////////////////
  308. HRESULT
  309. SidNameResolver::GetUserSid(
  310. PDISKQUOTA_USER pUser,
  311. PSID *ppSid
  312. )
  313. {
  314. HRESULT hResult = NO_ERROR;
  315. DWORD cbSid = 0;
  316. DBGASSERT((NULL != pUser));
  317. hResult = pUser->GetSidLength(&cbSid);
  318. if (SUCCEEDED(hResult))
  319. {
  320. PSID pUserSid = NULL;
  321. pUserSid = (PSID) new BYTE[cbSid];
  322. hResult = pUser->GetSid((PBYTE)pUserSid, cbSid);
  323. if (SUCCEEDED(hResult))
  324. {
  325. DBGASSERT((IsValidSid(pUserSid)));
  326. DBGASSERT((NULL != ppSid));
  327. *ppSid = pUserSid; // Return address of buffer to caller.
  328. // Caller must free it when done.
  329. }
  330. else
  331. {
  332. DBGERROR((TEXT("RESOLVER - GetSid failed.")));
  333. delete[] pUserSid; // Failed to get SID. Free buffer.
  334. }
  335. }
  336. else
  337. {
  338. DBGERROR((TEXT("RESOLVER - GetUserSid failed.")));
  339. }
  340. return hResult;
  341. }
  342. ///////////////////////////////////////////////////////////////////////////////
  343. /* Function: SidNameResolver::AddUserToResolverQueue
  344. Description: Adds a user pointer to the resolver's input queue.
  345. Arguments:
  346. pUser - Address of IDiskQuotaUser ptr.
  347. Returns:
  348. NO_ERROR - Success.
  349. Exceptions: OutOfMemory.
  350. Revision History:
  351. Date Description Programmer
  352. -------- --------------------------------------------------- ----------
  353. 08/09/96 Initial creation. BrianAu
  354. 09/03/96 Added exception handling. BrianAu
  355. 12/10/96 Removed interface marshaling. Using free-threading BrianAu
  356. model.
  357. */
  358. ///////////////////////////////////////////////////////////////////////////////
  359. HRESULT
  360. SidNameResolver::AddUserToResolverQueue(
  361. PDISKQUOTA_USER pUser
  362. )
  363. {
  364. DBGTRACE((DM_RESOLVER, DL_MID, TEXT("SidNameResolver::AddUserToResolverQueue")));
  365. DBGASSERT((NULL != pUser));
  366. HRESULT hResult = NO_ERROR;
  367. //
  368. // Add user object pointer to resolver input queue.
  369. // This can throw OutOfMemory.
  370. //
  371. pUser->AddRef();
  372. try
  373. {
  374. m_UserQueue.Add(pUser);
  375. }
  376. catch(CAllocException& e)
  377. {
  378. pUser->Release();
  379. hResult = E_OUTOFMEMORY;
  380. }
  381. //
  382. // Increment queue's semaphore count.
  383. // Means there's something in queue to process.
  384. //
  385. ReleaseSemaphore(m_hsemQueueNotEmpty, 1, NULL);
  386. return hResult;
  387. }
  388. ///////////////////////////////////////////////////////////////////////////////
  389. /* Function: SidNameResolver::RemoveUserFromResolverQueue
  390. Description: Removes a user pointer from the resolver's input queue.
  391. Arguments:
  392. ppUser - Address of pointer variable to receive IDiskQuotaUser ptr.
  393. Returns:
  394. NO_ERROR - Success.
  395. E_UNEXPECTED - Resolver queue was empty.
  396. Revision History:
  397. Date Description Programmer
  398. -------- --------------------------------------------------- ----------
  399. 08/09/96 Initial creation. BrianAu
  400. 12/10/96 Removed interface marshaling. Using free-threading BrianAu
  401. model.
  402. */
  403. ///////////////////////////////////////////////////////////////////////////////
  404. HRESULT
  405. SidNameResolver::RemoveUserFromResolverQueue(
  406. PDISKQUOTA_USER *ppUser
  407. )
  408. {
  409. DBGTRACE((DM_RESOLVER, DL_MID, TEXT("SidNameResolver::RemoveUserFromResolverQueue")));
  410. DBGASSERT((NULL != ppUser));
  411. HRESULT hResult = E_UNEXPECTED;
  412. *ppUser = NULL;
  413. if (!m_UserQueue.IsEmpty() &&
  414. m_UserQueue.Remove(*ppUser))
  415. {
  416. hResult = NO_ERROR;
  417. }
  418. else
  419. {
  420. DBGERROR((TEXT("RESOLVER - Input queue unexpectedly empty.")));
  421. }
  422. return hResult;
  423. }
  424. ///////////////////////////////////////////////////////////////////////////////
  425. /* Function: SidNameResolver::PromoteUserToQueueHead
  426. Description: Promotes a user object to the head of the resolver queue
  427. if the user object is in the queue. This can be used to
  428. give specific user objects higher priority if desired.
  429. In particular, the initial requirement behind this feature
  430. is so that user objects highlighted in the details list view
  431. get higher name-resolution priority so that the user
  432. (app user) feels the UI is responsive to their inputs.
  433. Arguments:
  434. pUser - Address of IDiskQuotaUser interface for user object.
  435. Returns:
  436. NO_ERROR - Success.
  437. S_FALSE - User record not in queue.
  438. E_OUTOFMEMORY - Insufficient memory adding item.
  439. E_UNEXPECTED - Exception caught. User record not promoted.
  440. E_INVALIDARG - pUser argument was NULL.
  441. Revision History:
  442. Date Description Programmer
  443. -------- --------------------------------------------------- ----------
  444. 05/18/97 Initial creation. BrianAu
  445. */
  446. ///////////////////////////////////////////////////////////////////////////////
  447. STDMETHODIMP
  448. SidNameResolver::PromoteUserToQueueHead(
  449. PDISKQUOTA_USER pUser
  450. )
  451. {
  452. DBGTRACE((DM_RESOLVER, DL_MID, TEXT("SidNameResolver::PromoteUserToQueueHead")));
  453. HRESULT hResult = S_FALSE;
  454. if (NULL == pUser)
  455. return E_INVALIDARG;
  456. m_UserQueue.Lock();
  457. try
  458. {
  459. //
  460. // Find the user in the resolver's queue.
  461. //
  462. INT iUser = m_UserQueue.Find(pUser);
  463. if (-1 != iUser)
  464. {
  465. //
  466. // Note we don't mess with the ref count of the
  467. // user object. We're merely deleting a user and re
  468. // inserting it into the queue. The queue's original
  469. // AddRef() is retained.
  470. //
  471. m_UserQueue.Delete(iUser);
  472. m_UserQueue.Add(pUser);
  473. }
  474. }
  475. catch(CAllocException& e)
  476. {
  477. hResult = E_OUTOFMEMORY;
  478. }
  479. m_UserQueue.ReleaseLock();
  480. return hResult;
  481. }
  482. ///////////////////////////////////////////////////////////////////////////////
  483. /* Function: SidNameResolver::ResolveSidToName
  484. Description: Finds the name corresponding to a user's SID.
  485. Once the name is found, it is sent to the user object for storage.
  486. Arguments:
  487. pUser - Pointer to user objects's IDiskQuotaUser interface.
  488. Returns:
  489. NO_ERROR - Success.
  490. E_FAIL - Couldn't resolve SID to a name.
  491. ERROR_NONE_MAPPED (hr) - No SID-to-Name mapping available.
  492. No need to try again.
  493. Exceptions: OutOfMemory.
  494. Revision History:
  495. Date Description Programmer
  496. -------- --------------------------------------------------- ----------
  497. 06/11/96 Initial creation. BrianAu
  498. 08/09/96 Set hResult to E_FAIL when LookupAccountSid fails. BrianAu
  499. 09/05/96 Added user domain name string. BrianAu
  500. 05/18/97 Changed to report deleted SIDs. BrianAu
  501. */
  502. ///////////////////////////////////////////////////////////////////////////////
  503. HRESULT
  504. SidNameResolver::ResolveSidToName(
  505. PDISKQUOTA_USER pUser
  506. )
  507. {
  508. DBGTRACE((DM_RESOLVER, DL_HIGH, TEXT("SidNameResolver::ResolveSidToName")));
  509. HRESULT hResult = NO_ERROR;
  510. array_autoptr<BYTE> ptrUserSid;
  511. DBGASSERT((NULL != pUser));
  512. hResult = GetUserSid(pUser, (PSID *)(ptrUserSid.getaddr()));
  513. if (SUCCEEDED(hResult))
  514. {
  515. SID_NAME_USE SidNameUse = SidTypeUnknown;
  516. CString strContainer;
  517. CString strLogonName;
  518. CString strDisplayName;
  519. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER - Calling LookupAccountBySid.")));
  520. hResult = m_rQuotaController.m_NTDS.LookupAccountBySid(
  521. NULL,
  522. (PSID)(ptrUserSid.get()),
  523. &strContainer,
  524. &strLogonName,
  525. &strDisplayName,
  526. &SidNameUse);
  527. if (SUCCEEDED(hResult))
  528. {
  529. switch(SidNameUse)
  530. {
  531. case SidTypeDeletedAccount:
  532. static_cast<DiskQuotaUser *>(pUser)->SetAccountStatus(DISKQUOTA_USER_ACCOUNT_DELETED);
  533. break;
  534. case SidTypeInvalid:
  535. static_cast<DiskQuotaUser *>(pUser)->SetAccountStatus(DISKQUOTA_USER_ACCOUNT_INVALID);
  536. break;
  537. case SidTypeUnknown:
  538. static_cast<DiskQuotaUser *>(pUser)->SetAccountStatus(DISKQUOTA_USER_ACCOUNT_UNKNOWN);
  539. break;
  540. default:
  541. {
  542. //
  543. // Valid account.
  544. //
  545. SidNameCache *pSidCache;
  546. HRESULT hr = SidNameCache_Get(&pSidCache);
  547. if (SUCCEEDED(hr))
  548. {
  549. //
  550. // Add SID/Name pair to cache.
  551. // Indicate failure only with a debug msg. If cache
  552. // addition fails, we'll still work OK, just slower.
  553. // This can throw OutOfMemory.
  554. //
  555. hr = pSidCache->Add((PSID)(ptrUserSid.get()),
  556. strContainer,
  557. strLogonName,
  558. strDisplayName);
  559. if (FAILED(hr))
  560. {
  561. DBGERROR((TEXT("SIDNAME - Addition of %s\\%s failed."), strLogonName.Cstr()));
  562. }
  563. }
  564. //
  565. // Set the user object's account name strings.
  566. //
  567. hResult = static_cast<DiskQuotaUser *>(pUser)->SetName(
  568. strContainer,
  569. strLogonName,
  570. strDisplayName);
  571. if (SUCCEEDED(hResult))
  572. {
  573. static_cast<DiskQuotaUser *>(pUser)->SetAccountStatus(DISKQUOTA_USER_ACCOUNT_RESOLVED);
  574. }
  575. else
  576. {
  577. DBGERROR((TEXT("SIDNAME - SetName failed in ResolveSidToName. hResult = 0x%08X"),
  578. hResult));
  579. }
  580. break;
  581. }
  582. }
  583. }
  584. else
  585. {
  586. //
  587. // Failed asynch name resolution.
  588. //
  589. static_cast<DiskQuotaUser *>(pUser)->SetAccountStatus(DISKQUOTA_USER_ACCOUNT_UNAVAILABLE);
  590. if (ERROR_NONE_MAPPED == GetLastError())
  591. hResult = HRESULT_FROM_WIN32(ERROR_NONE_MAPPED);
  592. else
  593. hResult = E_FAIL;
  594. }
  595. }
  596. else
  597. {
  598. DBGERROR((TEXT("SIDNAME - GetUserSid failed in ResolveSidToName, hResult = 0x%08X"),
  599. hResult));
  600. }
  601. return hResult;
  602. }
  603. ///////////////////////////////////////////////////////////////////////////////
  604. /* Function: SidNameResolver::FindCachedUserName
  605. Description: Accepts a user object's IDiskQuotaUser interface pointer and
  606. looks for it's SID/Name pair in the SID/Name cache. If found, the
  607. name is set in the user object and the function returns NO_ERROR.
  608. Arguments:
  609. pUser - Pointer to user objects's IDiskQuotaUser interface.
  610. Returns:
  611. NO_ERROR - Success. User's SID found in cache.
  612. ERROR_FILE_NOT_FOUND (hr) - User's SID not in cache.
  613. Exceptions: OutOfMemory
  614. Revision History:
  615. Date Description Programmer
  616. -------- --------------------------------------------------- ----------
  617. 06/27/96 Initial creation. BrianAu
  618. 08/14/96 Moved initialization of SID/Name cache from BrianAu
  619. SidNameResolver::Initialize().
  620. 09/05/96 Added user domain name string. BrianAu
  621. 09/21/96 New cache design. BrianAu
  622. 03/18/98 Replaced "domain", "name" and "full name" with BrianAu
  623. "container", "logon name" and "display name" to
  624. better match the actual contents. This was in
  625. reponse to making the quota UI DS-aware. The
  626. "logon name" is now a unique key as it contains
  627. both account name and domain-like information.
  628. i.e. "REDMOND\brianau" or "[email protected]".
  629. */
  630. ///////////////////////////////////////////////////////////////////////////////
  631. HRESULT
  632. SidNameResolver::FindCachedUserName(
  633. PDISKQUOTA_USER pUser
  634. )
  635. {
  636. DBGTRACE((DM_RESOLVER, DL_MID, TEXT("SidNameResolver::FindCachedUserName")));
  637. HRESULT hResult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // Assume not found.
  638. PSID pUserSid = NULL;
  639. hResult = GetUserSid(pUser, &pUserSid);
  640. if (SUCCEEDED(hResult))
  641. {
  642. LPTSTR pszContainer = NULL;
  643. LPTSTR pszLogonName = NULL;
  644. LPTSTR pszDisplayName = NULL;
  645. try
  646. {
  647. //
  648. // Can throw OutOfMemory.
  649. //
  650. SidNameCache *pSidCache;
  651. hResult = SidNameCache_Get(&pSidCache);
  652. if (SUCCEEDED(hResult))
  653. {
  654. //
  655. // Check cache for SID/Name pair.
  656. // This can throw OutOfMemory.
  657. //
  658. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER - Query cache for user 0x%08X."), pUser));
  659. hResult = pSidCache->Lookup(pUserSid,
  660. &pszContainer,
  661. &pszLogonName,
  662. &pszDisplayName);
  663. if (SUCCEEDED(hResult))
  664. {
  665. //
  666. // Name was cached. Set it in the user object and return NO_ERROR.
  667. //
  668. hResult = static_cast<DiskQuotaUser *>(pUser)->SetName(
  669. pszContainer,
  670. pszLogonName,
  671. pszDisplayName);
  672. if (SUCCEEDED(hResult))
  673. {
  674. static_cast<DiskQuotaUser *>(pUser)->SetAccountStatus(DISKQUOTA_USER_ACCOUNT_RESOLVED);
  675. }
  676. }
  677. }
  678. else
  679. {
  680. //
  681. // Set the return value so the caller knows to resolve
  682. // the user name.
  683. //
  684. hResult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  685. DBGERROR((TEXT("RESOLVER - SID/Name cache not available.")));
  686. }
  687. }
  688. catch(CAllocException& e)
  689. {
  690. hResult = E_OUTOFMEMORY;
  691. }
  692. delete[] pszContainer;
  693. delete[] pszLogonName;
  694. delete[] pszDisplayName;
  695. delete[] pUserSid;
  696. }
  697. return hResult;
  698. }
  699. ///////////////////////////////////////////////////////////////////////////////
  700. /* Function: SidNameResolver::FindUserName
  701. Description: Accepts a user object's IDiskQuotaUser interface pointer and
  702. looks for it's SID/Name pair in the SID/Name cache. If the information
  703. is not cached, the function calls ResolveSidToName to synchronously
  704. determine the SID's account name. The function blocks until the name
  705. is retrieved.
  706. Arguments:
  707. pUser - Pointer to user objects's IDiskQuotaUser interface.
  708. Returns:
  709. NO_ERROR - Success.
  710. E_FAIL - Couldn't resolve SID to name.
  711. ERROR_NONE_MAPPED (hr) - No SID-to-Name mapping found.
  712. Exceptions: OutOfMemory.
  713. Revision History:
  714. Date Description Programmer
  715. -------- --------------------------------------------------- ----------
  716. 06/27/96 Initial creation. BrianAu
  717. */
  718. ///////////////////////////////////////////////////////////////////////////////
  719. STDMETHODIMP
  720. SidNameResolver::FindUserName(
  721. PDISKQUOTA_USER pUser
  722. )
  723. {
  724. DBGTRACE((DM_RESOLVER, DL_MID, TEXT("SidNameResolver::FindUserName")));
  725. HRESULT hResult = NO_ERROR;
  726. DBGASSERT((NULL != pUser));
  727. hResult = FindCachedUserName(pUser); // Can throw OutOfMemory.
  728. if (ERROR_FILE_NOT_FOUND == HRESULT_CODE(hResult))
  729. {
  730. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER - User 0x%08X not cached. Resolving..."),
  731. pUser));
  732. hResult = ResolveSidToName(pUser); // Can throw OutOfMemory.
  733. }
  734. else
  735. {
  736. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER - User 0x%08X found in cache."), pUser));
  737. }
  738. return hResult;
  739. }
  740. ///////////////////////////////////////////////////////////////////////////////
  741. /* Function: SidNameResolver::FindUserNameAsync
  742. Description: Accepts a user object's IDiskQuotaUser interface pointer and
  743. looks for it's SID/Name pair in the SID/Name cache. If the information
  744. is not cached, the user object is submitted to the resolver for
  745. background processing and asynchronous client notification when the
  746. operation is complete.
  747. Arguments:
  748. pUser - Pointer to user objects's IDiskQuotaUser interface.
  749. Returns:
  750. NO_ERROR - Success.
  751. E_FAIL - Resolver thread not active. Can't resolve Async.
  752. S_FALSE - User name not in cache. Submitted for background
  753. processing. Client will be notified when name is
  754. found and set in user object.
  755. Exceptions: OutOfMemory.
  756. Revision History:
  757. Date Description Programmer
  758. -------- --------------------------------------------------- ----------
  759. 06/11/96 Initial creation. BrianAu
  760. 06/25/96 Added SID/Name caching. BrianAu
  761. */
  762. ///////////////////////////////////////////////////////////////////////////////
  763. STDMETHODIMP
  764. SidNameResolver::FindUserNameAsync(
  765. PDISKQUOTA_USER pUser
  766. )
  767. {
  768. DBGTRACE((DM_RESOLVER, DL_MID, TEXT("SidNameResolver::FindUserNameAsync")));
  769. HRESULT hResult = NO_ERROR;
  770. DBGASSERT((NULL != pUser));
  771. hResult = FindCachedUserName(pUser);
  772. if (ERROR_FILE_NOT_FOUND == HRESULT_CODE(hResult))
  773. {
  774. if (0 != m_dwResolverThreadId)
  775. {
  776. DBGPRINT((DM_RESOLVER, DL_MID,
  777. TEXT("RESOLVER - User 0x%08X not cached. Submitting to Resolver."),
  778. pUser));
  779. //
  780. // Name was not cached. Add the user object to the resolver's input queue
  781. // so that the name can be located by the resolver's background thread.
  782. //
  783. hResult = AddUserToResolverQueue(pUser);
  784. }
  785. else
  786. {
  787. DBGERROR((TEXT("RESOLVER - Thread not active. Can't resolve user 0x%08X async."),
  788. pUser));
  789. hResult = E_FAIL;
  790. }
  791. }
  792. else
  793. {
  794. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER - User 0x%08X found in cache."),
  795. pUser));
  796. }
  797. return hResult;
  798. }
  799. ///////////////////////////////////////////////////////////////////////////////
  800. /* Function: SidNameResolver::ClearInputQueue.
  801. Description: Called by a SidNameResolver thread after the thread receives
  802. a WM_QUIT message. This function removes all user object pointers
  803. from the input queue before the thread exists.
  804. Arguments: None.
  805. Returns:
  806. NO_ERROR - Always returns NO_ERROR.
  807. Revision History:
  808. Date Description Programmer
  809. -------- --------------------------------------------------- ----------
  810. 06/18/96 Initial creation. BrianAu
  811. 12/10/96 Moved Semaphore reduction from method BrianAu
  812. HandleShutdownMessages then deleted that method.
  813. */
  814. ///////////////////////////////////////////////////////////////////////////////
  815. HRESULT
  816. SidNameResolver::ClearInputQueue(
  817. void
  818. )
  819. {
  820. DBGTRACE((DM_RESOLVER, DL_HIGH, TEXT("SidNameResolver::ClearInputQueue")));
  821. PDISKQUOTA_USER pUser = NULL;
  822. //
  823. // Decrement the queue-not-empty semaphore to 0 so that the thread
  824. // doesn't try to remove any more queue entries.
  825. // Set the resolver's thread ID to 0 so that FindNameAsync will not
  826. // submit any more users to the resolver.
  827. //
  828. m_dwResolverThreadId = 0;
  829. while(WAIT_OBJECT_0 == WaitForSingleObject(m_hsemQueueNotEmpty, 0))
  830. NULL;
  831. //
  832. // Remove all remaining items from input queue
  833. // Remove will return E_FAIL if list is empty.
  834. //
  835. m_UserQueue.Lock();
  836. while(m_UserQueue.Count() > 0)
  837. {
  838. HRESULT hResult = RemoveUserFromResolverQueue(&pUser);
  839. if (SUCCEEDED(hResult) && NULL != pUser)
  840. {
  841. pUser->Release(); // Release user object.
  842. }
  843. }
  844. m_UserQueue.ReleaseLock();
  845. return NO_ERROR;
  846. }
  847. ///////////////////////////////////////////////////////////////////////////////
  848. /* Function: SidNameResolver::ThreadOnQueueNotEmpty
  849. Description: Called by a SidNameResolver thread when the resolver's input
  850. queue is not empty. This function removes the next entry
  851. from the queue, resolves the user's SID to its name, sets the name
  852. in the user object and notifies the client of the name change.
  853. Arguments: None.
  854. Returns:
  855. NO_ERROR - Always returns NO_ERROR.
  856. Exceptions: OutOfMemory
  857. Revision History:
  858. Date Description Programmer
  859. -------- --------------------------------------------------- ----------
  860. 06/18/96 Initial creation. BrianAu
  861. */
  862. ///////////////////////////////////////////////////////////////////////////////
  863. HRESULT
  864. SidNameResolver::ThreadOnQueueNotEmpty(
  865. void
  866. )
  867. {
  868. DBGTRACE((DM_RESOLVER, DL_LOW, TEXT("SidNameResolver::ThreadOnQueueNotEmpty")));
  869. HRESULT hResult = NO_ERROR;
  870. PDISKQUOTA_USER pUser = NULL;
  871. LPSTREAM pstm = NULL;
  872. //
  873. // Remove item from queue
  874. // RemoveFirst() will return E_FAIL if list is empty.
  875. //
  876. try
  877. {
  878. hResult = RemoveUserFromResolverQueue(&pUser);
  879. if (SUCCEEDED(hResult) && NULL != pUser)
  880. {
  881. ResolveSidToName(pUser);
  882. //
  883. // If successful or not, notify client event sink.
  884. // Even if we couldn't resolve the name, the object's account
  885. // status has changed. The client will want to respond to this.
  886. //
  887. // Don't bother with return value. We don't care if it fails.
  888. // The client will but we don't.
  889. //
  890. m_rQuotaController.NotifyUserNameChanged(pUser);
  891. pUser->Release(); // Release pointer obtained from resolver queue.
  892. }
  893. else
  894. {
  895. DBGERROR((TEXT("RESOLVER - Error removing stream ptr from input queue.")));
  896. }
  897. }
  898. catch(CAllocException& e)
  899. {
  900. if (NULL != pUser)
  901. pUser->Release();
  902. hResult = E_OUTOFMEMORY;
  903. }
  904. return hResult;
  905. }
  906. ///////////////////////////////////////////////////////////////////////////////
  907. /* Function: SidNameResolver::ThreadProc
  908. Description: This thread procedure sits in a loop handling events and
  909. thread messages.
  910. Conditions that cause the thread to exit.
  911. 1. OleInitalize() fails.
  912. 2. Thread receives a WM_QUIT message.
  913. 3. Wait function failure or timeout.
  914. Arguments:
  915. pvParam - "this" pointer for the SidNameResolver object.
  916. Required since ThreadProc must be static to be a THREADPROC.
  917. Returns:
  918. Revision History:
  919. Date Description Programmer
  920. -------- --------------------------------------------------- ----------
  921. 06/11/96 Initial creation. BrianAu
  922. 03/22/00 Changed dwParam for ia64 compat. BrianAu
  923. */
  924. ///////////////////////////////////////////////////////////////////////////////
  925. DWORD
  926. SidNameResolver::ThreadProc(
  927. LPVOID pvParam
  928. )
  929. {
  930. DBGTRACE((DM_RESOLVER, DL_HIGH, TEXT("SidNameResolver::ThreadProc")));
  931. DBGPRINT((DM_RESOLVER, DL_HIGH, TEXT("\tThreadID = %d"), GetCurrentThreadId()));
  932. SidNameResolver *pThis = (SidNameResolver *)pvParam;
  933. BOOL bExitThread = FALSE;
  934. //
  935. // Make sure DLL stays loaded while this thread is active.
  936. //
  937. InterlockedIncrement(&g_cRefThisDll);
  938. //
  939. // Must call CoInitializeEx() for each thread.
  940. //
  941. if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
  942. {
  943. BOOL bReadyToReceiveMsgs = FALSE;
  944. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER: Thread %d entering msg loop."), GetCurrentThreadId()));
  945. while(!bExitThread)
  946. {
  947. MSG msg;
  948. try
  949. {
  950. //
  951. // Allow blocked thread to respond to sent messages.
  952. //
  953. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && !bExitThread)
  954. {
  955. if ( WM_QUIT != msg.message )
  956. {
  957. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER: Thread %d dispatching msg %d"),
  958. GetCurrentThreadId(), msg.message));
  959. TranslateMessage(&msg);
  960. DispatchMessage(&msg);
  961. }
  962. else
  963. {
  964. //
  965. // Rcvd WM_QUIT. Clear the resolver's input queue and
  966. // exit the msg loop.
  967. //
  968. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER: Thread %d received WM_QUIT"),
  969. GetCurrentThreadId()));
  970. pThis->ClearInputQueue();
  971. bExitThread = TRUE;
  972. }
  973. }
  974. if (!bExitThread)
  975. {
  976. DWORD dwWaitResult = 0;
  977. if (!bReadyToReceiveMsgs)
  978. {
  979. //
  980. // Tell the thread creation function that it can
  981. // now return. The thread is ready to accept messages.
  982. //
  983. SetEvent(pThis->m_heventResolverThreadReady);
  984. bReadyToReceiveMsgs = TRUE;
  985. }
  986. //
  987. // Sleep if the queue is empty.
  988. // Wake up on queue-not-empty or any thread messages.
  989. //
  990. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER - Thread %d waiting for messages..."),
  991. GetCurrentThreadId()));
  992. dwWaitResult = MsgWaitForMultipleObjects(
  993. 1,
  994. &(pThis->m_hsemQueueNotEmpty),
  995. FALSE,
  996. INFINITE,
  997. QS_ALLINPUT);
  998. switch(dwWaitResult)
  999. {
  1000. case WAIT_OBJECT_0:
  1001. //
  1002. // Have data in input queue. Process one user.
  1003. //
  1004. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER - Something added to input queue.")));
  1005. pThis->ThreadOnQueueNotEmpty();
  1006. break;
  1007. case WAIT_OBJECT_0 + 1:
  1008. //
  1009. // Received input message(s).
  1010. // Loop back around and handle them.
  1011. //
  1012. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER - Thread %d rcvd message(s)."),
  1013. GetCurrentThreadId()));
  1014. break;
  1015. case WAIT_FAILED:
  1016. case WAIT_TIMEOUT:
  1017. default:
  1018. //
  1019. // Something bad happened.
  1020. //
  1021. DBGPRINT((DM_RESOLVER, DL_MID, TEXT("RESOLVER - Thread %d wait failed."),
  1022. GetCurrentThreadId()));
  1023. DBGASSERT((FALSE));
  1024. bExitThread = TRUE;
  1025. break;
  1026. }
  1027. }
  1028. }
  1029. catch(CAllocException& e)
  1030. {
  1031. DBGERROR((TEXT("RESOLVER - Out of memory")));
  1032. bExitThread = TRUE;
  1033. }
  1034. }
  1035. CoUninitialize();
  1036. }
  1037. else
  1038. {
  1039. DBGERROR((TEXT("RESOLVER - OleInitialize failed for thread %d."),
  1040. GetCurrentThreadId()));
  1041. }
  1042. DBGPRINT((DM_RESOLVER, DL_HIGH, TEXT("RESOLVER - Exit thread %d"), GetCurrentThreadId()));
  1043. pThis->m_dwResolverThreadId = 0;
  1044. InterlockedDecrement(&g_cRefThisDll);
  1045. return 0;
  1046. }
  1047. ///////////////////////////////////////////////////////////////////////////////
  1048. /* Function: SidNameResolver::CreateResolverThread
  1049. Description: Creates a thread that will process user objects and resolve
  1050. their SIDs to account names.
  1051. Arguments:
  1052. phThread [optional] - Address of handle variable to receive handle of
  1053. new thread. Can be NULL.
  1054. pdwThreadId [optional] - Address of DWORD to receive thread ID.
  1055. Can be NULL.
  1056. Returns:
  1057. NO_ERROR - Started thread.
  1058. E_FAIL - Couldn't start thread.
  1059. Revision History:
  1060. Date Description Programmer
  1061. -------- --------------------------------------------------- ----------
  1062. 06/27/96 Initial creation. BrianAu
  1063. */
  1064. ///////////////////////////////////////////////////////////////////////////////
  1065. HRESULT
  1066. SidNameResolver::CreateResolverThread(
  1067. PHANDLE phThread,
  1068. LPDWORD pdwThreadId
  1069. )
  1070. {
  1071. DBGTRACE((DM_RESOLVER, DL_HIGH, TEXT("SidNameResolver::CreateResolverThread")));
  1072. HRESULT hResult = NO_ERROR;
  1073. DWORD dwThreadId = 0;
  1074. HANDLE hThread = NULL;
  1075. //
  1076. // Launch new thread.
  1077. //
  1078. hThread = CreateThread(NULL, // No security attributes.
  1079. 0, // Default stack size.
  1080. &ThreadProc,
  1081. this, // Static thread proc needs this.
  1082. 0, // Not suspended.
  1083. &dwThreadId);
  1084. if (NULL != hThread)
  1085. {
  1086. if (NULL != phThread)
  1087. *phThread = hThread; // Caller want's handle value.
  1088. else
  1089. CloseHandle(hThread); // Caller doesn't want it.
  1090. if (NULL != pdwThreadId)
  1091. *pdwThreadId = dwThreadId; // Caller want's thread ID.
  1092. //
  1093. // Wait here until the thread is ready to receive thread messages.
  1094. // This event is set in ThreadProc.
  1095. //
  1096. WaitForSingleObject(m_heventResolverThreadReady, INFINITE);
  1097. }
  1098. else
  1099. {
  1100. hResult = E_FAIL;
  1101. }
  1102. return hResult;
  1103. }