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.

1686 lines
45 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: misc.cpp
  8. //
  9. // This file contains miscellaneous helper functions.
  10. //
  11. //--------------------------------------------------------------------------
  12. #include "aclpriv.h"
  13. /*******************************************************************
  14. NAME: GetAceSid
  15. SYNOPSIS: Gets pointer to SID from an ACE
  16. ENTRY: pAce - pointer to ACE
  17. EXIT:
  18. RETURNS: Pointer to SID if successful, NULL otherwise
  19. NOTES:
  20. HISTORY:
  21. JeffreyS 08-Oct-1996 Created
  22. ********************************************************************/
  23. PSID
  24. GetAceSid(PACE_HEADER pAce)
  25. {
  26. switch (pAce->AceType)
  27. {
  28. case ACCESS_ALLOWED_ACE_TYPE:
  29. case ACCESS_DENIED_ACE_TYPE:
  30. case SYSTEM_AUDIT_ACE_TYPE:
  31. case SYSTEM_ALARM_ACE_TYPE:
  32. return (PSID)&((PKNOWN_ACE)pAce)->SidStart;
  33. case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
  34. return (PSID)&((PKNOWN_COMPOUND_ACE)pAce)->SidStart;
  35. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  36. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  37. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  38. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  39. return RtlObjectAceSid(pAce);
  40. }
  41. return NULL;
  42. }
  43. /*******************************************************************
  44. NAME: LocalAllocSid
  45. SYNOPSIS: Copies a SID
  46. ENTRY: pOriginal - pointer to SID to copy
  47. EXIT:
  48. RETURNS: Pointer to SID if successful, NULL otherwise
  49. NOTES: Caller must free the returned SID with LocalFree
  50. HISTORY:
  51. JeffreyS 12-Apr-1999 Created
  52. ********************************************************************/
  53. PSID
  54. LocalAllocSid(PSID pOriginal)
  55. {
  56. PSID pCopy = NULL;
  57. if (pOriginal && IsValidSid(pOriginal))
  58. {
  59. DWORD dwLength = GetLengthSid(pOriginal);
  60. pCopy = (PSID)LocalAlloc(LMEM_FIXED, dwLength);
  61. if (NULL != pCopy)
  62. CopyMemory(pCopy, pOriginal, dwLength);
  63. }
  64. return pCopy;
  65. }
  66. /*******************************************************************
  67. NAME: DestroyDPA
  68. SYNOPSIS: LocalFree's all pointers in a Dynamic Pointer
  69. Array and then frees the DPA.
  70. ENTRY: hList - handle of list to destroy
  71. EXIT:
  72. RETURNS: nothing
  73. NOTES:
  74. HISTORY:
  75. JeffreyS 08-Oct-1996 Created
  76. ********************************************************************/
  77. int CALLBACK
  78. _LocalFreeCB(LPVOID pVoid, LPVOID /*pData*/)
  79. {
  80. if (pVoid)
  81. LocalFree(pVoid);
  82. return 1;
  83. }
  84. void
  85. DestroyDPA(HDPA hList)
  86. {
  87. if (hList != NULL)
  88. DPA_DestroyCallback(hList, _LocalFreeCB, 0);
  89. }
  90. /*******************************************************************
  91. NAME: GetLSAConnection
  92. SYNOPSIS: Wrapper for LsaOpenPolicy
  93. ENTRY: pszServer - the server on which to make the connection
  94. EXIT:
  95. RETURNS: LSA_HANDLE if successful, NULL otherwise
  96. NOTES:
  97. HISTORY:
  98. JeffreyS 08-Oct-1996 Created
  99. ********************************************************************/
  100. LSA_HANDLE
  101. GetLSAConnection(LPCTSTR pszServer, DWORD dwAccessDesired)
  102. {
  103. LSA_HANDLE hPolicy = NULL;
  104. LSA_UNICODE_STRING uszServer = {0};
  105. LSA_UNICODE_STRING *puszServer = NULL;
  106. LSA_OBJECT_ATTRIBUTES oa;
  107. SECURITY_QUALITY_OF_SERVICE sqos;
  108. sqos.Length = SIZEOF(sqos);
  109. sqos.ImpersonationLevel = SecurityImpersonation;
  110. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  111. sqos.EffectiveOnly = FALSE;
  112. InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);
  113. oa.SecurityQualityOfService = &sqos;
  114. if (pszServer &&
  115. *pszServer &&
  116. RtlCreateUnicodeString(&uszServer, pszServer))
  117. {
  118. puszServer = &uszServer;
  119. }
  120. LsaOpenPolicy(puszServer, &oa, dwAccessDesired, &hPolicy);
  121. if (puszServer)
  122. RtlFreeUnicodeString(puszServer);
  123. return hPolicy;
  124. }
  125. /*******************************************************************
  126. NAME: LookupSid
  127. SYNOPSIS: Gets the qualified account name for a given SID
  128. ENTRY: pszServer - the server on which to do the lookup
  129. pSid - the SID to lookup
  130. EXIT: *ppszName contains the account name. This buffer
  131. must be freed by the caller with LocalFree.
  132. *pSidType contains the SID type. pSidType is optional.
  133. RETURNS: TRUE if successful, FALSE otherwise
  134. NOTES:
  135. HISTORY:
  136. JeffreyS 08-Oct-1996 Created
  137. JeffreyS 16-Jan-1998 Converted to HDPA (multiple lookup)
  138. ********************************************************************/
  139. BOOL
  140. LookupSids(HDPA hSids, LPCTSTR pszServer, LPSECURITYINFO2 psi2, PUSER_LIST *ppUserList)
  141. {
  142. PSIDCACHE pSidCache;
  143. if (NULL == hSids)
  144. return FALSE;
  145. if (ppUserList != NULL)
  146. *ppUserList = NULL;
  147. pSidCache = GetSidCache();
  148. if (NULL != pSidCache)
  149. {
  150. BOOL bRet = pSidCache->LookupSids(hSids, pszServer, psi2, ppUserList);
  151. pSidCache->Release();
  152. return bRet;
  153. }
  154. return FALSE;
  155. }
  156. BOOL
  157. LookupSid(PSID pSid, LPCTSTR pszServer, LPSECURITYINFO2 psi2, PUSER_LIST *ppUserList)
  158. {
  159. BOOL fResult;
  160. HDPA hSids = NULL;
  161. if (NULL == pSid)
  162. return FALSE;
  163. hSids = DPA_Create(1);
  164. if (NULL == hSids)
  165. return FALSE;
  166. DPA_AppendPtr(hSids, pSid);
  167. fResult = LookupSids(hSids, pszServer, psi2, ppUserList);
  168. if (NULL != hSids)
  169. DPA_Destroy(hSids);
  170. return fResult;
  171. }
  172. // Private data structure used by LookupSidsAsync to pass
  173. // data needed by the thread
  174. typedef struct _LOOKUPSIDSDATA
  175. {
  176. HDPA hSids;
  177. LPTSTR pszServer;
  178. HWND hWndNotify;
  179. UINT uMsgNotify;
  180. } LOOKUPSIDSDATA, *PLOOKUPSIDSDATA;
  181. DWORD WINAPI
  182. _LookupSidsAsyncProc(LPVOID pv)
  183. {
  184. PLOOKUPSIDSDATA pdata = (PLOOKUPSIDSDATA)pv;
  185. if (pdata)
  186. {
  187. PSIDCACHE pSidCache = GetSidCache();
  188. if (NULL != pSidCache)
  189. {
  190. pSidCache->LookupSidsAsync(pdata->hSids,
  191. pdata->pszServer,
  192. NULL,
  193. pdata->hWndNotify,
  194. pdata->uMsgNotify);
  195. pSidCache->Release();
  196. }
  197. PostMessage(pdata->hWndNotify, pdata->uMsgNotify, 0, 0);
  198. DestroyDPA(pdata->hSids);
  199. LocalFreeString(&pdata->pszServer);
  200. LocalFree(pdata);
  201. }
  202. FreeLibraryAndExitThread(GetModuleHandle(c_szDllName), 0);
  203. return 0;
  204. }
  205. BOOL
  206. LookupSidsAsync(HDPA hSids,
  207. LPCTSTR pszServer,
  208. LPSECURITYINFO2 psi2,
  209. HWND hWndNotify,
  210. UINT uMsgNotify,
  211. PHANDLE phThread)
  212. {
  213. PLOOKUPSIDSDATA pdata;
  214. if (phThread)
  215. *phThread = NULL;
  216. if (NULL == hSids)
  217. return FALSE;
  218. if (psi2)
  219. {
  220. // Should marshal psi2 into a stream and do this on the
  221. // other thread. Well No one has implemented psi2 so its fine.
  222. BOOL bResult = LookupSids(hSids, pszServer, psi2, NULL);
  223. PostMessage(hWndNotify, uMsgNotify, 0, 0);
  224. return bResult;
  225. }
  226. //
  227. // Copy all of the data so the thread can be abandoned if necessary
  228. //
  229. pdata = (PLOOKUPSIDSDATA)LocalAlloc(LPTR, SIZEOF(LOOKUPSIDSDATA));
  230. if (pdata)
  231. {
  232. int cSids;
  233. int i;
  234. HINSTANCE hInstThisDll;
  235. DWORD dwThreadId;
  236. HANDLE hThread;
  237. cSids = DPA_GetPtrCount(hSids);
  238. pdata->hSids = DPA_Create(cSids);
  239. if (!pdata->hSids)
  240. {
  241. LocalFree(pdata);
  242. return FALSE;
  243. }
  244. for (i = 0; i < cSids; i++)
  245. {
  246. PSID p2 = LocalAllocSid((PSID)DPA_FastGetPtr(hSids, i));
  247. if (p2)
  248. {
  249. DPA_AppendPtr(pdata->hSids, p2);
  250. }
  251. }
  252. if (pszServer)
  253. LocalAllocString(&pdata->pszServer, pszServer);
  254. pdata->hWndNotify = hWndNotify;
  255. pdata->uMsgNotify = uMsgNotify;
  256. // Give the thread we are about to create a ref to the dll,
  257. // so that the dll will remain for the lifetime of the thread
  258. hInstThisDll = LoadLibrary(c_szDllName);
  259. hThread = CreateThread(NULL,
  260. 0,
  261. _LookupSidsAsyncProc,
  262. pdata,
  263. NULL,
  264. &dwThreadId);
  265. if (hThread != NULL)
  266. {
  267. if (phThread)
  268. *phThread = hThread;
  269. else
  270. CloseHandle(hThread);
  271. return TRUE;
  272. }
  273. else
  274. {
  275. // Thread creation has failed; clean up
  276. DestroyDPA(pdata->hSids);
  277. LocalFreeString(&pdata->pszServer);
  278. LocalFree(pdata);
  279. FreeLibrary(hInstThisDll);
  280. }
  281. }
  282. return FALSE;
  283. }
  284. BOOL
  285. BuildUserDisplayName(LPTSTR *ppszDisplayName,
  286. LPCTSTR pszName,
  287. LPCTSTR pszLogonName)
  288. {
  289. TCHAR szDisplayName[MAX_PATH];
  290. if (NULL == ppszDisplayName || NULL == pszName)
  291. return FALSE;
  292. *ppszDisplayName = NULL;
  293. if (NULL != pszLogonName && *pszLogonName)
  294. {
  295. return (BOOL)FormatStringID(ppszDisplayName,
  296. ::hModule,
  297. IDS_FMT_USER_DISPLAY,
  298. pszName,
  299. pszLogonName);
  300. }
  301. return SUCCEEDED(LocalAllocString(ppszDisplayName, pszName));
  302. }
  303. /*******************************************************************
  304. NAME: LoadImageList
  305. SYNOPSIS: Creates an image list from a bitmap resource
  306. ENTRY: hInstance - the bitmap lives here
  307. pszBitmapID - resource ID of the bitmap
  308. EXIT:
  309. RETURNS: HIMAGELIST if successful, NULL otherwise
  310. NOTES:
  311. In order to calculate the number of images, it is assumed
  312. that the width and height of a single image are the same.
  313. HISTORY:
  314. JeffreyS 08-Oct-1996 Created
  315. ********************************************************************/
  316. HIMAGELIST
  317. LoadImageList(HINSTANCE hInstance, LPCTSTR pszBitmapID)
  318. {
  319. HIMAGELIST himl = NULL;
  320. HBITMAP hbm = LoadBitmap(hInstance, pszBitmapID);
  321. if (hbm != NULL)
  322. {
  323. BITMAP bm;
  324. GetObject(hbm, SIZEOF(bm), &bm);
  325. himl = ImageList_Create(bm.bmHeight, // height == width
  326. bm.bmHeight,
  327. ILC_COLOR | ILC_MASK,
  328. bm.bmWidth / bm.bmHeight,
  329. 0); // don't need to grow
  330. if (himl != NULL)
  331. ImageList_AddMasked(himl, hbm, CLR_DEFAULT);
  332. DeleteObject(hbm);
  333. }
  334. return himl;
  335. }
  336. /*******************************************************************
  337. NAME: GetSidImageIndex
  338. SYNOPSIS: Gets the image index for the given SID type
  339. ENTRY: sidType - type of SID
  340. sidSys - well-known group type
  341. fRemoteUser - TRUE if SID is a user on a remote system
  342. EXIT:
  343. RETURNS: index into image list
  344. NOTES:
  345. HISTORY:
  346. JeffreyS 08-Oct-1996 Created
  347. ********************************************************************/
  348. SID_IMAGE_INDEX
  349. GetSidImageIndex(PSID psid,
  350. SID_NAME_USE sidType)
  351. {
  352. SID_IMAGE_INDEX idBitmap;
  353. switch (sidType)
  354. {
  355. case SidTypeUser:
  356. idBitmap = SID_IMAGE_USER;
  357. break;
  358. case SidTypeAlias:
  359. case SidTypeGroup:
  360. case SidTypeWellKnownGroup:
  361. idBitmap = SID_IMAGE_GROUP;
  362. break;
  363. #if(_WIN32_WINNT >= 0x0500)
  364. case SidTypeComputer:
  365. idBitmap = SID_IMAGE_COMPUTER;
  366. break;
  367. #endif
  368. default:
  369. idBitmap = SID_IMAGE_UNKNOWN;
  370. break;
  371. }
  372. return idBitmap;
  373. }
  374. #if(_WIN32_WINNT >= 0x0500)
  375. #include <dsrole.h>
  376. BOOL IsStandalone(LPCTSTR pszMachine, PBOOL pbIsDC)
  377. {
  378. BOOL bStandalone = TRUE;
  379. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  380. //
  381. // Find out if target machine is a standalone machine or joined to
  382. // an NT domain.
  383. //
  384. __try
  385. {
  386. if (pbIsDC)
  387. *pbIsDC = FALSE;
  388. DsRoleGetPrimaryDomainInformation(pszMachine,
  389. DsRolePrimaryDomainInfoBasic,
  390. (PBYTE*)&pDsRole);
  391. }
  392. __finally
  393. {
  394. }
  395. if (NULL != pDsRole)
  396. {
  397. if (pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation ||
  398. pDsRole->MachineRole == DsRole_RoleStandaloneServer)
  399. {
  400. bStandalone = TRUE;
  401. }
  402. else
  403. bStandalone = FALSE;
  404. if (pbIsDC)
  405. {
  406. if (pDsRole->MachineRole == DsRole_RolePrimaryDomainController ||
  407. pDsRole->MachineRole == DsRole_RoleBackupDomainController)
  408. {
  409. *pbIsDC = TRUE;
  410. }
  411. }
  412. DsRoleFreeMemory(pDsRole);
  413. }
  414. return bStandalone;
  415. }
  416. #else // _WIN32_WINNT < 0x0500
  417. BOOL IsStandalone(LPCTSTR pszMachine, PBOOL pbIsDC)
  418. {
  419. BOOL bStandalone = FALSE;
  420. //implement an NT4 version of this? There is no request for this
  421. //so no need.
  422. if (pbIsDC)
  423. *pbIsDC = FALSE;
  424. return bStandalone;
  425. }
  426. //
  427. // Stuff used by GetUserGroup below
  428. //
  429. #include <getuser.h>
  430. const TCHAR c_szGetUserLib[] = TEXT("netui2.dll");
  431. const char c_szOpenUB[] = "OpenUserBrowser";
  432. const char c_szEnumUBSelection[] = "EnumUserBrowserSelection";
  433. const char c_szCloseUB[] = "CloseUserBrowser";
  434. typedef HUSERBROW (WINAPI *PFN_UB_OPEN)(LPUSERBROWSER);
  435. typedef BOOL (WINAPI *PFN_UB_ENUM)(HUSERBROW, LPUSERDETAILS, LPDWORD);
  436. typedef BOOL (WINAPI *PFN_UB_CLOSE)(HUSERBROW);
  437. PFN_UB_OPEN pfnUBOpen;
  438. PFN_UB_ENUM pfnUBEnum;
  439. PFN_UB_CLOSE pfnUBClose;
  440. #ifndef HC_SED_USER_BROWSER_DIALOG
  441. #define HC_SED_USER_BROWSER_DIALOG 4300
  442. #define HC_SED_USER_BROWSER_AUDIT_DLG 4325
  443. #endif
  444. /*******************************************************************
  445. NAME: GetUserGroup
  446. SYNOPSIS: Invokes the old NT4 user/group picker dialog
  447. ENTRY: hwndOwner - owner window
  448. dwFlags - indicate multi-select, etc.
  449. pszServer - initial focus of dialog
  450. ppUserList - out parameter
  451. EXIT: *ppUserList contains a list of USER_INFO structures
  452. RETURNS: HRESULT
  453. NOTES: *ppUserList must be LocalFree'd by the caller.
  454. HISTORY:
  455. JeffreyS 16-Jan-1998 Created
  456. ********************************************************************/
  457. HRESULT
  458. GetUserGroup(HWND hwndOwner,
  459. DWORD dwFlags,
  460. LPCTSTR pszServer,
  461. BOOL /*bStandalone*/,
  462. PUSER_LIST *ppUserList)
  463. {
  464. HRESULT hr = S_OK;
  465. HUSERBROW hUserBrowser = NULL;
  466. USERBROWSER ub;
  467. DWORD dwUDLength = 1024;
  468. PUSERDETAILS pUserDetails = NULL;
  469. PSID_CACHE_ENTRY pEntry;
  470. HDPA hEntryList = NULL;
  471. PSIDCACHE pSidCache = NULL;
  472. TraceEnter(TRACE_MISC, "GetUserGroup");
  473. TraceAssert(ppUserList != NULL);
  474. if (!ppUserList)
  475. TraceLeaveResult(E_INVALIDARG);
  476. *ppUserList = NULL;
  477. if (!g_hGetUserLib)
  478. {
  479. g_hGetUserLib = LoadLibrary(c_szGetUserLib);
  480. if (g_hGetUserLib == NULL)
  481. ExitGracefully(hr, E_FAIL, "Unable to load netui2.dll");
  482. pfnUBOpen = (PFN_UB_OPEN)GetProcAddress(g_hGetUserLib, c_szOpenUB);
  483. pfnUBEnum = (PFN_UB_ENUM)GetProcAddress(g_hGetUserLib, c_szEnumUBSelection);
  484. pfnUBClose = (PFN_UB_CLOSE)GetProcAddress(g_hGetUserLib, c_szCloseUB);
  485. if (!pfnUBOpen || !pfnUBEnum || !pfnUBClose)
  486. {
  487. FreeLibrary(g_hGetUserLib);
  488. g_hGetUserLib = NULL;
  489. ExitGracefully(hr, E_FAIL, "Unable to link to netui2.dll");
  490. }
  491. }
  492. //
  493. // Create the global sid cache object, if necessary
  494. //
  495. pSidCache = GetSidCache();
  496. if (pSidCache == NULL)
  497. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create SID cache");
  498. ub.ulStructSize = sizeof(ub);
  499. ub.fUserCancelled = FALSE;
  500. ub.fExpandNames = TRUE;
  501. ub.hwndOwner = hwndOwner;
  502. ub.pszTitle = NULL;
  503. ub.pszInitialDomain = (LPTSTR)pszServer;
  504. ub.Flags = USRBROWS_SHOW_ALL | USRBROWS_INCL_ALL;
  505. ub.ulHelpContext = HC_SED_USER_BROWSER_DIALOG;
  506. ub.pszHelpFileName = (LPWSTR)c_szAcluiHelpFile;
  507. #ifdef USRBROWS_INCL_RESTRICTED
  508. ub.Flags &= ~USRBROWS_INCL_RESTRICTED; // NT5 only
  509. #endif
  510. if (!(dwFlags & GU_CONTAINER))
  511. ub.Flags &= ~USRBROWS_INCL_CREATOR;
  512. if (!(dwFlags & GU_MULTI_SELECT))
  513. ub.Flags |= USRBROWS_SINGLE_SELECT;
  514. if (dwFlags & GU_AUDIT_HLP)
  515. ub.ulHelpContext = HC_SED_USER_BROWSER_AUDIT_DLG;
  516. //
  517. // Open the dialog
  518. //
  519. hUserBrowser = (*pfnUBOpen)(&ub);
  520. if (hUserBrowser == NULL)
  521. ExitGracefully(hr, E_FAIL, "OpenUserBrowser returned false");
  522. pUserDetails = (PUSERDETAILS)LocalAlloc(LPTR, dwUDLength);
  523. if (!pUserDetails)
  524. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to allocate UserDetails buffer");
  525. hEntryList = DPA_Create(4);
  526. if (!hEntryList)
  527. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create SID cache entry list");
  528. //
  529. // Enumerate the results
  530. //
  531. for (;;)
  532. {
  533. if (!(*pfnUBEnum)(hUserBrowser, pUserDetails, &dwUDLength))
  534. {
  535. if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
  536. {
  537. // The details buffer wasn't big enough, reallocate it
  538. LocalFree(pUserDetails);
  539. pUserDetails = (PUSERDETAILS)LocalAlloc(LPTR, dwUDLength);
  540. if (pUserDetails == NULL)
  541. break;
  542. if (!(*pfnUBEnum)(hUserBrowser, pUserDetails, &dwUDLength))
  543. break;
  544. }
  545. else // probably ERROR_NO_MORE_ITEMS
  546. break;
  547. }
  548. //
  549. // See if it's already in the cache
  550. //
  551. pEntry = pSidCache->FindSid(pUserDetails->psidUser);
  552. if (NULL == pEntry)
  553. {
  554. //
  555. // Not in the cache, add it
  556. //
  557. TCHAR szAccountName[MAX_PATH];
  558. TCHAR szDomainName[MAX_PATH];
  559. ULONG nAccountLength;
  560. lstrcpy(szAccountName, pUserDetails->pszAccountName);
  561. lstrcpy(szDomainName, pUserDetails->pszDomainName);
  562. switch (pUserDetails->UserType)
  563. {
  564. case SidTypeUnknown:
  565. case SidTypeInvalid:
  566. // Load unknown account string
  567. LoadString(::hModule, IDS_SID_UNKNOWN, szAccountName, ARRAYSIZE(szAccountName));
  568. break;
  569. case SidTypeAlias:
  570. //if (IsAliasSid(pSid))
  571. // szDomainName[0] = TEXT('\0'); // The domain is "BUILTIN"
  572. break;
  573. case SidTypeDeletedAccount:
  574. // Load deleted account string
  575. LoadString(::hModule, IDS_SID_DELETED, szAccountName, ARRAYSIZE(szAccountName));
  576. break;
  577. case SidTypeWellKnownGroup:
  578. // Don't include the domain for a well-known group
  579. szDomainName[0] = TEXT('\0');
  580. break;
  581. }
  582. //
  583. // Build NT4 "domain\user" style name (logon name)
  584. //
  585. if (szDomainName[0] != TEXT('\0'))
  586. {
  587. lstrcat(szDomainName, TEXT("\\"));
  588. lstrcat(szDomainName, szAccountName);
  589. }
  590. LPCTSTR pszCommonName = pUserDetails->pszFullName;
  591. if (!pszCommonName || !*pszCommonName)
  592. pszCommonName = pUserDetails->pszAccountName;
  593. pEntry = pSidCache->MakeEntry(pUserDetails->psidUser,
  594. pUserDetails->UserType,
  595. pszCommonName,
  596. szDomainName);
  597. if (NULL != pEntry)
  598. pSidCache->AddEntry(pEntry);
  599. }
  600. if (NULL != pEntry)
  601. DPA_AppendPtr(hEntryList, pEntry);
  602. }
  603. //
  604. // Build return list
  605. //
  606. if (DPA_GetPtrCount(hEntryList))
  607. pSidCache->BuildUserList(hEntryList, pszServer, ppUserList);
  608. if (NULL == *ppUserList)
  609. hr = E_FAIL;
  610. exit_gracefully:
  611. if (pSidCache)
  612. pSidCache->Release();
  613. if (NULL != hUserBrowser)
  614. (*pfnUBClose)(hUserBrowser);
  615. if (pUserDetails != NULL)
  616. LocalFree(pUserDetails);
  617. DPA_Destroy(hEntryList);
  618. TraceLeaveResult(hr);
  619. }
  620. #endif // _WIN32_WINNT < 0x0500
  621. /*******************************************************************
  622. NAME: IsDACLCanonical
  623. SYNOPSIS: Checks a DACL for canonical ordering
  624. ENTRY: pDacl - points to DACL to check
  625. EXIT:
  626. RETURNS: Nonzero if DACL is in canonical order, zero otherwise
  627. NOTES:
  628. HISTORY:
  629. JeffreyS 08-Oct-1996 Created
  630. JeffreyS 03-Oct-1997 Make object aces same as non-object aces
  631. ********************************************************************/
  632. enum ACELEVEL
  633. {
  634. alNonInheritAccessDenied,
  635. alNonInheritAccessAllowed,
  636. alInheritedAces,
  637. };
  638. BOOL
  639. IsDACLCanonical(PACL pDacl)
  640. {
  641. PACE_HEADER pAce;
  642. ACELEVEL currentAceLevel;
  643. DWORD dwAceCount;
  644. if (pDacl == NULL)
  645. return TRUE;
  646. currentAceLevel = alNonInheritAccessDenied;
  647. dwAceCount = pDacl->AceCount;
  648. if (dwAceCount == 0)
  649. return TRUE;
  650. for (pAce = (PACE_HEADER)FirstAce(pDacl);
  651. dwAceCount > 0;
  652. --dwAceCount, pAce = (PACE_HEADER)NextAce(pAce))
  653. {
  654. ACELEVEL aceLevel;
  655. //
  656. // NOTE: We do not skip INHERIT_ONLY aces because we want them in
  657. // canonical order too.
  658. //
  659. if (pAce->AceFlags & INHERITED_ACE)
  660. {
  661. aceLevel = alInheritedAces; // don't check order here
  662. }
  663. else
  664. {
  665. switch(pAce->AceType)
  666. {
  667. case ACCESS_DENIED_ACE_TYPE:
  668. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  669. aceLevel = alNonInheritAccessDenied;
  670. break;
  671. case ACCESS_ALLOWED_ACE_TYPE:
  672. case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
  673. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  674. aceLevel = alNonInheritAccessAllowed;
  675. break;
  676. default:
  677. return FALSE;
  678. }
  679. }
  680. //
  681. // If the ace type is less than the level we are currently at,
  682. // then it is not canonical.
  683. //
  684. if (aceLevel < currentAceLevel)
  685. return FALSE;
  686. //
  687. // Update the current ace level.
  688. //
  689. currentAceLevel = aceLevel;
  690. }
  691. //
  692. // If we get here, then the DACL is in canonical order.
  693. //
  694. return TRUE;
  695. }
  696. /*******************************************************************
  697. NAME: IsDenyACL
  698. SYNOPSIS: Checks a DACL for Deny ACEs. Also looks for "Deny
  699. All" ACEs.
  700. ENTRY: pDacl - points to DACL to check
  701. EXIT: *pdwWarning is 0, IDS_PERM_DENY, or IDS_PERM_DENY_ALL
  702. RETURNS: Nonzero if DACL contains any Deny ACEs, zero otherwise
  703. NOTES:
  704. HISTORY:
  705. JeffreyS 05-Sep-1997 Created
  706. ********************************************************************/
  707. BOOL
  708. IsDenyACL(PACL pDacl,
  709. BOOL fProtected,
  710. DWORD dwFullControlMask,
  711. LPDWORD pdwWarning)
  712. {
  713. DWORD dwWarning = 0;
  714. TraceEnter(TRACE_MISC, "IsDenyACL");
  715. // NULL DACL implies "Allow Everyone Full Control"
  716. if (pDacl == NULL)
  717. goto exit_gracefully;
  718. // Check for empty DACL (no access to anyone)
  719. if (pDacl->AceCount == 0)
  720. {
  721. if (fProtected)
  722. dwWarning = IDS_PERM_DENY_ALL;
  723. // else the object will inherit permissions from the parent.
  724. }
  725. else
  726. {
  727. PACE_HEADER pAce;
  728. int iEntry;
  729. // Iterate through the ACL looking for "Deny All"
  730. for (iEntry = 0, pAce = (PACE_HEADER)FirstAce(pDacl);
  731. iEntry < pDacl->AceCount;
  732. iEntry++, pAce = (PACE_HEADER)NextAce(pAce))
  733. {
  734. if (pAce->AceType != ACCESS_DENIED_ACE_TYPE &&
  735. pAce->AceType != ACCESS_DENIED_OBJECT_ACE_TYPE)
  736. {
  737. // Assuming the ACL is in canonical order, we can
  738. // stop as soon as we find something that isn't
  739. // a Deny ACE. (Deny ACEs come first)
  740. break;
  741. }
  742. // Found a Deny ACE
  743. dwWarning = IDS_PERM_DENY;
  744. // Check for "Deny Everyone Full Control". Don't look
  745. // for ACCESS_DENIED_OBJECT_ACE_TYPE here since Object
  746. // aces don't have as wide an effect as normal aces.
  747. if (pAce->AceType == ACCESS_DENIED_ACE_TYPE &&
  748. ((PKNOWN_ACE)pAce)->Mask == dwFullControlMask &&
  749. EqualSid(GetAceSid(pAce), QuerySystemSid(UI_SID_World)))
  750. {
  751. // Found "Deny All"
  752. dwWarning = IDS_PERM_DENY_ALL;
  753. break;
  754. }
  755. }
  756. }
  757. exit_gracefully:
  758. if (pdwWarning != NULL)
  759. *pdwWarning = dwWarning;
  760. TraceLeaveValue(dwWarning != 0);
  761. }
  762. /*******************************************************************
  763. NAME: QuerySystemSid
  764. SYNOPSIS: Retrieves the requested SID
  765. ENTRY: SystemSidType - Which SID to retrieve
  766. EXIT:
  767. RETURNS: PSID if successful, NULL otherwise
  768. HISTORY:
  769. JeffreyS 08-Oct-1996 Created
  770. ********************************************************************/
  771. //
  772. // Global array of static system SIDs, corresponding to UI_SystemSid
  773. //
  774. const struct
  775. {
  776. SID sid; // contains 1 subauthority
  777. DWORD dwSubAuth[1]; // we currently need at most 2 subauthorities
  778. } g_StaticSids[COUNT_SYSTEM_SID_TYPES] =
  779. {
  780. {{SID_REVISION,1,SECURITY_WORLD_SID_AUTHORITY, {SECURITY_WORLD_RID}}, {0} },
  781. {{SID_REVISION,1,SECURITY_CREATOR_SID_AUTHORITY,{SECURITY_CREATOR_OWNER_RID}}, {0} },
  782. {{SID_REVISION,1,SECURITY_CREATOR_SID_AUTHORITY,{SECURITY_CREATOR_GROUP_RID}}, {0} },
  783. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_DIALUP_RID}}, {0} },
  784. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_NETWORK_RID}}, {0} },
  785. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_BATCH_RID}}, {0} },
  786. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_INTERACTIVE_RID}}, {0} },
  787. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_SERVICE_RID}}, {0} },
  788. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_ANONYMOUS_LOGON_RID}}, {0} },
  789. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_PROXY_RID}}, {0} },
  790. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_ENTERPRISE_CONTROLLERS_RID}},{0} },
  791. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_PRINCIPAL_SELF_RID}}, {0} },
  792. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_AUTHENTICATED_USER_RID}}, {0} },
  793. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_RESTRICTED_CODE_RID}}, {0} },
  794. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_TERMINAL_SERVER_RID}}, {0} },
  795. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_LOCAL_SYSTEM_RID}}, {0} },
  796. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ADMINS} },
  797. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_USERS} },
  798. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_GUESTS} },
  799. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_POWER_USERS} },
  800. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ACCOUNT_OPS} },
  801. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_SYSTEM_OPS} },
  802. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_PRINT_OPS} },
  803. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_BACKUP_OPS} },
  804. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_REPLICATOR} },
  805. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_RAS_SERVERS} },
  806. };
  807. PSID
  808. QuerySystemSid(UI_SystemSid SystemSidType)
  809. {
  810. if (SystemSidType == UI_SID_Invalid || SystemSidType >= UI_SID_Count)
  811. return NULL;
  812. return (PSID)&g_StaticSids[SystemSidType];
  813. }
  814. //
  815. // Global array of cached token SIDs
  816. //
  817. struct
  818. {
  819. SID sid; // SID contains 1 subauthority
  820. DWORD dwSubAuth[SID_MAX_SUB_AUTHORITIES - 1];
  821. } g_TokenSids[COUNT_TOKEN_SID_TYPES] = {0};
  822. PSID
  823. QueryTokenSid(UI_TokenSid TokenSidType)
  824. {
  825. if (TokenSidType == UI_TSID_Invalid || TokenSidType >= UI_TSID_Count)
  826. return NULL;
  827. if (0 == *GetSidSubAuthorityCount((PSID)&g_TokenSids[TokenSidType]))
  828. {
  829. HANDLE hProcessToken;
  830. // Get the current process's user's SID
  831. if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
  832. {
  833. BYTE buffer[sizeof(TOKEN_USER) + sizeof(g_TokenSids[0])];
  834. ULONG cbBuffer = sizeof(buffer);
  835. switch (TokenSidType)
  836. {
  837. case UI_TSID_CurrentProcessUser:
  838. if (GetTokenInformation(hProcessToken,
  839. TokenUser,
  840. buffer,
  841. cbBuffer,
  842. &cbBuffer))
  843. {
  844. PTOKEN_USER ptu = (PTOKEN_USER)buffer;
  845. CopyMemory(&g_TokenSids[UI_TSID_CurrentProcessUser],
  846. ptu->User.Sid,
  847. GetLengthSid(ptu->User.Sid));
  848. }
  849. break;
  850. case UI_TSID_CurrentProcessOwner:
  851. if (GetTokenInformation(hProcessToken,
  852. TokenOwner,
  853. buffer,
  854. cbBuffer,
  855. &cbBuffer))
  856. {
  857. PTOKEN_OWNER pto = (PTOKEN_OWNER)buffer;
  858. CopyMemory(&g_TokenSids[UI_TSID_CurrentProcessOwner],
  859. pto->Owner,
  860. GetLengthSid(pto->Owner));
  861. }
  862. break;
  863. case UI_TSID_CurrentProcessPrimaryGroup:
  864. if (GetTokenInformation(hProcessToken,
  865. TokenPrimaryGroup,
  866. buffer,
  867. cbBuffer,
  868. &cbBuffer))
  869. {
  870. PTOKEN_PRIMARY_GROUP ptg = (PTOKEN_PRIMARY_GROUP)buffer;
  871. CopyMemory(&g_TokenSids[UI_TSID_CurrentProcessPrimaryGroup],
  872. ptg->PrimaryGroup,
  873. GetLengthSid(ptg->PrimaryGroup));
  874. }
  875. break;
  876. }
  877. CloseHandle(hProcessToken);
  878. }
  879. if (0 == *GetSidSubAuthorityCount((PSID)&g_TokenSids[TokenSidType]))
  880. return NULL;
  881. }
  882. return (PSID)&g_TokenSids[TokenSidType];
  883. }
  884. /*******************************************************************
  885. NAME: GetAuthenticationID
  886. SYNOPSIS: Retrieves the SID associated with the credentials
  887. currently being used for network access.
  888. (runas /netonly credentials)
  889. ENTRY: pszServer = server on which to lookup the account.
  890. NULL indicates local system.
  891. EXIT:
  892. RETURNS: PSID if successful, NULL otherwise. Caller must
  893. free with LocalFree.
  894. HISTORY:
  895. JeffreyS 05-Aug-1999 Created
  896. ********************************************************************/
  897. PSID
  898. GetAuthenticationID(LPCWSTR pszServer)
  899. {
  900. PSID pSid = NULL;
  901. HANDLE hLsa;
  902. NTSTATUS Status;
  903. //
  904. // These LSA calls are delay-loaded from secur32.dll using the linker's
  905. // delay-load mechanism. Therefore, wrap with an exception handler.
  906. //
  907. __try
  908. {
  909. Status = LsaConnectUntrusted(&hLsa);
  910. if (Status == 0)
  911. {
  912. NEGOTIATE_CALLER_NAME_REQUEST Req = {0};
  913. PNEGOTIATE_CALLER_NAME_RESPONSE pResp;
  914. ULONG cbSize;
  915. NTSTATUS SubStatus;
  916. Req.MessageType = NegGetCallerName;
  917. Status = LsaCallAuthenticationPackage(
  918. hLsa,
  919. 0,
  920. &Req,
  921. sizeof(Req),
  922. (void**)&pResp,
  923. &cbSize,
  924. &SubStatus);
  925. if ((Status == 0) && (SubStatus == 0))
  926. {
  927. BYTE sid[sizeof(SID) + (SID_MAX_SUB_AUTHORITIES - 1)*sizeof(DWORD)];
  928. PSID psid = (PSID)sid;
  929. DWORD cbSid = sizeof(sid);
  930. WCHAR szDomain[MAX_PATH];
  931. DWORD cchDomain = ARRAYSIZE(szDomain);
  932. SID_NAME_USE sidType;
  933. if (LookupAccountNameW(pszServer,
  934. pResp->CallerName,
  935. psid,
  936. &cbSid,
  937. szDomain,
  938. &cchDomain,
  939. &sidType))
  940. {
  941. pSid = LocalAllocSid(psid);
  942. }
  943. LsaFreeReturnBuffer(pResp);
  944. }
  945. LsaDeregisterLogonProcess(hLsa);
  946. }
  947. }
  948. __except(EXCEPTION_EXECUTE_HANDLER)
  949. {
  950. }
  951. return pSid;
  952. }
  953. /*******************************************************************
  954. NAME: CopyUnicodeString
  955. SYNOPSIS: Allocates a buffer and copies a string from
  956. a UNICODE_STRING sources.
  957. ENTRY: pszDest - pointer to destination buffer
  958. cchDest - # of chars in pszDest (bytes for MBCS)
  959. pSrc - pointer to UNICODE_STRING to copy
  960. EXIT: pszDest - containing copy of string
  961. RETURNS: # of chars copied, or 0 if not successful.
  962. NOTES:
  963. HISTORY:
  964. JeffreyS 22-Jan-1998 Created
  965. ********************************************************************/
  966. int
  967. CopyUnicodeString(LPTSTR pszDest, ULONG cchDest, PLSA_UNICODE_STRING pSrc)
  968. {
  969. int nResult;
  970. ULONG cchSrc;
  971. // If UNICODE, cchDest is size of destination buffer in chars
  972. // Else (MBCS) cchDest is size of destination buffer in bytes
  973. if (pszDest == NULL || 0 == cchDest)
  974. return 0;
  975. *pszDest = TEXT('\0');
  976. if (pSrc == NULL || pSrc->Buffer == NULL)
  977. return 0;
  978. // Get # of chars in source (not including NULL)
  979. cchSrc = pSrc->Length/sizeof(WCHAR);
  980. #ifdef UNICODE
  981. //
  982. // Note that pSrc->Buffer may not be NULL terminated so we can't just
  983. // call lstrcpynW with cchDest. Also, if we call lstrcpynW with cchSrc,
  984. // it copies the correct # of chars, but then overwrites the last char
  985. // with NULL giving an incorrect result. If we call lstrcpynW with
  986. // (cchSrc+1) it reads past the end of the buffer, which may fault (360251)
  987. // causing lstrcpynW's exception handler to return 0 without NULL-
  988. // terminating the resulting string.
  989. //
  990. // So let's just copy the bits.
  991. //
  992. nResult = min(cchSrc, cchDest);
  993. CopyMemory(pszDest, pSrc->Buffer, sizeof(WCHAR)*nResult);
  994. if (nResult == (int)cchDest)
  995. --nResult;
  996. pszDest[nResult] = L'\0';
  997. #else
  998. nResult = WideCharToMultiByte(CP_ACP,
  999. 0,
  1000. pSrc->Buffer,
  1001. cchSrc,
  1002. pszDest,
  1003. cchDest,
  1004. NULL,
  1005. NULL);
  1006. #endif
  1007. return nResult;
  1008. }
  1009. /*******************************************************************
  1010. NAME: CopyUnicodeString
  1011. SYNOPSIS: Allocates a buffer and copies a string from
  1012. a UNICODE_STRING sources.
  1013. ENTRY: pSrc - pointer to UNICODE_STRING to copy
  1014. EXIT: *ppszResult - points to LocalAlloc'd buffer containing copy.
  1015. RETURNS: # of chars copied, or 0 if not successful.
  1016. NOTES:
  1017. HISTORY:
  1018. JeffreyS 22-Jan-1998 Created
  1019. ********************************************************************/
  1020. int
  1021. CopyUnicodeString(LPTSTR *ppszResult, PLSA_UNICODE_STRING pSrc)
  1022. {
  1023. int nResult = 0;
  1024. if (NULL == ppszResult)
  1025. return 0;
  1026. *ppszResult = NULL;
  1027. if (NULL != pSrc)
  1028. {
  1029. ULONG cchResult;
  1030. *ppszResult = NULL;
  1031. // Get # of chars in source (including NULL)
  1032. cchResult = pSrc->Length/SIZEOF(WCHAR) + 1;
  1033. // Allocate buffer big enough for either UNICODE or MBCS result
  1034. *ppszResult = (LPTSTR)LocalAlloc(LPTR, cchResult * 2);
  1035. if (*ppszResult)
  1036. {
  1037. nResult = CopyUnicodeString(*ppszResult, cchResult, pSrc);
  1038. if (0 == nResult)
  1039. {
  1040. LocalFree(*ppszResult);
  1041. *ppszResult = NULL;
  1042. }
  1043. }
  1044. }
  1045. return nResult;
  1046. }
  1047. //
  1048. // Test GUIDs safely
  1049. //
  1050. BOOL IsSameGUID(const GUID *p1, const GUID *p2)
  1051. {
  1052. BOOL bResult = FALSE;
  1053. if (!p1) p1 = &GUID_NULL;
  1054. if (!p2) p2 = &GUID_NULL;
  1055. __try
  1056. {
  1057. bResult = InlineIsEqualGUID(*p1, *p2);
  1058. }
  1059. __except(EXCEPTION_EXECUTE_HANDLER)
  1060. {
  1061. }
  1062. return bResult;
  1063. }
  1064. /*******************************************************************
  1065. NAME: GetCountOfInheritableAces
  1066. SYNOPSIS: Get the count of aces in ACL which can be
  1067. inherited to child objects
  1068. RETURNS: Count of Aces
  1069. ********************************************************************/
  1070. DWORD GetCountOfInheritableAces(PACL pAcl)
  1071. {
  1072. if(!pAcl)
  1073. return 0;
  1074. DWORD dwCount = 0;
  1075. PACE_HEADER pAce = NULL;
  1076. int iEntry = 0;
  1077. for (iEntry = 0, pAce = (PACE_HEADER)FirstAce(pAcl);
  1078. iEntry < pAcl->AceCount;
  1079. iEntry++, pAce = (PACE_HEADER)NextAce(pAce))
  1080. {
  1081. //
  1082. //Consider only explicit aces
  1083. //
  1084. if((!(pAce->AceFlags & INHERITED_ACE))&&(pAce->AceFlags & (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE)))
  1085. dwCount++;
  1086. }
  1087. return dwCount;
  1088. }
  1089. /*******************************************************************
  1090. NAME: GetCountOfInheritableAces
  1091. SYNOPSIS: Get the count of aces in SACL or DACL which can be
  1092. inherited to child objects
  1093. RETURNS: Count of Aces
  1094. ********************************************************************/
  1095. DWORD GetCountOfInheritableAces(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
  1096. {
  1097. if(!pSD)
  1098. return 0;
  1099. PACL pAcl = NULL;
  1100. BOOL bPresent;
  1101. BOOL bDefault;
  1102. if(si & DACL_SECURITY_INFORMATION)
  1103. {
  1104. if(GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefault))
  1105. {
  1106. return GetCountOfInheritableAces(pAcl);
  1107. }
  1108. }
  1109. else if(si & SACL_SECURITY_INFORMATION)
  1110. {
  1111. if(GetSecurityDescriptorSacl(pSD, &bPresent, &pAcl, &bDefault))
  1112. {
  1113. return GetCountOfInheritableAces(pAcl);
  1114. }
  1115. }
  1116. return 0;
  1117. }
  1118. typedef struct AclBloatInfo{
  1119. DWORD dwInheriteAceCount;
  1120. SECURITY_INFORMATION si;
  1121. HFONT hFont;
  1122. BOOL bShowHelp;
  1123. }ACL_BLOAT_INFO;
  1124. INT_PTR CALLBACK
  1125. AclBloatDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1126. {
  1127. switch (uMsg)
  1128. {
  1129. case WM_INITDIALOG:
  1130. {
  1131. ACL_BLOAT_INFO * pInfo= (ACL_BLOAT_INFO*)lParam;
  1132. ASSERT(pInfo);
  1133. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pInfo);
  1134. //
  1135. //Add a warning icon
  1136. //
  1137. // add the warning icon
  1138. HICON hWarn = LoadIcon(NULL, IDI_WARNING);
  1139. SendDlgItemMessage(hDlg, // dialog box window handle
  1140. IDC_BLOAT_WARN_ICON, // icon identifier
  1141. STM_SETIMAGE, // message to send
  1142. (WPARAM) IMAGE_ICON, // image type
  1143. (LPARAM) hWarn); // icon handle
  1144. //
  1145. //Set the title of dialog box
  1146. //
  1147. LPTSTR pszCaption = NULL;
  1148. if(FormatStringID(&pszCaption,
  1149. ::hModule,
  1150. pInfo->si & DACL_SECURITY_INFORMATION ? IDS_PERMISSIONS : IDS_AUDITING))
  1151. {
  1152. SetWindowText(hDlg, pszCaption);
  1153. LocalFreeString(&pszCaption);
  1154. }
  1155. //
  1156. //Set the warning message
  1157. //
  1158. UINT cItem = pInfo->dwInheriteAceCount;
  1159. WCHAR buffer[34];
  1160. _itow(cItem,buffer,10);
  1161. if(FormatStringID(&pszCaption,
  1162. ::hModule,
  1163. pInfo->si & DACL_SECURITY_INFORMATION ? IDS_ACLBLOAT_NO_LIST_LINE1:IDS_ACLBLOAT_NO_LIST_SACL_LINE1,
  1164. buffer))
  1165. {
  1166. SetDlgItemText(hDlg, IDC_ACLBLOAT_LINE1, pszCaption);
  1167. LocalFreeString(&pszCaption);
  1168. }
  1169. //
  1170. //make warning bold
  1171. //
  1172. MakeBold(GetDlgItem(hDlg,IDC_ACLB_WARNING), &(pInfo->hFont));
  1173. //
  1174. //Set the line2, hide the Help button and move other buttons.
  1175. //
  1176. if(!pInfo->bShowHelp)
  1177. {
  1178. if(FormatStringID(&pszCaption,
  1179. ::hModule,
  1180. pInfo->si & DACL_SECURITY_INFORMATION ? IDS_BLOAT_PERM_LINE2_NOHELP : IDS_BLOAT_AUDIT_LINE2_NOHELP))
  1181. {
  1182. SetDlgItemText(hDlg, IDC_ACLB_LINE3, pszCaption);
  1183. LocalFreeString(&pszCaption);
  1184. }
  1185. RECT rcHelp, rcCancel;
  1186. GetWindowRect(GetDlgItem(hDlg, IDHELP), &rcHelp);
  1187. MapWindowPoints(NULL, hDlg, (LPPOINT)&rcHelp, 2);
  1188. GetWindowRect(GetDlgItem(hDlg, IDCANCEL), &rcCancel);
  1189. MapWindowPoints(NULL, hDlg, (LPPOINT)&rcCancel, 2);
  1190. //
  1191. //Hide the Help button, Move Cancel to help position
  1192. //and Ok to Cancel positon.
  1193. //
  1194. ShowWindow(GetDlgItem(hDlg, IDHELP),FALSE);
  1195. SetWindowPos(GetDlgItem(hDlg, IDCANCEL),
  1196. NULL,
  1197. rcHelp.left,
  1198. rcHelp.top,
  1199. 0,
  1200. 0,
  1201. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  1202. SetWindowPos(GetDlgItem(hDlg, IDOK),
  1203. NULL,
  1204. rcCancel.left,
  1205. rcCancel.top,
  1206. 0,
  1207. 0,
  1208. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  1209. }
  1210. break;
  1211. }
  1212. case WM_COMMAND:
  1213. {
  1214. WORD wControlID = GET_WM_COMMAND_ID(wParam, lParam);
  1215. switch (wControlID)
  1216. {
  1217. case IDOK:
  1218. {
  1219. ACL_BLOAT_INFO * pInfo = (ACL_BLOAT_INFO *)GetWindowLongPtr(hDlg, DWLP_USER);
  1220. if(pInfo->hFont)
  1221. DeleteObject(pInfo->hFont);
  1222. pInfo->hFont = NULL;
  1223. EndDialog(hDlg, FALSE);
  1224. break;
  1225. }
  1226. case IDCANCEL:
  1227. {
  1228. ACL_BLOAT_INFO * pInfo = (ACL_BLOAT_INFO *)GetWindowLongPtr(hDlg, DWLP_USER);
  1229. if(pInfo->hFont)
  1230. DeleteObject(pInfo->hFont);
  1231. pInfo->hFont = NULL;
  1232. EndDialog(hDlg, TRUE);
  1233. break;
  1234. }
  1235. case IDHELP:
  1236. HtmlHelp(NULL,
  1237. L"aclui.chm::/ACLUI_acl_BP.htm",
  1238. HH_DISPLAY_TOPIC,
  1239. 0);
  1240. return TRUE;
  1241. }
  1242. break;
  1243. }
  1244. }
  1245. return FALSE;
  1246. }
  1247. //
  1248. // This function displays the "An error has occured [Continue] [Cancel]" message
  1249. //
  1250. // Returns IDOK or IDCANCEL
  1251. //
  1252. BOOL
  1253. IsAclBloated(HWND hWndParent, SECURITY_INFORMATION si, DWORD dwInheritAceCount, int idd, BOOL bShowHelp)
  1254. {
  1255. AclBloatInfo info;
  1256. info.dwInheriteAceCount = dwInheritAceCount;
  1257. info.si = si;
  1258. info.hFont = NULL;
  1259. info.bShowHelp = bShowHelp;
  1260. return (BOOL)DialogBoxParam(::hModule,
  1261. MAKEINTRESOURCE(idd),
  1262. hWndParent,
  1263. AclBloatDialogProc,
  1264. (LPARAM)(&info));
  1265. }
  1266. BOOL IsAclBloated(HWND hDlg, SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD, DWORD dwOrgInheritAceCount, BOOL bShowHelp)
  1267. {
  1268. ASSERT(pSD);
  1269. BOOL fReturn = FALSE;
  1270. DWORD dwNewInheritAceCount = GetCountOfInheritableAces(si, pSD);
  1271. if( ((int)dwNewInheritAceCount - (int)dwOrgInheritAceCount) > ACL_BLOAT_LIMIT )
  1272. fReturn = IsAclBloated(hDlg,
  1273. si,
  1274. dwNewInheritAceCount - dwOrgInheritAceCount,
  1275. si & DACL_SECURITY_INFORMATION ? IDD_BLOAT_NO_LIST : IDD_BLOAT_NO_LIST_SACL,
  1276. bShowHelp);
  1277. return fReturn;
  1278. }
  1279. //
  1280. //Sets the font style to bold for the hwnd.
  1281. //phNewFont gets handle to newFont which
  1282. //is to freed after hwnd is destroyed.
  1283. //
  1284. HRESULT MakeBold (HWND hwnd, HFONT *phNewFont)
  1285. {
  1286. HRESULT hr = S_OK;
  1287. HFONT hFont = NULL;
  1288. *phNewFont = NULL;
  1289. LOGFONT LogFont;
  1290. if(!hwnd || !phNewFont)
  1291. return E_POINTER;
  1292. hFont = (HFONT)SendMessage(hwnd,WM_GETFONT,0,0);
  1293. if (!hFont)
  1294. {
  1295. hr = HRESULT_FROM_WIN32(GetLastError());
  1296. return hr;
  1297. }
  1298. if (!GetObject(hFont,sizeof(LOGFONT),(LPVOID)(&LogFont)))
  1299. {
  1300. hr = HRESULT_FROM_WIN32(GetLastError());
  1301. return hr;
  1302. }
  1303. LogFont.lfWeight = FW_BOLD;
  1304. if (!(*phNewFont = CreateFontIndirect(&LogFont)))
  1305. {
  1306. hr = HRESULT_FROM_WIN32(GetLastError());
  1307. return hr;
  1308. }
  1309. SendMessage(hwnd,WM_SETFONT,(WPARAM)(*phNewFont),MAKELPARAM(FALSE,0));
  1310. return S_OK;
  1311. }