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.

1511 lines
41 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. case SidTypeComputer:
  364. idBitmap = SID_IMAGE_COMPUTER;
  365. break;
  366. default:
  367. idBitmap = SID_IMAGE_UNKNOWN;
  368. break;
  369. }
  370. return idBitmap;
  371. }
  372. #include <dsrole.h>
  373. BOOL IsStandalone(LPCTSTR pszMachine, PBOOL pbIsDC)
  374. {
  375. BOOL bStandalone = TRUE;
  376. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  377. //
  378. // Find out if target machine is a standalone machine or joined to
  379. // an NT domain.
  380. //
  381. __try
  382. {
  383. if (pbIsDC)
  384. *pbIsDC = FALSE;
  385. DsRoleGetPrimaryDomainInformation(pszMachine,
  386. DsRolePrimaryDomainInfoBasic,
  387. (PBYTE*)&pDsRole);
  388. }
  389. __finally
  390. {
  391. }
  392. if (NULL != pDsRole)
  393. {
  394. if (pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation ||
  395. pDsRole->MachineRole == DsRole_RoleStandaloneServer)
  396. {
  397. bStandalone = TRUE;
  398. }
  399. else
  400. bStandalone = FALSE;
  401. if (pbIsDC)
  402. {
  403. if (pDsRole->MachineRole == DsRole_RolePrimaryDomainController ||
  404. pDsRole->MachineRole == DsRole_RoleBackupDomainController)
  405. {
  406. *pbIsDC = TRUE;
  407. }
  408. }
  409. DsRoleFreeMemory(pDsRole);
  410. }
  411. return bStandalone;
  412. }
  413. /*******************************************************************
  414. NAME: IsDACLCanonical
  415. SYNOPSIS: Checks a DACL for canonical ordering
  416. ENTRY: pDacl - points to DACL to check
  417. EXIT:
  418. RETURNS: Nonzero if DACL is in canonical order, zero otherwise
  419. NOTES:
  420. HISTORY:
  421. JeffreyS 08-Oct-1996 Created
  422. JeffreyS 03-Oct-1997 Make object aces same as non-object aces
  423. ********************************************************************/
  424. enum ACELEVEL
  425. {
  426. alNonInheritAccessDenied,
  427. alNonInheritAccessAllowed,
  428. alInheritedAces,
  429. };
  430. BOOL
  431. IsDACLCanonical(PACL pDacl)
  432. {
  433. PACE_HEADER pAce;
  434. ACELEVEL currentAceLevel;
  435. DWORD dwAceCount;
  436. if (pDacl == NULL)
  437. return TRUE;
  438. currentAceLevel = alNonInheritAccessDenied;
  439. dwAceCount = pDacl->AceCount;
  440. if (dwAceCount == 0)
  441. return TRUE;
  442. for (pAce = (PACE_HEADER)FirstAce(pDacl);
  443. dwAceCount > 0;
  444. --dwAceCount, pAce = (PACE_HEADER)NextAce(pAce))
  445. {
  446. ACELEVEL aceLevel;
  447. //
  448. // NOTE: We do not skip INHERIT_ONLY aces because we want them in
  449. // canonical order too.
  450. //
  451. if (pAce->AceFlags & INHERITED_ACE)
  452. {
  453. aceLevel = alInheritedAces; // don't check order here
  454. }
  455. else
  456. {
  457. switch(pAce->AceType)
  458. {
  459. case ACCESS_DENIED_ACE_TYPE:
  460. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  461. aceLevel = alNonInheritAccessDenied;
  462. break;
  463. case ACCESS_ALLOWED_ACE_TYPE:
  464. case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
  465. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  466. aceLevel = alNonInheritAccessAllowed;
  467. break;
  468. default:
  469. return FALSE;
  470. }
  471. }
  472. //
  473. // If the ace type is less than the level we are currently at,
  474. // then it is not canonical.
  475. //
  476. if (aceLevel < currentAceLevel)
  477. return FALSE;
  478. //
  479. // Update the current ace level.
  480. //
  481. currentAceLevel = aceLevel;
  482. }
  483. //
  484. // If we get here, then the DACL is in canonical order.
  485. //
  486. return TRUE;
  487. }
  488. /*******************************************************************
  489. NAME: IsDenyACL
  490. SYNOPSIS: Checks a DACL for Deny ACEs. Also looks for "Deny
  491. All" ACEs.
  492. ENTRY: pDacl - points to DACL to check
  493. EXIT: *pdwWarning is 0, IDS_PERM_DENY, or IDS_PERM_DENY_ALL
  494. RETURNS: Nonzero if DACL contains any Deny ACEs, zero otherwise
  495. NOTES:
  496. HISTORY:
  497. JeffreyS 05-Sep-1997 Created
  498. ********************************************************************/
  499. BOOL
  500. IsDenyACL(PACL pDacl,
  501. BOOL fProtected,
  502. DWORD dwFullControlMask,
  503. LPDWORD pdwWarning)
  504. {
  505. DWORD dwWarning = 0;
  506. TraceEnter(TRACE_MISC, "IsDenyACL");
  507. // NULL DACL implies "Allow Everyone Full Control"
  508. if (pDacl == NULL)
  509. goto exit_gracefully;
  510. // Check for empty DACL (no access to anyone)
  511. if (pDacl->AceCount == 0)
  512. {
  513. if (fProtected)
  514. dwWarning = IDS_PERM_DENY_EMPTY_DACL;
  515. // else the object will inherit permissions from the parent.
  516. }
  517. else
  518. {
  519. PACE_HEADER pAce;
  520. int iEntry;
  521. // Iterate through the ACL looking for "Deny All"
  522. for (iEntry = 0, pAce = (PACE_HEADER)FirstAce(pDacl);
  523. iEntry < pDacl->AceCount;
  524. iEntry++, pAce = (PACE_HEADER)NextAce(pAce))
  525. {
  526. if (pAce->AceType != ACCESS_DENIED_ACE_TYPE &&
  527. pAce->AceType != ACCESS_DENIED_OBJECT_ACE_TYPE)
  528. {
  529. // Assuming the ACL is in canonical order, we can
  530. // stop as soon as we find something that isn't
  531. // a Deny ACE. (Deny ACEs come first)
  532. break;
  533. }
  534. // Found a Deny ACE
  535. dwWarning = IDS_PERM_DENY;
  536. // Check for "Deny Everyone Full Control". Don't look
  537. // for ACCESS_DENIED_OBJECT_ACE_TYPE here since Object
  538. // aces don't have as wide an effect as normal aces.
  539. if (pAce->AceType == ACCESS_DENIED_ACE_TYPE &&
  540. ((PKNOWN_ACE)pAce)->Mask == dwFullControlMask &&
  541. EqualSid(GetAceSid(pAce), QuerySystemSid(UI_SID_World)))
  542. {
  543. // Found "Deny All"
  544. dwWarning = IDS_PERM_DENY_EVERYONE_GROUP;
  545. break;
  546. }
  547. }
  548. }
  549. exit_gracefully:
  550. if (pdwWarning != NULL)
  551. *pdwWarning = dwWarning;
  552. TraceLeaveValue(dwWarning != 0);
  553. }
  554. /*******************************************************************
  555. NAME: QuerySystemSid
  556. SYNOPSIS: Retrieves the requested SID
  557. ENTRY: SystemSidType - Which SID to retrieve
  558. EXIT:
  559. RETURNS: PSID if successful, NULL otherwise
  560. HISTORY:
  561. JeffreyS 08-Oct-1996 Created
  562. ********************************************************************/
  563. //
  564. // Global array of static system SIDs, corresponding to UI_SystemSid
  565. //
  566. const struct
  567. {
  568. SID sid; // contains 1 subauthority
  569. DWORD dwSubAuth[1]; // we currently need at most 2 subauthorities
  570. } g_StaticSids[COUNT_SYSTEM_SID_TYPES] =
  571. {
  572. {{SID_REVISION,1,SECURITY_WORLD_SID_AUTHORITY, {SECURITY_WORLD_RID}}, {0} },
  573. {{SID_REVISION,1,SECURITY_CREATOR_SID_AUTHORITY,{SECURITY_CREATOR_OWNER_RID}}, {0} },
  574. {{SID_REVISION,1,SECURITY_CREATOR_SID_AUTHORITY,{SECURITY_CREATOR_GROUP_RID}}, {0} },
  575. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_DIALUP_RID}}, {0} },
  576. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_NETWORK_RID}}, {0} },
  577. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_BATCH_RID}}, {0} },
  578. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_INTERACTIVE_RID}}, {0} },
  579. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_SERVICE_RID}}, {0} },
  580. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_ANONYMOUS_LOGON_RID}}, {0} },
  581. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_PROXY_RID}}, {0} },
  582. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_ENTERPRISE_CONTROLLERS_RID}},{0} },
  583. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_PRINCIPAL_SELF_RID}}, {0} },
  584. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_AUTHENTICATED_USER_RID}}, {0} },
  585. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_RESTRICTED_CODE_RID}}, {0} },
  586. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_TERMINAL_SERVER_RID}}, {0} },
  587. {{SID_REVISION,1,SECURITY_NT_AUTHORITY, {SECURITY_LOCAL_SYSTEM_RID}}, {0} },
  588. {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ADMINS} },
  589. // {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_USERS} },
  590. // {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_GUESTS} },
  591. // {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_POWER_USERS} },
  592. // {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ACCOUNT_OPS} },
  593. // {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_SYSTEM_OPS} },
  594. // {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_PRINT_OPS} },
  595. // {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_BACKUP_OPS} },
  596. // {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_REPLICATOR} },
  597. // {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_RAS_SERVERS} },
  598. };
  599. PSID
  600. QuerySystemSid(UI_SystemSid SystemSidType)
  601. {
  602. if (SystemSidType == UI_SID_Invalid || SystemSidType >= UI_SID_Count)
  603. return NULL;
  604. return (PSID)&g_StaticSids[SystemSidType];
  605. }
  606. //
  607. // Global array of cached token SIDs
  608. //
  609. struct
  610. {
  611. SID sid; // SID contains 1 subauthority
  612. DWORD dwSubAuth[SID_MAX_SUB_AUTHORITIES - 1];
  613. } g_TokenSids[COUNT_TOKEN_SID_TYPES] = {0};
  614. PSID
  615. QueryTokenSid(UI_TokenSid TokenSidType)
  616. {
  617. if (TokenSidType == UI_TSID_Invalid || TokenSidType >= UI_TSID_Count)
  618. return NULL;
  619. if (0 == *GetSidSubAuthorityCount((PSID)&g_TokenSids[TokenSidType]))
  620. {
  621. HANDLE hProcessToken;
  622. // Get the current process's user's SID
  623. if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
  624. {
  625. BYTE buffer[sizeof(TOKEN_USER) + sizeof(g_TokenSids[0])];
  626. ULONG cbBuffer = sizeof(buffer);
  627. switch (TokenSidType)
  628. {
  629. case UI_TSID_CurrentProcessUser:
  630. if (GetTokenInformation(hProcessToken,
  631. TokenUser,
  632. buffer,
  633. cbBuffer,
  634. &cbBuffer))
  635. {
  636. PTOKEN_USER ptu = (PTOKEN_USER)buffer;
  637. CopyMemory(&g_TokenSids[UI_TSID_CurrentProcessUser],
  638. ptu->User.Sid,
  639. GetLengthSid(ptu->User.Sid));
  640. }
  641. break;
  642. case UI_TSID_CurrentProcessOwner:
  643. if (GetTokenInformation(hProcessToken,
  644. TokenOwner,
  645. buffer,
  646. cbBuffer,
  647. &cbBuffer))
  648. {
  649. PTOKEN_OWNER pto = (PTOKEN_OWNER)buffer;
  650. CopyMemory(&g_TokenSids[UI_TSID_CurrentProcessOwner],
  651. pto->Owner,
  652. GetLengthSid(pto->Owner));
  653. }
  654. break;
  655. case UI_TSID_CurrentProcessPrimaryGroup:
  656. if (GetTokenInformation(hProcessToken,
  657. TokenPrimaryGroup,
  658. buffer,
  659. cbBuffer,
  660. &cbBuffer))
  661. {
  662. PTOKEN_PRIMARY_GROUP ptg = (PTOKEN_PRIMARY_GROUP)buffer;
  663. CopyMemory(&g_TokenSids[UI_TSID_CurrentProcessPrimaryGroup],
  664. ptg->PrimaryGroup,
  665. GetLengthSid(ptg->PrimaryGroup));
  666. }
  667. break;
  668. }
  669. CloseHandle(hProcessToken);
  670. }
  671. if (0 == *GetSidSubAuthorityCount((PSID)&g_TokenSids[TokenSidType]))
  672. return NULL;
  673. }
  674. return (PSID)&g_TokenSids[TokenSidType];
  675. }
  676. /*******************************************************************
  677. NAME: GetAuthenticationID
  678. SYNOPSIS: Retrieves the SID associated with the credentials
  679. currently being used for network access.
  680. (runas /netonly credentials)
  681. ENTRY: pszServer = server on which to lookup the account.
  682. NULL indicates local system.
  683. EXIT:
  684. RETURNS: PSID if successful, NULL otherwise. Caller must
  685. free with LocalFree.
  686. HISTORY:
  687. JeffreyS 05-Aug-1999 Created
  688. ********************************************************************/
  689. PSID
  690. GetAuthenticationID(LPCWSTR pszServer)
  691. {
  692. PSID pSid = NULL;
  693. HANDLE hLsa;
  694. NTSTATUS Status;
  695. //
  696. // These LSA calls are delay-loaded from secur32.dll using the linker's
  697. // delay-load mechanism. Therefore, wrap with an exception handler.
  698. //
  699. __try
  700. {
  701. Status = LsaConnectUntrusted(&hLsa);
  702. if (Status == 0)
  703. {
  704. NEGOTIATE_CALLER_NAME_REQUEST Req = {0};
  705. PNEGOTIATE_CALLER_NAME_RESPONSE pResp;
  706. ULONG cbSize;
  707. NTSTATUS SubStatus;
  708. Req.MessageType = NegGetCallerName;
  709. Status = LsaCallAuthenticationPackage(
  710. hLsa,
  711. 0,
  712. &Req,
  713. sizeof(Req),
  714. (void**)&pResp,
  715. &cbSize,
  716. &SubStatus);
  717. if ((Status == 0) && (SubStatus == 0))
  718. {
  719. BYTE sid[sizeof(SID) + (SID_MAX_SUB_AUTHORITIES - 1)*sizeof(DWORD)];
  720. PSID psid = (PSID)sid;
  721. DWORD cbSid = sizeof(sid);
  722. WCHAR szDomain[MAX_PATH];
  723. DWORD cchDomain = ARRAYSIZE(szDomain);
  724. SID_NAME_USE sidType;
  725. if (LookupAccountNameW(pszServer,
  726. pResp->CallerName,
  727. psid,
  728. &cbSid,
  729. szDomain,
  730. &cchDomain,
  731. &sidType))
  732. {
  733. pSid = LocalAllocSid(psid);
  734. }
  735. LsaFreeReturnBuffer(pResp);
  736. }
  737. LsaDeregisterLogonProcess(hLsa);
  738. }
  739. }
  740. __except(EXCEPTION_EXECUTE_HANDLER)
  741. {
  742. }
  743. return pSid;
  744. }
  745. /*******************************************************************
  746. NAME: CopyUnicodeString
  747. SYNOPSIS: Allocates a buffer and copies a string from
  748. a UNICODE_STRING sources.
  749. ENTRY: pszDest - pointer to destination buffer
  750. cchDest - # of chars in pszDest (bytes for MBCS)
  751. pSrc - pointer to UNICODE_STRING to copy
  752. EXIT: pszDest - containing copy of string
  753. RETURNS: # of chars copied, or 0 if not successful.
  754. NOTES:
  755. HISTORY:
  756. JeffreyS 22-Jan-1998 Created
  757. ********************************************************************/
  758. int
  759. CopyUnicodeString(LPTSTR pszDest, ULONG cchDest, PLSA_UNICODE_STRING pSrc)
  760. {
  761. int nResult;
  762. ULONG cchSrc;
  763. // If UNICODE, cchDest is size of destination buffer in chars
  764. // Else (MBCS) cchDest is size of destination buffer in bytes
  765. if (pszDest == NULL || 0 == cchDest)
  766. return 0;
  767. *pszDest = TEXT('\0');
  768. if (pSrc == NULL || pSrc->Buffer == NULL)
  769. return 0;
  770. // Get # of chars in source (not including NULL)
  771. cchSrc = pSrc->Length/sizeof(WCHAR);
  772. //
  773. // Note that pSrc->Buffer may not be NULL terminated so we can't just
  774. // call lstrcpynW with cchDest. Also, if we call lstrcpynW with cchSrc,
  775. // it copies the correct # of chars, but then overwrites the last char
  776. // with NULL giving an incorrect result. If we call lstrcpynW with
  777. // (cchSrc+1) it reads past the end of the buffer, which may fault (360251)
  778. // causing lstrcpynW's exception handler to return 0 without NULL-
  779. // terminating the resulting string.
  780. //
  781. // So let's just copy the bits.
  782. //
  783. nResult = min(cchSrc, cchDest);
  784. CopyMemory(pszDest, pSrc->Buffer, sizeof(WCHAR)*nResult);
  785. if (nResult == (int)cchDest)
  786. --nResult;
  787. pszDest[nResult] = L'\0';
  788. return nResult;
  789. }
  790. /*******************************************************************
  791. NAME: CopyUnicodeString
  792. SYNOPSIS: Allocates a buffer and copies a string from
  793. a UNICODE_STRING sources.
  794. ENTRY: pSrc - pointer to UNICODE_STRING to copy
  795. EXIT: *ppszResult - points to LocalAlloc'd buffer containing copy.
  796. RETURNS: # of chars copied, or 0 if not successful.
  797. NOTES:
  798. HISTORY:
  799. JeffreyS 22-Jan-1998 Created
  800. ********************************************************************/
  801. int
  802. CopyUnicodeString(LPTSTR *ppszResult, PLSA_UNICODE_STRING pSrc)
  803. {
  804. int nResult = 0;
  805. if (NULL == ppszResult)
  806. return 0;
  807. *ppszResult = NULL;
  808. if (NULL != pSrc)
  809. {
  810. ULONG cchResult;
  811. *ppszResult = NULL;
  812. // Get # of chars in source (including NULL)
  813. cchResult = pSrc->Length/SIZEOF(WCHAR) + 1;
  814. // Allocate buffer big enough for either UNICODE or MBCS result
  815. *ppszResult = (LPTSTR)LocalAlloc(LPTR, cchResult * 2);
  816. if (*ppszResult)
  817. {
  818. nResult = CopyUnicodeString(*ppszResult, cchResult, pSrc);
  819. if (0 == nResult)
  820. {
  821. LocalFree(*ppszResult);
  822. *ppszResult = NULL;
  823. }
  824. }
  825. }
  826. return nResult;
  827. }
  828. //
  829. // Test GUIDs safely
  830. //
  831. BOOL IsSameGUID(const GUID *p1, const GUID *p2)
  832. {
  833. BOOL bResult = FALSE;
  834. if (!p1) p1 = &GUID_NULL;
  835. if (!p2) p2 = &GUID_NULL;
  836. __try
  837. {
  838. bResult = InlineIsEqualGUID(*p1, *p2);
  839. }
  840. __except(EXCEPTION_EXECUTE_HANDLER)
  841. {
  842. }
  843. return bResult;
  844. }
  845. /*******************************************************************
  846. NAME: GetCountOfInheritableAces
  847. SYNOPSIS: Get the count of aces in ACL which can be
  848. inherited to child objects
  849. RETURNS: Count of Aces
  850. ********************************************************************/
  851. DWORD GetCountOfInheritableAces(PACL pAcl)
  852. {
  853. if(!pAcl)
  854. return 0;
  855. DWORD dwCount = 0;
  856. PACE_HEADER pAce = NULL;
  857. int iEntry = 0;
  858. for (iEntry = 0, pAce = (PACE_HEADER)FirstAce(pAcl);
  859. iEntry < pAcl->AceCount;
  860. iEntry++, pAce = (PACE_HEADER)NextAce(pAce))
  861. {
  862. //
  863. //Consider only explicit aces
  864. //
  865. if((!(pAce->AceFlags & INHERITED_ACE))&&(pAce->AceFlags & (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE)))
  866. dwCount++;
  867. }
  868. return dwCount;
  869. }
  870. /*******************************************************************
  871. NAME: GetCountOfInheritableAces
  872. SYNOPSIS: Get the count of aces in SACL or DACL which can be
  873. inherited to child objects
  874. RETURNS: Count of Aces
  875. ********************************************************************/
  876. DWORD GetCountOfInheritableAces(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
  877. {
  878. if(!pSD)
  879. return 0;
  880. PACL pAcl = NULL;
  881. BOOL bPresent;
  882. BOOL bDefault;
  883. if(si & DACL_SECURITY_INFORMATION)
  884. {
  885. if(GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefault))
  886. {
  887. return GetCountOfInheritableAces(pAcl);
  888. }
  889. }
  890. else if(si & SACL_SECURITY_INFORMATION)
  891. {
  892. if(GetSecurityDescriptorSacl(pSD, &bPresent, &pAcl, &bDefault))
  893. {
  894. return GetCountOfInheritableAces(pAcl);
  895. }
  896. }
  897. return 0;
  898. }
  899. typedef struct AclBloatInfo{
  900. DWORD dwInheriteAceCount;
  901. SECURITY_INFORMATION si;
  902. HFONT hFont;
  903. BOOL bShowHelp;
  904. }ACL_BLOAT_INFO;
  905. INT_PTR CALLBACK
  906. AclBloatDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  907. {
  908. switch (uMsg)
  909. {
  910. case WM_INITDIALOG:
  911. {
  912. ACL_BLOAT_INFO * pInfo= (ACL_BLOAT_INFO*)lParam;
  913. ASSERT(pInfo);
  914. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pInfo);
  915. //
  916. //Add a warning icon
  917. //
  918. // add the warning icon
  919. HICON hWarn = LoadIcon(NULL, IDI_WARNING);
  920. SendDlgItemMessage(hDlg, // dialog box window handle
  921. IDC_BLOAT_WARN_ICON, // icon identifier
  922. STM_SETIMAGE, // message to send
  923. (WPARAM) IMAGE_ICON, // image type
  924. (LPARAM) hWarn); // icon handle
  925. //
  926. //Set the title of dialog box
  927. //
  928. LPTSTR pszCaption = NULL;
  929. if(FormatStringID(&pszCaption,
  930. ::hModule,
  931. pInfo->si & DACL_SECURITY_INFORMATION ? IDS_PERMISSIONS : IDS_AUDITING))
  932. {
  933. SetWindowText(hDlg, pszCaption);
  934. LocalFreeString(&pszCaption);
  935. }
  936. //
  937. //Set the warning message
  938. //
  939. UINT cItem = pInfo->dwInheriteAceCount;
  940. WCHAR buffer[34];
  941. _itow(cItem,buffer,10);
  942. if(FormatStringID(&pszCaption,
  943. ::hModule,
  944. pInfo->si & DACL_SECURITY_INFORMATION ? IDS_ACLBLOAT_NO_LIST_LINE1:IDS_ACLBLOAT_NO_LIST_SACL_LINE1,
  945. buffer))
  946. {
  947. SetDlgItemText(hDlg, IDC_ACLBLOAT_LINE1, pszCaption);
  948. LocalFreeString(&pszCaption);
  949. }
  950. //
  951. //make warning bold
  952. //
  953. MakeBold(GetDlgItem(hDlg,IDC_ACLB_WARNING), &(pInfo->hFont));
  954. //
  955. //Set the line2, hide the Help button and move other buttons.
  956. //
  957. if(!pInfo->bShowHelp)
  958. {
  959. if(FormatStringID(&pszCaption,
  960. ::hModule,
  961. pInfo->si & DACL_SECURITY_INFORMATION ? IDS_BLOAT_PERM_LINE2_NOHELP : IDS_BLOAT_AUDIT_LINE2_NOHELP))
  962. {
  963. SetDlgItemText(hDlg, IDC_ACLB_LINE3, pszCaption);
  964. LocalFreeString(&pszCaption);
  965. }
  966. RECT rcHelp, rcCancel;
  967. GetWindowRect(GetDlgItem(hDlg, IDHELP), &rcHelp);
  968. MapWindowPoints(NULL, hDlg, (LPPOINT)&rcHelp, 2);
  969. GetWindowRect(GetDlgItem(hDlg, IDCANCEL), &rcCancel);
  970. MapWindowPoints(NULL, hDlg, (LPPOINT)&rcCancel, 2);
  971. //
  972. //Hide the Help button, Move Cancel to help position
  973. //and Ok to Cancel positon.
  974. //
  975. ShowWindow(GetDlgItem(hDlg, IDHELP),FALSE);
  976. SetWindowPos(GetDlgItem(hDlg, IDCANCEL),
  977. NULL,
  978. rcHelp.left,
  979. rcHelp.top,
  980. 0,
  981. 0,
  982. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  983. SetWindowPos(GetDlgItem(hDlg, IDOK),
  984. NULL,
  985. rcCancel.left,
  986. rcCancel.top,
  987. 0,
  988. 0,
  989. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  990. }
  991. break;
  992. }
  993. case WM_COMMAND:
  994. {
  995. WORD wControlID = GET_WM_COMMAND_ID(wParam, lParam);
  996. switch (wControlID)
  997. {
  998. case IDOK:
  999. {
  1000. ACL_BLOAT_INFO * pInfo = (ACL_BLOAT_INFO *)GetWindowLongPtr(hDlg, DWLP_USER);
  1001. if(pInfo->hFont)
  1002. DeleteObject(pInfo->hFont);
  1003. pInfo->hFont = NULL;
  1004. EndDialog(hDlg, FALSE);
  1005. break;
  1006. }
  1007. case IDCANCEL:
  1008. {
  1009. ACL_BLOAT_INFO * pInfo = (ACL_BLOAT_INFO *)GetWindowLongPtr(hDlg, DWLP_USER);
  1010. if(pInfo->hFont)
  1011. DeleteObject(pInfo->hFont);
  1012. pInfo->hFont = NULL;
  1013. EndDialog(hDlg, TRUE);
  1014. break;
  1015. }
  1016. case IDHELP:
  1017. HtmlHelp(NULL,
  1018. L"aclui.chm::/ACLUI_acl_BP.htm",
  1019. HH_DISPLAY_TOPIC,
  1020. 0);
  1021. return TRUE;
  1022. }
  1023. break;
  1024. }
  1025. }
  1026. return FALSE;
  1027. }
  1028. //
  1029. // This function displays the "An error has occured [Continue] [Cancel]" message
  1030. //
  1031. // Returns IDOK or IDCANCEL
  1032. //
  1033. BOOL
  1034. IsAclBloated(HWND hWndParent, SECURITY_INFORMATION si, DWORD dwInheritAceCount, int idd, BOOL bShowHelp)
  1035. {
  1036. AclBloatInfo info;
  1037. info.dwInheriteAceCount = dwInheritAceCount;
  1038. info.si = si;
  1039. info.hFont = NULL;
  1040. info.bShowHelp = bShowHelp;
  1041. return (BOOL)DialogBoxParam(::hModule,
  1042. MAKEINTRESOURCE(idd),
  1043. hWndParent,
  1044. AclBloatDialogProc,
  1045. (LPARAM)(&info));
  1046. }
  1047. BOOL IsAclBloated(HWND hDlg, SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD, DWORD dwOrgInheritAceCount, BOOL bShowHelp)
  1048. {
  1049. ASSERT(pSD);
  1050. BOOL fReturn = FALSE;
  1051. DWORD dwNewInheritAceCount = GetCountOfInheritableAces(si, pSD);
  1052. if( ((int)dwNewInheritAceCount - (int)dwOrgInheritAceCount) > ACL_BLOAT_LIMIT )
  1053. fReturn = IsAclBloated(hDlg,
  1054. si,
  1055. dwNewInheritAceCount - dwOrgInheritAceCount,
  1056. si & DACL_SECURITY_INFORMATION ? IDD_BLOAT_NO_LIST : IDD_BLOAT_NO_LIST_SACL,
  1057. bShowHelp);
  1058. return fReturn;
  1059. }
  1060. //
  1061. //Sets the font style to bold for the hwnd.
  1062. //phNewFont gets handle to newFont which
  1063. //is to freed after hwnd is destroyed.
  1064. //
  1065. HRESULT MakeBold (HWND hwnd, HFONT *phNewFont)
  1066. {
  1067. HRESULT hr = S_OK;
  1068. HFONT hFont = NULL;
  1069. *phNewFont = NULL;
  1070. LOGFONT LogFont;
  1071. if(!hwnd || !phNewFont)
  1072. return E_POINTER;
  1073. hFont = (HFONT)SendMessage(hwnd,WM_GETFONT,0,0);
  1074. if (!hFont)
  1075. {
  1076. hr = HRESULT_FROM_WIN32(GetLastError());
  1077. return hr;
  1078. }
  1079. if (!GetObject(hFont,sizeof(LOGFONT),(LPVOID)(&LogFont)))
  1080. {
  1081. hr = HRESULT_FROM_WIN32(GetLastError());
  1082. return hr;
  1083. }
  1084. LogFont.lfWeight = FW_BOLD;
  1085. if (!(*phNewFont = CreateFontIndirect(&LogFont)))
  1086. {
  1087. hr = HRESULT_FROM_WIN32(GetLastError());
  1088. return hr;
  1089. }
  1090. SendMessage(hwnd,WM_SETFONT,(WPARAM)(*phNewFont),MAKELPARAM(FALSE,0));
  1091. return S_OK;
  1092. }
  1093. //+----------------------------------------------------------------------------
  1094. // Function:DoDisabledCheck
  1095. // Synopsis:Check if any of the object in pDsSelList is disabled. if yes,
  1096. // function displays a dialog box to user.
  1097. // Returns: TRUE if to add objects in list to acl else no.
  1098. //-----------------------------------------------------------------------------
  1099. BOOL
  1100. DoDisabledCheck(IN HWND hWnd,
  1101. IN PDS_SELECTION_LIST pDsSelList)
  1102. {
  1103. if(!pDsSelList)
  1104. {
  1105. return FALSE;
  1106. }
  1107. HRESULT hr = S_OK;
  1108. int cNames = pDsSelList->cItems;
  1109. BOOL bDisabled = FALSE;
  1110. //
  1111. //Check if account of any of the object in the list is disbled
  1112. //
  1113. for (int i = 0; i < cNames; i++)
  1114. {
  1115. //Second element in the array is pointer to UserAccountControl
  1116. LPVARIANT pvarUAC = pDsSelList->aDsSelection[i].pvarFetchedAttributes + 1;
  1117. if (NULL == pvarUAC || (VT_I4 != V_VT(pvarUAC)))
  1118. {
  1119. continue;
  1120. }
  1121. if(bDisabled = V_I4(pvarUAC) & UF_ACCOUNTDISABLE)
  1122. break;
  1123. }
  1124. BOOL bReturn = TRUE;
  1125. if(bDisabled)
  1126. {
  1127. WCHAR szBuffer[1024];
  1128. WCHAR szCaption[1024];
  1129. LoadString(::hModule, IDS_DISABLED_USER, szBuffer, ARRAYSIZE(szBuffer));
  1130. LoadString(::hModule, IDS_SECURITY, szCaption, ARRAYSIZE(szCaption));
  1131. if(IDCANCEL == MessageBox(hWnd,
  1132. szBuffer,
  1133. szCaption,
  1134. MB_OKCANCEL | MB_ICONWARNING | MB_APPLMODAL ))
  1135. {
  1136. bReturn = FALSE;
  1137. }
  1138. }
  1139. return bReturn;
  1140. }
  1141. BOOL
  1142. IsCallBackAcePresentInSD(PSECURITY_DESCRIPTOR pSD)
  1143. {
  1144. if (pSD == NULL || !IsValidSecurityDescriptor(pSD))
  1145. return FALSE;
  1146. PACL pAcl = NULL;
  1147. BOOL bDefaulted = FALSE;
  1148. BOOL bPresent = FALSE;
  1149. if(!GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefaulted))
  1150. return FALSE;
  1151. if(!bPresent || !pAcl)
  1152. return FALSE;
  1153. return IsCallBackAcePresentInAcl(pAcl);
  1154. }
  1155. BOOL
  1156. IsCallBackAcePresentInAcl(PACL pAcl)
  1157. {
  1158. if(!pAcl)
  1159. return FALSE;
  1160. DWORD dwAceCount = pAcl->AceCount;
  1161. if (dwAceCount == 0)
  1162. return FALSE;
  1163. PACE_HEADER pAce;
  1164. for (pAce = (PACE_HEADER)FirstAce(pAcl);
  1165. dwAceCount > 0;
  1166. --dwAceCount, pAce = (PACE_HEADER)NextAce(pAce))
  1167. {
  1168. if(pAce->AceType >= ACCESS_ALLOWED_CALLBACK_ACE_TYPE &&
  1169. pAce->AceType <= SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE)
  1170. {
  1171. return TRUE;
  1172. }
  1173. }
  1174. return FALSE;
  1175. }