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.

1279 lines
35 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2000 - 2001.
  5. //
  6. // File: sidcache.cpp
  7. //
  8. // Contents:
  9. //
  10. // History:
  11. //----------------------------------------------------------------------------
  12. #include "headers.h"
  13. const struct
  14. {
  15. SID sid; // contains 1 subauthority
  16. DWORD dwSubAuth[1]; // we currently need at most 2 subauthorities
  17. } g_StaticSids[] =
  18. {
  19. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ADMINS} },
  20. };
  21. #define IsAliasSid(pSid) EqualPrefixSid(pSid, (PSID)&g_StaticSids[0])
  22. /******************************************************************************
  23. Class: SID_CACHE_ENTRY
  24. Purpose: Contains info for a single security principle
  25. ******************************************************************************/
  26. DEBUG_DECLARE_INSTANCE_COUNTER(SID_CACHE_ENTRY);
  27. SID_CACHE_ENTRY::
  28. SID_CACHE_ENTRY(PSID pSid)
  29. :m_SidType(SidTypeUnknown)
  30. {
  31. DEBUG_INCREMENT_INSTANCE_COUNTER(SID_CACHE_ENTRY);
  32. ASSERT(pSid);
  33. DWORD dwLen = GetLengthSid(pSid);
  34. m_pSid = new BYTE[dwLen];
  35. ASSERT(m_pSid);
  36. CopySid(dwLen,m_pSid,pSid);
  37. ConvertSidToStringSid(m_pSid,&m_strSid);
  38. m_strType.LoadString(IDS_TYPE_UNKNOWN);
  39. m_strNameToDisplay = m_strSid;
  40. m_SidType = SidTypeUnknown;
  41. }
  42. SID_CACHE_ENTRY::
  43. ~SID_CACHE_ENTRY()
  44. {
  45. DEBUG_DECREMENT_INSTANCE_COUNTER(SID_CACHE_ENTRY);
  46. delete[] m_pSid;
  47. }
  48. VOID
  49. SID_CACHE_ENTRY::
  50. AddNameAndType(IN SID_NAME_USE SidType,
  51. const CString& strAccountName,
  52. const CString& strLogonName)
  53. {
  54. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  55. //Empty the m_strNameToDisplay which was made using
  56. //ealier values of strAccountName and strLogonName
  57. m_strNameToDisplay.Empty();
  58. m_strType.Empty();
  59. m_SidType = SidType;
  60. m_strAccountName = strAccountName;
  61. m_strLogonName = strLogonName;
  62. //
  63. //Set the Display Name
  64. //
  65. if(m_SidType == SidTypeDeletedAccount ||
  66. m_SidType == SidTypeInvalid ||
  67. m_SidType == SidTypeUnknown)
  68. {
  69. UINT idFormat;
  70. if(m_SidType == SidTypeDeletedAccount)
  71. idFormat = IDS_SID_DELETED;
  72. if(m_SidType == SidTypeInvalid)
  73. idFormat = IDS_SID_INVALID;
  74. if(m_SidType == SidTypeUnknown)
  75. idFormat = IDS_SID_UNKNOWN;
  76. FormatString(m_strNameToDisplay,idFormat,LPCTSTR(m_strSid));
  77. }
  78. else if(!m_strAccountName.IsEmpty())
  79. {
  80. if(!m_strLogonName.IsEmpty())
  81. {
  82. //Both the names are present.
  83. FormatString(m_strNameToDisplay,
  84. IDS_NT_USER_FORMAT,
  85. (LPCTSTR)m_strAccountName,
  86. (LPCTSTR)m_strLogonName);
  87. }
  88. else
  89. {
  90. m_strNameToDisplay = m_strAccountName;
  91. }
  92. }
  93. else
  94. {
  95. //Just return the sid in string format
  96. m_SidType = SidTypeUnknown;
  97. m_strNameToDisplay = m_strSid;
  98. }
  99. //
  100. //Set Sid Type String
  101. //
  102. if(m_SidType == SidTypeDeletedAccount ||
  103. m_SidType == SidTypeInvalid ||
  104. m_SidType == SidTypeUnknown)
  105. {
  106. m_strType.LoadString(IDS_TYPE_UNKNOWN);
  107. }
  108. else if(m_SidType == SidTypeUser)
  109. {
  110. m_strType.LoadString(IDS_TYPE_WINDOWS_USER);
  111. }
  112. else if(m_SidType == SidTypeComputer)
  113. {
  114. m_strType.LoadString(IDS_TYPE_WINDOWS_COMPUTER);
  115. }
  116. else //Assume everything else is group
  117. {
  118. m_strType.LoadString(IDS_TYPE_WINDOWS_GROUP);
  119. }
  120. }
  121. /******************************************************************************
  122. Class: CMachineInfo
  123. Purpose: Contains all the info for machine.
  124. ******************************************************************************/
  125. DEBUG_DECLARE_INSTANCE_COUNTER(CMachineInfo);
  126. CMachineInfo::
  127. CMachineInfo():m_bIsStandAlone(TRUE),
  128. m_bIsDC(FALSE)
  129. {
  130. DEBUG_INCREMENT_INSTANCE_COUNTER(CMachineInfo);
  131. }
  132. CMachineInfo::
  133. ~CMachineInfo()
  134. {
  135. DEBUG_DECREMENT_INSTANCE_COUNTER(CMachineInfo);
  136. }
  137. //+----------------------------------------------------------------------------
  138. // Function:InitializeMacineConfiguration
  139. // Synopsis:Get the information about TargetComputer's conficguration
  140. //-----------------------------------------------------------------------------
  141. VOID
  142. CMachineInfo::
  143. InitializeMacineConfiguration(IN const CString& strTargetComputerName)
  144. {
  145. TRACE_METHOD_EX(DEB_SNAPIN,CMachineInfo,InitializeMacineConfiguration)
  146. //
  147. //Initialize the values to default
  148. //
  149. m_strTargetComputerName = strTargetComputerName;
  150. m_bIsStandAlone = TRUE;
  151. m_strDCName.Empty();
  152. m_bIsDC = FALSE;
  153. m_strTargetDomainFlat.Empty();
  154. m_strTargetDomainDNS.Empty();
  155. HRESULT hr = S_OK;
  156. ULONG ulResult;
  157. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  158. PDOMAIN_CONTROLLER_INFO pdci = NULL;
  159. do
  160. {
  161. PCWSTR pwzMachine = strTargetComputerName;
  162. ulResult = DsRoleGetPrimaryDomainInformation(pwzMachine,
  163. DsRolePrimaryDomainInfoBasic,
  164. (PBYTE *)&pDsRole);
  165. if (ulResult != NO_ERROR)
  166. {
  167. DBG_OUT_LRESULT(ulResult);
  168. break;
  169. }
  170. if(!pDsRole)
  171. {
  172. //We should never reach here, but sadly DsRoleGetPrimaryDomainInformation
  173. //sometimes succeeds but pDsRole is null.
  174. ASSERT(FALSE);
  175. break;
  176. }
  177. Dbg(DEB_SNAPIN, "DsRoleGetPrimaryDomainInformation returned:\n");
  178. Dbg(DEB_SNAPIN, "DomainNameFlat: %ws\n", CHECK_NULL(pDsRole->DomainNameFlat));
  179. Dbg(DEB_SNAPIN, "DomainNameDns: %ws\n", CHECK_NULL(pDsRole->DomainNameDns));
  180. Dbg(DEB_SNAPIN, "DomainForestName: %ws\n", CHECK_NULL(pDsRole->DomainForestName));
  181. //
  182. // If machine is in a workgroup, we're done.
  183. //
  184. if (pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation ||
  185. pDsRole->MachineRole == DsRole_RoleStandaloneServer)
  186. {
  187. Dbg(DEB_SNAPIN, "Target machine is not joined to a domain\n");
  188. m_bIsStandAlone = TRUE;
  189. m_bIsDC = FALSE;
  190. break;
  191. }
  192. //
  193. // Target Computer is joined to a domain
  194. //
  195. m_bIsStandAlone = FALSE;
  196. if (pDsRole->DomainNameFlat)
  197. {
  198. m_strTargetDomainFlat = pDsRole->DomainNameFlat;
  199. }
  200. if (pDsRole->DomainNameDns)
  201. {
  202. m_strTargetDomainDNS = pDsRole->DomainNameDns;
  203. }
  204. //
  205. // TargetComputer is Joined to a domain and is dc
  206. //
  207. if (pDsRole->MachineRole == DsRole_RolePrimaryDomainController ||
  208. pDsRole->MachineRole == DsRole_RoleBackupDomainController)
  209. {
  210. m_bIsDC = TRUE;
  211. m_strDCName = m_strTargetComputerName;
  212. break;
  213. }
  214. //
  215. //Target computer is Joined to domain and is not a DC.
  216. //Get a DC for the domain
  217. //
  218. PWSTR pwzDomainNameForDsGetDc;
  219. ULONG flDsGetDc = DS_DIRECTORY_SERVICE_PREFERRED;
  220. if (pDsRole->DomainNameDns)
  221. {
  222. pwzDomainNameForDsGetDc = pDsRole->DomainNameDns;
  223. flDsGetDc |= DS_IS_DNS_NAME;
  224. Dbg(DEB_TRACE,
  225. "DsGetDcName(Domain=%ws, flags=DS_IS_DNS_NAME | DS_DIRECTORY_SERVICE_PREFERRED)\n",
  226. CHECK_NULL(pwzDomainNameForDsGetDc));
  227. }
  228. else
  229. {
  230. pwzDomainNameForDsGetDc = pDsRole->DomainNameFlat;
  231. flDsGetDc |= DS_IS_FLAT_NAME;
  232. Dbg(DEB_TRACE,
  233. "DsGetDcName(Domain=%ws, flags=DS_IS_FLAT_NAME | DS_DIRECTORY_SERVICE_PREFERRED)\n",
  234. CHECK_NULL(pwzDomainNameForDsGetDc));
  235. }
  236. ulResult = DsGetDcName(NULL,
  237. pwzDomainNameForDsGetDc,
  238. NULL,
  239. NULL,
  240. flDsGetDc,
  241. &pdci);
  242. if (ulResult != NO_ERROR)
  243. {
  244. Dbg(DEB_ERROR,
  245. "DsGetDcName for domain %ws returned %#x, Too bad don't have the dc name\n",
  246. pwzDomainNameForDsGetDc,
  247. ulResult);
  248. break;
  249. }
  250. ASSERT(pdci);
  251. m_strDCName = pdci->DomainControllerName;
  252. } while (0);
  253. if (pdci)
  254. {
  255. NetApiBufferFree(pdci);
  256. }
  257. if (pDsRole)
  258. {
  259. DsRoleFreeMemory(pDsRole);
  260. }
  261. }
  262. int
  263. CopyUnicodeString(CString* pstrDest, PLSA_UNICODE_STRING pSrc)
  264. {
  265. ULONG cchSrc;
  266. // If UNICODE, cchDest is size of destination buffer in chars
  267. // Else (MBCS) cchDest is size of destination buffer in bytes
  268. if (pstrDest == NULL )
  269. return 0;
  270. if (pSrc == NULL || pSrc->Buffer == NULL)
  271. return 0;
  272. // Get # of chars in source (not including NULL)
  273. cchSrc = pSrc->Length/sizeof(WCHAR);
  274. //
  275. // Note that pSrc->Buffer may not be NULL terminated so we can't just
  276. // call lstrcpynW with cchDest. Also, if we call lstrcpynW with cchSrc,
  277. // it copies the correct # of chars, but then overwrites the last char
  278. // with NULL giving an incorrect result. If we call lstrcpynW with
  279. // (cchSrc+1) it reads past the end of the buffer, which may fault (360251)
  280. // causing lstrcpynW's exception handler to return 0 without NULL-
  281. // terminating the resulting string.
  282. //
  283. // So let's just copy the bits.
  284. //
  285. CString temp(pSrc->Buffer,cchSrc);
  286. *pstrDest = temp;
  287. return cchSrc;
  288. }
  289. VOID
  290. GetAccountAndDomainName(int index,
  291. PLSA_TRANSLATED_NAME pTranslatedNames,
  292. PLSA_REFERENCED_DOMAIN_LIST pRefDomains,
  293. CString* pstrAccountName,
  294. CString* pstrDomainName,
  295. SID_NAME_USE* puse)
  296. {
  297. PLSA_TRANSLATED_NAME pLsaName = &pTranslatedNames[index];
  298. PLSA_TRUST_INFORMATION pLsaDomain = NULL;
  299. // Get the referenced domain, if any
  300. if (pLsaName->DomainIndex >= 0 && pRefDomains)
  301. {
  302. pLsaDomain = &pRefDomains->Domains[pLsaName->DomainIndex];
  303. }
  304. CopyUnicodeString(pstrAccountName,&pLsaName->Name);
  305. if (pLsaDomain)
  306. {
  307. CopyUnicodeString(pstrDomainName,&pLsaDomain->Name);
  308. }
  309. *puse = pLsaName->Use;
  310. }
  311. HRESULT
  312. TranslateNameInternal(IN const CString& strAccountName,
  313. IN EXTENDED_NAME_FORMAT AccountNameFormat,
  314. IN EXTENDED_NAME_FORMAT DesiredNameFormat,
  315. OUT CString* pstrTranslatedName)
  316. {
  317. if (!pstrTranslatedName)
  318. {
  319. ASSERT(pstrTranslatedName);
  320. return E_POINTER;
  321. }
  322. HRESULT hr = S_OK;
  323. //
  324. // cchTrans is static so that if a particular installation's
  325. // account names are really long, we'll not be resizing the
  326. // buffer for each account.
  327. //
  328. static ULONG cchTrans = MAX_PATH;
  329. ULONG cch = cchTrans;
  330. LPTSTR lpszTranslatedName = (LPTSTR)LocalAlloc(LPTR, cch*sizeof(WCHAR));
  331. if (lpszTranslatedName == NULL)
  332. return E_OUTOFMEMORY;
  333. *lpszTranslatedName = L'\0';
  334. //
  335. // TranslateName is delay-loaded from secur32.dll using the linker's
  336. // delay-load mechanism. Therefore, wrap with an exception handler.
  337. //
  338. __try
  339. {
  340. while(!::TranslateName(strAccountName,
  341. AccountNameFormat,
  342. DesiredNameFormat,
  343. lpszTranslatedName,
  344. &cch))
  345. {
  346. if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
  347. {
  348. LocalFree(lpszTranslatedName);
  349. lpszTranslatedName = (LPTSTR)LocalAlloc(LPTR, cch*sizeof(WCHAR));
  350. if (!lpszTranslatedName)
  351. {
  352. hr = E_OUTOFMEMORY;
  353. break;
  354. }
  355. *lpszTranslatedName = L'\0';
  356. }
  357. else
  358. {
  359. hr = E_FAIL;
  360. break;
  361. }
  362. }
  363. cchTrans = max(cch, cchTrans);
  364. }
  365. __except(EXCEPTION_EXECUTE_HANDLER)
  366. {
  367. hr = E_FAIL;
  368. }
  369. if (FAILED(hr))
  370. {
  371. if(lpszTranslatedName)
  372. {
  373. LocalFree(lpszTranslatedName);
  374. }
  375. }
  376. else
  377. {
  378. *pstrTranslatedName = lpszTranslatedName;
  379. }
  380. return hr;
  381. }
  382. #define DSOP_FILTER_COMMON1 ( DSOP_FILTER_INCLUDE_ADVANCED_VIEW \
  383. | DSOP_FILTER_USERS \
  384. | DSOP_FILTER_UNIVERSAL_GROUPS_SE \
  385. | DSOP_FILTER_GLOBAL_GROUPS_SE \
  386. | DSOP_FILTER_COMPUTERS \
  387. )
  388. #define DSOP_FILTER_COMMON2 ( DSOP_FILTER_COMMON1 \
  389. | DSOP_FILTER_WELL_KNOWN_PRINCIPALS \
  390. | DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE\
  391. )
  392. #define DSOP_FILTER_COMMON3 ( DSOP_FILTER_COMMON2 \
  393. | DSOP_FILTER_BUILTIN_GROUPS \
  394. )
  395. #define DSOP_FILTER_DL_COMMON1 ( DSOP_DOWNLEVEL_FILTER_USERS \
  396. | DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS \
  397. )
  398. #define DSOP_FILTER_DL_COMMON2 ( DSOP_FILTER_DL_COMMON1 \
  399. | DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS \
  400. )
  401. #define DSOP_FILTER_DL_COMMON3 ( DSOP_FILTER_DL_COMMON2 \
  402. | DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS \
  403. )
  404. // Same as DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS, except no CREATOR flags.
  405. // Note that we need to keep this in sync with any object picker changes.
  406. #define DSOP_FILTER_DL_WELLKNOWN ( DSOP_DOWNLEVEL_FILTER_WORLD \
  407. | DSOP_DOWNLEVEL_FILTER_AUTHENTICATED_USER \
  408. | DSOP_DOWNLEVEL_FILTER_ANONYMOUS \
  409. | DSOP_DOWNLEVEL_FILTER_BATCH \
  410. | DSOP_DOWNLEVEL_FILTER_DIALUP \
  411. | DSOP_DOWNLEVEL_FILTER_INTERACTIVE \
  412. | DSOP_DOWNLEVEL_FILTER_NETWORK \
  413. | DSOP_DOWNLEVEL_FILTER_SERVICE \
  414. | DSOP_DOWNLEVEL_FILTER_SYSTEM \
  415. | DSOP_DOWNLEVEL_FILTER_TERMINAL_SERVER \
  416. )
  417. #define DECLARE_SCOPE(t,f,b,m,n,d) \
  418. { sizeof(DSOP_SCOPE_INIT_INFO), (t), (f|DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS|DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS), { { (b), (m), (n) }, (d) }, NULL, NULL, S_OK }
  419. // The domain to which the target computer is joined.
  420. // Make 2 scopes, one for uplevel domains, the other for downlevel.
  421. #define JOINED_DOMAIN_SCOPE(f) \
  422. DECLARE_SCOPE(DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN,(f),0,(DSOP_FILTER_COMMON2 & ~(DSOP_FILTER_UNIVERSAL_GROUPS_SE|DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE)),DSOP_FILTER_COMMON2,0), \
  423. DECLARE_SCOPE(DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN,(f),0,0,0,DSOP_FILTER_DL_COMMON2)
  424. // The domain for which the target computer is a Domain Controller.
  425. // Make 2 scopes, one for uplevel domains, the other for downlevel.
  426. #define JOINED_DOMAIN_SCOPE_DC(f) \
  427. DECLARE_SCOPE(DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN,(f),0,(DSOP_FILTER_COMMON3 & ~DSOP_FILTER_UNIVERSAL_GROUPS_SE),DSOP_FILTER_COMMON3,0), \
  428. DECLARE_SCOPE(DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN,(f),0,0,0,DSOP_FILTER_DL_COMMON3)
  429. // Target computer scope. Computer scopes are always treated as
  430. // downlevel (i.e., they use the WinNT provider).
  431. #define TARGET_COMPUTER_SCOPE(f)\
  432. DECLARE_SCOPE(DSOP_SCOPE_TYPE_TARGET_COMPUTER,(f),0,0,0,DSOP_FILTER_DL_COMMON3)
  433. // The Global Catalog
  434. #define GLOBAL_CATALOG_SCOPE(f) \
  435. DECLARE_SCOPE(DSOP_SCOPE_TYPE_GLOBAL_CATALOG,(f),DSOP_FILTER_COMMON1|DSOP_FILTER_WELL_KNOWN_PRINCIPALS,0,0,0)
  436. // The domains in the same forest (enterprise) as the domain to which
  437. // the target machine is joined. Note these can only be DS-aware
  438. #define ENTERPRISE_SCOPE(f) \
  439. DECLARE_SCOPE(DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN,(f),DSOP_FILTER_COMMON1,0,0,0)
  440. // Domains external to the enterprise but trusted directly by the
  441. // domain to which the target machine is joined.
  442. #define EXTERNAL_SCOPE(f) \
  443. DECLARE_SCOPE(DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN|DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN,\
  444. (f),DSOP_FILTER_COMMON1,0,0,DSOP_DOWNLEVEL_FILTER_USERS|DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS)
  445. // Workgroup scope. Only valid if the target computer is not joined
  446. // to a domain.
  447. #define WORKGROUP_SCOPE(f) \
  448. DECLARE_SCOPE(DSOP_SCOPE_TYPE_WORKGROUP,(f),0,0,0, DSOP_FILTER_DL_COMMON1|DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS )
  449. //
  450. // Array of Default Scopes
  451. //
  452. static const DSOP_SCOPE_INIT_INFO g_aDefaultScopes[] =
  453. {
  454. JOINED_DOMAIN_SCOPE(DSOP_SCOPE_FLAG_STARTING_SCOPE),
  455. TARGET_COMPUTER_SCOPE(0),
  456. GLOBAL_CATALOG_SCOPE(0),
  457. ENTERPRISE_SCOPE(0),
  458. EXTERNAL_SCOPE(0),
  459. };
  460. //
  461. // Same as above, but without the Target Computer
  462. // Used when the target is a Domain Controller
  463. //
  464. static const DSOP_SCOPE_INIT_INFO g_aDCScopes[] =
  465. {
  466. JOINED_DOMAIN_SCOPE_DC(DSOP_SCOPE_FLAG_STARTING_SCOPE),
  467. GLOBAL_CATALOG_SCOPE(0),
  468. ENTERPRISE_SCOPE(0),
  469. EXTERNAL_SCOPE(0),
  470. };
  471. //
  472. // Array of scopes for standalone machines
  473. //
  474. static const DSOP_SCOPE_INIT_INFO g_aStandAloneScopes[] =
  475. {
  476. //
  477. //On Standalone machine Both User And Groups are selected by default
  478. //
  479. TARGET_COMPUTER_SCOPE(DSOP_SCOPE_FLAG_STARTING_SCOPE|DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS),
  480. };
  481. //
  482. // Attributes that we want the Object Picker to retrieve
  483. //
  484. static const LPCTSTR g_aszOPAttributes[] =
  485. {
  486. TEXT("ObjectSid"),
  487. };
  488. /******************************************************************************
  489. Class: CSidHandler
  490. Purpose: class for handling tasks related to selecting windows users,
  491. converting sids to name etc.
  492. ******************************************************************************/
  493. DEBUG_DECLARE_INSTANCE_COUNTER(CSidHandler);
  494. CSidHandler::
  495. CSidHandler(CMachineInfo* pMachineInfo)
  496. :m_pMachineInfo(pMachineInfo),
  497. m_bObjectPickerInitialized(FALSE)
  498. {
  499. DEBUG_INCREMENT_INSTANCE_COUNTER(CSidHandler);
  500. InitializeCriticalSection(&m_csSidHandlerLock);
  501. InitializeCriticalSection(&m_csSidCacheLock);
  502. }
  503. CSidHandler::~CSidHandler()
  504. {
  505. DEBUG_DECREMENT_INSTANCE_COUNTER(CSidHandler);
  506. delete m_pMachineInfo;
  507. //Remove itesm from the map
  508. LockSidHandler();
  509. for (SidCacheMap::iterator it = m_mapSidCache.begin();
  510. it != m_mapSidCache.end();
  511. ++it)
  512. {
  513. delete (*it).second;
  514. }
  515. UnlockSidHandler();
  516. DeleteCriticalSection(&m_csSidCacheLock);
  517. DeleteCriticalSection(&m_csSidHandlerLock);
  518. }
  519. PSID_CACHE_ENTRY
  520. CSidHandler::
  521. GetEntryFromCache(PSID pSid)
  522. {
  523. PSID_CACHE_ENTRY pSidCache = NULL;
  524. LockSidHandler();
  525. //Check if item in the cache
  526. CString strSid;
  527. ConvertSidToStringSid(pSid,&strSid);
  528. SidCacheMap::iterator it = m_mapSidCache.find(&strSid);
  529. if(it != m_mapSidCache.end())
  530. pSidCache = (*it).second;
  531. if(!pSidCache)
  532. {
  533. //No in the cache Create a new entry and add to the cache
  534. pSidCache = new SID_CACHE_ENTRY(pSid);
  535. if(pSidCache)
  536. {
  537. m_mapSidCache.insert(pair<const CString*,PSID_CACHE_ENTRY>(&(pSidCache->GetStringSid()),pSidCache));
  538. }
  539. }
  540. UnlockSidHandler();
  541. return pSidCache;
  542. }
  543. //+----------------------------------------------------------------------------
  544. // Synopsis: CoCreateInstance ObjectPikcer
  545. //-----------------------------------------------------------------------------
  546. HRESULT
  547. CSidHandler::
  548. GetObjectPicker()
  549. {
  550. LockSidHandler();
  551. TRACE_METHOD_EX(DEB_SNAPIN,CSidHandler,GetObjectPicker)
  552. HRESULT hr = S_OK;
  553. if (!m_spDsObjectPicker)
  554. {
  555. hr = CoCreateInstance(CLSID_DsObjectPicker,
  556. NULL,
  557. CLSCTX_INPROC_SERVER,
  558. IID_IDsObjectPicker,
  559. (LPVOID*)&m_spDsObjectPicker);
  560. CHECK_HRESULT(hr);
  561. }
  562. UnlockSidHandler();
  563. return hr;
  564. }
  565. //+----------------------------------------------------------------------------
  566. // Function: InitObjectPicker
  567. // Synopsis: Initializes the object picker. This needs to be done once in
  568. // lifetime
  569. //-----------------------------------------------------------------------------
  570. HRESULT
  571. CSidHandler::InitObjectPicker()
  572. {
  573. TRACE_METHOD_EX(DEB_SNAPIN,CSidHandler,InitObjectPicker)
  574. HRESULT hr = S_OK;
  575. hr = GetObjectPicker();
  576. if(FAILED(hr))
  577. return hr;
  578. LockSidHandler();
  579. do
  580. {
  581. if(m_bObjectPickerInitialized)
  582. break;
  583. DSOP_INIT_INFO InitInfo;
  584. InitInfo.cbSize = sizeof(InitInfo);
  585. InitInfo.flOptions = DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK | DSOP_FLAG_MULTISELECT;
  586. //Select the appropriate scopes
  587. PCDSOP_SCOPE_INIT_INFO pScopes;
  588. ULONG cScopes;
  589. if(m_pMachineInfo->IsStandAlone())
  590. {
  591. cScopes = ARRAYLEN(g_aStandAloneScopes);
  592. pScopes = g_aStandAloneScopes;
  593. }
  594. else if(m_pMachineInfo->IsDC())
  595. {
  596. cScopes = ARRAYLEN(g_aDCScopes);
  597. pScopes = g_aDCScopes;
  598. }
  599. else
  600. {
  601. pScopes = g_aDefaultScopes;
  602. cScopes = ARRAYLEN(g_aDefaultScopes);
  603. }
  604. InitInfo.pwzTargetComputer = m_pMachineInfo->GetMachineName();
  605. InitInfo.cDsScopeInfos = cScopes;
  606. InitInfo.aDsScopeInfos = (PDSOP_SCOPE_INIT_INFO)LocalAlloc(LPTR, sizeof(*pScopes)*cScopes);
  607. if (!InitInfo.aDsScopeInfos)
  608. {
  609. hr = E_OUTOFMEMORY;
  610. break;
  611. }
  612. CopyMemory(InitInfo.aDsScopeInfos, pScopes, sizeof(*pScopes)*cScopes);
  613. InitInfo.cAttributesToFetch = ARRAYLEN(g_aszOPAttributes);
  614. InitInfo.apwzAttributeNames = (LPCTSTR*)g_aszOPAttributes;
  615. if (m_pMachineInfo->IsDC())
  616. {
  617. for (ULONG i = 0; i < cScopes; i++)
  618. {
  619. // Set the DC name if appropriate
  620. if(InitInfo.aDsScopeInfos[i].flType & DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN)
  621. {
  622. InitInfo.aDsScopeInfos[i].pwzDcName = InitInfo.pwzTargetComputer;
  623. }
  624. }
  625. }
  626. //Initialize the object picker
  627. hr = m_spDsObjectPicker->Initialize(&InitInfo);
  628. if (SUCCEEDED(hr))
  629. {
  630. m_bObjectPickerInitialized = TRUE;
  631. }
  632. if(InitInfo.aDsScopeInfos)
  633. LocalFree(InitInfo.aDsScopeInfos);
  634. }while(0);
  635. UnlockSidHandler();
  636. return hr;
  637. }
  638. //+----------------------------------------------------------------------------
  639. // Synopsis: Pops up object pikcer. Function also does the sidlookop for
  640. // objects selected. Information is returned in listSidCacheEntry
  641. //-----------------------------------------------------------------------------
  642. HRESULT
  643. CSidHandler::
  644. GetUserGroup(IN HWND hDlg,
  645. IN CBaseAz* pOwnerAz,
  646. OUT CList<CBaseAz*,CBaseAz*>& listWindowsGroups)
  647. {
  648. if(!pOwnerAz)
  649. {
  650. ASSERT(pOwnerAz);
  651. return E_POINTER;
  652. }
  653. TRACE_METHOD_EX(DEB_SNAPIN,CSidHandler,GetUserGroup)
  654. HRESULT hr;
  655. LPDATAOBJECT pdoSelection = NULL;
  656. STGMEDIUM medium = {0};
  657. FORMATETC fe = { (CLIPFORMAT)g_cfDsSelectionList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  658. PDS_SELECTION_LIST pDsSelList = NULL;
  659. do
  660. {
  661. // Create and initialize the Object Picker object
  662. hr = InitObjectPicker();
  663. if (FAILED(hr))
  664. return hr;
  665. // Bring up the object picker dialog
  666. hr = m_spDsObjectPicker->InvokeDialog(hDlg, &pdoSelection);
  667. BREAK_ON_FAIL_HRESULT(hr);
  668. //User Pressed cancel
  669. if (S_FALSE == hr)
  670. {
  671. hr = S_OK;
  672. break;
  673. }
  674. hr = pdoSelection->GetData(&fe, &medium);
  675. BREAK_ON_FAIL_HRESULT(hr);
  676. pDsSelList = (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal);
  677. if (!pDsSelList)
  678. {
  679. hr = E_FAIL;
  680. BREAK_ON_FAIL_HRESULT(hr);
  681. }
  682. CList<SID_CACHE_ENTRY*,SID_CACHE_ENTRY*> listSidCacheEntry;
  683. CList<SID_CACHE_ENTRY*,SID_CACHE_ENTRY*> listUnresolvedSidCacheEntry;
  684. //Get the listof sidcache entries from pDsSelList
  685. hr = GetSidCacheListFromOPOutput(pDsSelList,
  686. listSidCacheEntry,
  687. listUnresolvedSidCacheEntry);
  688. BREAK_ON_FAIL_HRESULT(hr);
  689. //Resolve the sids not resolved in listSidCacheEntry
  690. LookupSidsHelper(listUnresolvedSidCacheEntry,
  691. m_pMachineInfo->GetMachineName(),
  692. m_pMachineInfo->IsStandAlone(),
  693. m_pMachineInfo->IsDC(),
  694. FALSE);
  695. POSITION pos = listSidCacheEntry.GetHeadPosition();
  696. for( int i = 0; i < listSidCacheEntry.GetCount(); ++i)
  697. {
  698. SID_CACHE_ENTRY* pSidCacheEntry = listSidCacheEntry.GetNext(pos);
  699. CSidCacheAz* pSidCacheAz = new CSidCacheAz(pSidCacheEntry,
  700. pOwnerAz);
  701. if(!pSidCacheAz)
  702. {
  703. hr = E_OUTOFMEMORY;
  704. break;
  705. }
  706. listWindowsGroups.AddTail(pSidCacheAz);
  707. }
  708. }while(0);
  709. if (pDsSelList)
  710. GlobalUnlock(medium.hGlobal);
  711. ReleaseStgMedium(&medium);
  712. if(pdoSelection)
  713. pdoSelection->Release();
  714. return hr;
  715. }
  716. //+----------------------------------------------------------------------------
  717. // Function:LookupSidsHelper
  718. // Synopsis:Calls LsaLookupSid for sids in listSids. First it tries on
  719. // strServerName machine and next it tries on DC( if possible).
  720. // Arguments:listSidCacheEntry
  721. // Returns:
  722. //-----------------------------------------------------------------------------
  723. VOID
  724. CSidHandler::
  725. LookupSidsHelper(IN OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listSidCacheEntry,
  726. IN const CString& strServerName,
  727. IN BOOL bStandAlone,
  728. IN BOOL bIsDC,
  729. IN BOOL bSecondTry)
  730. {
  731. TRACE_METHOD_EX(DEB_SNAPIN,CSidHandler,LookupSidsHelper)
  732. PLSA_REFERENCED_DOMAIN_LIST pRefDomains = NULL;
  733. PLSA_TRANSLATED_NAME pTranslatedNames = NULL;
  734. LSA_HANDLE hlsa = NULL;
  735. CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY> listUnknownSids;
  736. PSID *ppSid = NULL;
  737. if(!listSidCacheEntry.GetCount())
  738. return;
  739. do
  740. {
  741. //
  742. //Open LsaConnection
  743. //
  744. hlsa = GetLSAConnection(strServerName,
  745. POLICY_LOOKUP_NAMES);
  746. if (NULL == hlsa &&
  747. !strServerName.IsEmpty() &&
  748. !bSecondTry)
  749. {
  750. CString strLocalMachine = L"";
  751. hlsa = GetLSAConnection(strLocalMachine, POLICY_LOOKUP_NAMES);
  752. }
  753. if (hlsa == NULL)
  754. {
  755. break;
  756. }
  757. //
  758. //Now we have LSA Connection
  759. //Do LookupSids
  760. //
  761. int cSids = (int)listSidCacheEntry.GetCount();
  762. ppSid = new PSID[cSids];
  763. if(!ppSid)
  764. {
  765. break;
  766. }
  767. POSITION pos = listSidCacheEntry.GetHeadPosition();
  768. for (int i=0;i < cSids; i++)
  769. {
  770. PSID_CACHE_ENTRY pSidCacheEntry = listSidCacheEntry.GetNext(pos);
  771. ppSid[i] = pSidCacheEntry->GetSid();
  772. }
  773. DWORD dwStatus = 0;
  774. dwStatus = LsaLookupSids(hlsa,
  775. cSids,
  776. ppSid,
  777. &pRefDomains,
  778. &pTranslatedNames);
  779. if (STATUS_SUCCESS == dwStatus ||
  780. STATUS_SOME_NOT_MAPPED == dwStatus ||
  781. STATUS_NONE_MAPPED == dwStatus)
  782. {
  783. ASSERT(pTranslatedNames);
  784. ASSERT(pRefDomains);
  785. //
  786. // Build cache entries with NT4 style names
  787. //
  788. pos = listSidCacheEntry.GetHeadPosition();
  789. for (int i = 0; i < cSids; i++)
  790. {
  791. PSID_CACHE_ENTRY pSidCacheEntry = listSidCacheEntry.GetNext(pos);
  792. PSID pSid = pSidCacheEntry->GetSid();
  793. BOOL bNoCache = FALSE;
  794. CString strAccountName;
  795. CString strDomainName;
  796. SID_NAME_USE sid_name_use;
  797. GetAccountAndDomainName(i,
  798. pTranslatedNames,
  799. pRefDomains,
  800. &strAccountName,
  801. &strDomainName,
  802. &sid_name_use);
  803. CString strLogonName;
  804. //
  805. // Build NT4 "domain\user" style name
  806. //
  807. if (!strDomainName.IsEmpty() && !strAccountName.IsEmpty())
  808. {
  809. strLogonName = strDomainName;
  810. strLogonName += L"\\";
  811. strLogonName += strAccountName;
  812. }
  813. switch (sid_name_use)
  814. {
  815. case SidTypeUser:
  816. {
  817. if(!bStandAlone)
  818. {
  819. // Get "User Principal Name" etc.
  820. CString strNewLogonName;
  821. CString strNewAccountName;
  822. GetUserFriendlyName(strLogonName,
  823. &strNewLogonName,
  824. &strNewAccountName);
  825. if (!strNewLogonName.IsEmpty())
  826. strLogonName = strNewLogonName;
  827. if (!strNewAccountName.IsEmpty())
  828. strAccountName = strNewAccountName;
  829. }
  830. break;
  831. }
  832. case SidTypeGroup:
  833. case SidTypeDomain:
  834. break;
  835. case SidTypeAlias:
  836. {
  837. if (!IsAliasSid(pSid))
  838. {
  839. sid_name_use = SidTypeGroup;
  840. break;
  841. }
  842. if(!m_pMachineInfo->GetTargetDomainFlat().IsEmpty() &&
  843. !strAccountName.IsEmpty())
  844. {
  845. strLogonName = m_pMachineInfo->GetTargetDomainFlat();
  846. strLogonName += L"\\";
  847. strLogonName += strAccountName;
  848. }
  849. break;
  850. }
  851. // else Fall Through
  852. case SidTypeWellKnownGroup:
  853. {
  854. // No logon name for these
  855. strLogonName.Empty();
  856. break;
  857. }
  858. case SidTypeDeletedAccount:
  859. case SidTypeInvalid: // 7
  860. break;
  861. case SidTypeUnknown: // 8
  862. {
  863. // Some SIDs can only be looked up on a DC, so
  864. // if pszServer is not a DC, remember them and
  865. // look them up on a DC after this loop is done.
  866. if (!bSecondTry && !bStandAlone && !bIsDC && !(m_pMachineInfo->GetDCName()).IsEmpty())
  867. {
  868. //Add to unknown list
  869. listUnknownSids.AddTail(pSidCacheEntry);
  870. bNoCache = TRUE;
  871. }
  872. break;
  873. }
  874. case SidTypeComputer: // 9
  875. {
  876. // TODO
  877. // Strip the trailing '$'
  878. break;
  879. }
  880. }
  881. if (!bNoCache)
  882. {
  883. //Only one sidcahce entry per sid chache handler can
  884. //be updated at a time. Which is fine.
  885. LockSidCacheEntry();
  886. pSidCacheEntry->AddNameAndType(sid_name_use,
  887. strAccountName,
  888. strLogonName);
  889. UnlockSidCacheEntry();
  890. }
  891. }
  892. }
  893. }while(0);
  894. // Cleanup
  895. if(pTranslatedNames)
  896. LsaFreeMemory(pTranslatedNames);
  897. if(pRefDomains)
  898. LsaFreeMemory(pRefDomains);
  899. if(hlsa)
  900. LsaClose(hlsa);
  901. if(ppSid)
  902. delete[] ppSid;
  903. if (!listUnknownSids.IsEmpty())
  904. {
  905. //
  906. // Some (or all) SIDs were unknown on the target machine,
  907. // try a DC for the target machine's primary domain.
  908. //
  909. // This typically happens for certain Alias SIDs, such
  910. // as Print Operators and System Operators, for which LSA
  911. // only returns names if the lookup is done on a DC.
  912. //
  913. LookupSidsHelper(listUnknownSids,
  914. m_pMachineInfo->GetDCName(),
  915. FALSE,
  916. TRUE,
  917. TRUE);
  918. }
  919. }
  920. //+----------------------------------------------------------------------------
  921. // Function: GetUserFriendlyName
  922. // Synopsis: Gets name in Domain\Name format and returns UPN name and
  923. // Display Name.
  924. // Arguments:
  925. // Returns:
  926. //-----------------------------------------------------------------------------
  927. void
  928. CSidHandler::
  929. GetUserFriendlyName(IN const CString & strSamLogonName,
  930. OUT CString *pstrLogonName,
  931. OUT CString *pstrDisplayName)
  932. {
  933. if(strSamLogonName.IsEmpty()|| !pstrLogonName || !pstrDisplayName)
  934. {
  935. ASSERT(strSamLogonName.IsEmpty());
  936. ASSERT(!pstrLogonName);
  937. ASSERT(!pstrDisplayName);
  938. return;
  939. }
  940. //
  941. // Start by getting the FQDN. Cracking is most efficient when the
  942. // FQDN is the starting point.
  943. //
  944. // TranslateName takes a while to complete, so bUseSamCompatibleInfo
  945. // should be TRUE whenever possible, e.g. for local accounts on a non-DC
  946. // or anything where we know a FQDN doesn't exist.
  947. //
  948. CString strFQDN;
  949. if (FAILED(TranslateNameInternal(strSamLogonName,
  950. NameSamCompatible,
  951. NameFullyQualifiedDN,
  952. &strFQDN)))
  953. {
  954. return;
  955. }
  956. //
  957. //Get UPN
  958. //
  959. TranslateNameInternal(strFQDN,
  960. NameFullyQualifiedDN,
  961. NameUserPrincipal,
  962. pstrLogonName);
  963. //
  964. //Get Display Name
  965. //
  966. TranslateNameInternal(strFQDN,
  967. NameFullyQualifiedDN,
  968. NameDisplay,
  969. pstrDisplayName);
  970. }
  971. //+----------------------------------------------------------------------------
  972. // Function: LookupSids
  973. // Synopsis: Given a list of sids, retuns a list of corresponding
  974. // CSidCacheAz objects
  975. // Arguments:
  976. // Returns:
  977. //-----------------------------------------------------------------------------
  978. HRESULT
  979. CSidHandler::
  980. LookupSids(IN CBaseAz* pOwnerAz,
  981. IN CList<PSID,PSID>& listSids,
  982. OUT CList<CBaseAz*,CBaseAz*>& listSidCacheAz)
  983. {
  984. if(!pOwnerAz)
  985. {
  986. ASSERT(pOwnerAz);
  987. return E_POINTER;
  988. }
  989. HRESULT hr = S_OK;
  990. CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY> listSidCacheEntries;
  991. CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY> listUnResolvedSidCacheEntries;
  992. hr = GetSidCacheListFromSidList(listSids,
  993. listSidCacheEntries,
  994. listUnResolvedSidCacheEntries);
  995. if(FAILED(hr))
  996. {
  997. return hr;
  998. }
  999. //Do the Lookup for unresolved sids
  1000. LookupSidsHelper(listUnResolvedSidCacheEntries,
  1001. m_pMachineInfo->GetMachineName(),
  1002. m_pMachineInfo->IsStandAlone(),
  1003. m_pMachineInfo->IsDC(),
  1004. FALSE);
  1005. POSITION pos = listSidCacheEntries.GetHeadPosition();
  1006. for( int i = 0; i < listSidCacheEntries.GetCount(); ++i)
  1007. {
  1008. PSID_CACHE_ENTRY pSidCacheEntry = listSidCacheEntries.GetNext(pos);
  1009. CSidCacheAz* pSidCacheAz = new CSidCacheAz(pSidCacheEntry,
  1010. pOwnerAz);
  1011. if(!pSidCacheAz)
  1012. {
  1013. hr = E_OUTOFMEMORY;
  1014. break;
  1015. }
  1016. listSidCacheAz.AddTail(pSidCacheAz);
  1017. }
  1018. if(FAILED(hr))
  1019. {
  1020. RemoveItemsFromList(listSidCacheAz);
  1021. }
  1022. return hr;
  1023. }
  1024. //+----------------------------------------------------------------------------
  1025. // Function: GetSidCacheListFromSidList
  1026. // Gets a list of sids and returns corresponding list of sidcache
  1027. // entries and unresolved sid cache entries
  1028. // Arguments:listSid: List of sids
  1029. // listSidCacheEntry: Gets list of SidCacheEntries
  1030. // listUnresolvedSidCacheEntry Gets List of unresolved
  1031. // SidCacheEntries
  1032. //-----------------------------------------------------------------------------
  1033. HRESULT
  1034. CSidHandler::
  1035. GetSidCacheListFromSidList(IN CList<PSID,PSID>& listSid,
  1036. OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listSidCacheEntry,
  1037. OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listUnresolvedSidCacheEntry)
  1038. {
  1039. POSITION pos = listSid.GetHeadPosition();
  1040. for( int i = 0; i < listSid.GetCount(); ++i)
  1041. {
  1042. PSID pSid = listSid.GetNext(pos);
  1043. PSID_CACHE_ENTRY pEntry = GetEntryFromCache(pSid);
  1044. if(!pEntry)
  1045. {
  1046. return E_OUTOFMEMORY;
  1047. }
  1048. listSidCacheEntry.AddTail(pEntry);
  1049. if(!pEntry->IsSidResolved())
  1050. listUnresolvedSidCacheEntry.AddTail(pEntry);
  1051. }
  1052. return S_OK;
  1053. }
  1054. //+----------------------------------------------------------------------------
  1055. // Function: GetSidCacheListFromOPOutput
  1056. // Synopsis: Gets the sid from Object Pickers output and returns corresponding
  1057. // list of SidCacheEntries. Also returns sids of unresolved sids.
  1058. //
  1059. // Arguments:pDsSelList selection list from OP.
  1060. // listSidCacheEntry: Gets list of SidCacheEntries
  1061. // listUnresolvedSidCacheEntry Gets List of unresolved
  1062. // SidCacheEntries
  1063. //-----------------------------------------------------------------------------
  1064. HRESULT
  1065. CSidHandler::
  1066. GetSidCacheListFromOPOutput(IN PDS_SELECTION_LIST pDsSelList,
  1067. OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listSidCacheEntry,
  1068. OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listUnresolvedSidCacheEntry)
  1069. {
  1070. if(!pDsSelList)
  1071. {
  1072. ASSERT(pDsSelList);
  1073. return E_POINTER;
  1074. }
  1075. HRESULT hr = S_OK;
  1076. int cNames = pDsSelList->cItems;
  1077. for (int i = 0; i < cNames; i++)
  1078. {
  1079. PSID pSid = NULL;
  1080. LPVARIANT pvarSid = pDsSelList->aDsSelection[i].pvarFetchedAttributes;
  1081. if (NULL == pvarSid || (VT_ARRAY | VT_UI1) != V_VT(pvarSid)
  1082. || FAILED(SafeArrayAccessData(V_ARRAY(pvarSid), &pSid)))
  1083. {
  1084. continue;
  1085. }
  1086. PSID_CACHE_ENTRY pEntry = GetEntryFromCache(pSid);
  1087. if(!pEntry)
  1088. {
  1089. return E_OUTOFMEMORY;
  1090. }
  1091. listSidCacheEntry.AddTail(pEntry);
  1092. if(!pEntry->IsSidResolved())
  1093. listUnresolvedSidCacheEntry.AddTail(pEntry);
  1094. }
  1095. return S_OK;
  1096. }