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.

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