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.

1509 lines
48 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: ntfssi.cpp
  8. //
  9. // This file contains the implementation of the CNTFSSecurity object.
  10. //
  11. //--------------------------------------------------------------------------
  12. #include "rshx32.h"
  13. #include <windowsx.h> // GET_WM_COMMAND_ID, etc.
  14. #include <atlconv.h>
  15. #define MY_FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED \
  16. | SYNCHRONIZE \
  17. | FILE_READ_DATA | FILE_LIST_DIRECTORY \
  18. | FILE_WRITE_DATA | FILE_ADD_FILE \
  19. | FILE_APPEND_DATA | FILE_ADD_SUBDIRECTORY \
  20. | FILE_CREATE_PIPE_INSTANCE \
  21. | FILE_READ_EA \
  22. | FILE_WRITE_EA \
  23. | FILE_EXECUTE | FILE_TRAVERSE \
  24. | FILE_DELETE_CHILD \
  25. | FILE_READ_ATTRIBUTES \
  26. | FILE_WRITE_ATTRIBUTES)
  27. #if(FILE_ALL_ACCESS != MY_FILE_ALL_ACCESS)
  28. #error ACL editor needs to sync with file permissions changes in ntioapi.h (or ntioapi.h is broken)
  29. #endif
  30. #define INHERIT_FULL (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)
  31. //
  32. // Treat SYNCHRONIZE specially. In particular, always allow SYNCHRONIZE and
  33. // never Deny SYNCHRONIZE. Do this by removing it from the Generic Mapping,
  34. // turning it off in all ACEs and SI_ACCESS entries, and then adding it to
  35. // all Allow ACEs before saving a new ACL.
  36. //
  37. #define FILE_GENERIC_READ_ (FILE_GENERIC_READ & ~SYNCHRONIZE)
  38. #define FILE_GENERIC_WRITE_ (FILE_GENERIC_WRITE & ~(SYNCHRONIZE | READ_CONTROL))
  39. #define FILE_GENERIC_EXECUTE_ (FILE_GENERIC_EXECUTE & ~SYNCHRONIZE)
  40. #define FILE_GENERIC_ALL_ (FILE_ALL_ACCESS & ~SYNCHRONIZE)
  41. #define FILE_GENERAL_MODIFY (FILE_GENERIC_READ_ | FILE_GENERIC_WRITE_ | FILE_GENERIC_EXECUTE_ | DELETE)
  42. #define FILE_GENERAL_PUBLISH (FILE_GENERIC_READ_ | FILE_GENERIC_WRITE_ | FILE_GENERIC_EXECUTE_)
  43. #define FILE_GENERAL_DEPOSIT (FILE_GENERIC_WRITE_ | FILE_GENERIC_EXECUTE_)
  44. #define FILE_GENERAL_READ_EX (FILE_GENERIC_READ_ | FILE_GENERIC_EXECUTE_)
  45. // The following array defines the permission names for NTFS objects.
  46. SI_ACCESS siNTFSAccesses[] =
  47. {
  48. { &GUID_NULL, FILE_GENERIC_ALL_, MAKEINTRESOURCE(IDS_NTFS_GENERIC_ALL), SI_ACCESS_GENERAL | INHERIT_FULL|SI_ACCESS_SPECIFIC },
  49. { &GUID_NULL, FILE_GENERAL_MODIFY, MAKEINTRESOURCE(IDS_NTFS_GENERAL_MODIFY), SI_ACCESS_GENERAL | INHERIT_FULL },
  50. { &GUID_NULL, FILE_GENERAL_READ_EX, MAKEINTRESOURCE(IDS_NTFS_GENERAL_READ), SI_ACCESS_GENERAL | INHERIT_FULL },
  51. { &GUID_NULL, FILE_GENERAL_READ_EX, MAKEINTRESOURCE(IDS_NTFS_GENERAL_LIST), SI_ACCESS_CONTAINER | CONTAINER_INHERIT_ACE },
  52. { &GUID_NULL, FILE_GENERIC_READ_, MAKEINTRESOURCE(IDS_NTFS_GENERIC_READ), SI_ACCESS_GENERAL | INHERIT_FULL },
  53. { &GUID_NULL, FILE_GENERIC_WRITE_, MAKEINTRESOURCE(IDS_NTFS_GENERIC_WRITE), SI_ACCESS_GENERAL | INHERIT_FULL },
  54. { &GUID_NULL, FILE_EXECUTE, MAKEINTRESOURCE(IDS_NTFS_FILE_EXECUTE), SI_ACCESS_SPECIFIC },
  55. { &GUID_NULL, FILE_READ_DATA, MAKEINTRESOURCE(IDS_NTFS_FILE_READ_DATA), SI_ACCESS_SPECIFIC },
  56. { &GUID_NULL, FILE_READ_ATTRIBUTES, MAKEINTRESOURCE(IDS_NTFS_FILE_READ_ATTR), SI_ACCESS_SPECIFIC },
  57. { &GUID_NULL, FILE_READ_EA, MAKEINTRESOURCE(IDS_NTFS_FILE_READ_EA), SI_ACCESS_SPECIFIC },
  58. { &GUID_NULL, FILE_WRITE_DATA, MAKEINTRESOURCE(IDS_NTFS_FILE_WRITE_DATA), SI_ACCESS_SPECIFIC },
  59. { &GUID_NULL, FILE_APPEND_DATA, MAKEINTRESOURCE(IDS_NTFS_FILE_APPEND_DATA), SI_ACCESS_SPECIFIC },
  60. { &GUID_NULL, FILE_WRITE_ATTRIBUTES,MAKEINTRESOURCE(IDS_NTFS_FILE_WRITE_ATTR), SI_ACCESS_SPECIFIC },
  61. { &GUID_NULL, FILE_WRITE_EA, MAKEINTRESOURCE(IDS_NTFS_FILE_WRITE_EA), SI_ACCESS_SPECIFIC },
  62. { &GUID_NULL, FILE_DELETE_CHILD, MAKEINTRESOURCE(IDS_NTFS_FILE_DELETE_CHILD),SI_ACCESS_SPECIFIC },
  63. #if(FILE_CREATE_PIPE_INSTANCE != FILE_APPEND_DATA)
  64. { &GUID_NULL, FILE_CREATE_PIPE_INSTANCE, MAKEINTRESOURCE(IDS_NTFS_FILE_CREATE_PIPE), SI_ACCESS_SPECIFIC },
  65. #endif
  66. { &GUID_NULL, DELETE, MAKEINTRESOURCE(IDS_NTFS_STD_DELETE), SI_ACCESS_SPECIFIC },
  67. { &GUID_NULL, READ_CONTROL, MAKEINTRESOURCE(IDS_NTFS_STD_READ_CONTROL), SI_ACCESS_SPECIFIC },
  68. { &GUID_NULL, WRITE_DAC, MAKEINTRESOURCE(IDS_NTFS_STD_WRITE_DAC), SI_ACCESS_SPECIFIC },
  69. { &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCE(IDS_NTFS_STD_WRITE_OWNER), SI_ACCESS_SPECIFIC },
  70. // { &GUID_NULL, SYNCHRONIZE, MAKEINTRESOURCE(IDS_NTFS_STD_SYNCHRONIZE), SI_ACCESS_SPECIFIC },
  71. { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_NONE), 0 },
  72. { &GUID_NULL, FILE_GENERIC_EXECUTE_,MAKEINTRESOURCE(IDS_NTFS_GENERIC_EXECUTE), 0 },
  73. { &GUID_NULL, FILE_GENERAL_DEPOSIT, MAKEINTRESOURCE(IDS_NTFS_GENERAL_DEPOSIT), 0 },
  74. { &GUID_NULL, FILE_GENERAL_PUBLISH, MAKEINTRESOURCE(IDS_NTFS_GENERAL_PUBLISH), 0 },
  75. };
  76. #define iNTFSDefAccess 2 // FILE_GENERAL_READ_EX
  77. #define iNTFSDelChildAccess 14 // FILE_DELETE_CHILD
  78. // The following array defines the inheritance types for NTFS directories.
  79. SI_INHERIT_TYPE siNTFSInheritTypes[] =
  80. {
  81. &GUID_NULL, 0, MAKEINTRESOURCE(IDS_NTFS_FOLDER),
  82. &GUID_NULL, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_FOLDER_SUBITEMS),
  83. &GUID_NULL, CONTAINER_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_FOLDER_SUBFOLDER),
  84. &GUID_NULL, OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_FOLDER_FILE),
  85. &GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_SUBITEMS_ONLY),
  86. &GUID_NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_SUBFOLDER_ONLY),
  87. &GUID_NULL, INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_NTFS_FILE_ONLY),
  88. };
  89. VOID ProgressFunction(IN LPWSTR pObjectName,
  90. IN DWORD Status,
  91. IN OUT PPROG_INVOKE_SETTING pInvokeSetting ,
  92. IN PVOID Args,
  93. IN BOOL SecuritySet);
  94. BOOL SetFileSecurityUsingNTName(IN LPCWSTR pszFileName,
  95. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  96. OUT PBOOL pbIsFile);
  97. STDMETHODIMP
  98. CheckFileAccess(LPCTSTR pszObjectName, LPDWORD pdwAccessGranted)
  99. {
  100. HRESULT hr = S_OK;
  101. UINT i;
  102. UNICODE_STRING usNtFileName = {0};
  103. DWORD dwAccessDesired[] = { ALL_SECURITY_ACCESS,
  104. READ_CONTROL,
  105. WRITE_DAC,
  106. WRITE_OWNER,
  107. ACCESS_SYSTEM_SECURITY };
  108. TraceEnter(TRACE_NTFSSI, "CheckFileAccess");
  109. TraceAssert(pdwAccessGranted != NULL);
  110. *pdwAccessGranted = 0;
  111. if (!RtlDosPathNameToNtPathName_U(pszObjectName,
  112. &usNtFileName,
  113. NULL,
  114. NULL))
  115. {
  116. ExitGracefully(hr, E_OUTOFMEMORY, "RtlDosPathNameToNtPathName_U failed");
  117. }
  118. for (i = 0; i < ARRAYSIZE(dwAccessDesired); i++)
  119. {
  120. OBJECT_ATTRIBUTES oa;
  121. IO_STATUS_BLOCK StatusBlock;
  122. DWORD dwErr;
  123. HANDLE hFile;
  124. if ((dwAccessDesired[i] & *pdwAccessGranted) == dwAccessDesired[i])
  125. continue; // already have this access
  126. InitializeObjectAttributes(&oa,
  127. &usNtFileName,
  128. OBJ_CASE_INSENSITIVE,
  129. 0,
  130. 0);
  131. dwErr = RtlNtStatusToDosError(NtOpenFile(&hFile,
  132. dwAccessDesired[i],
  133. &oa,
  134. &StatusBlock,
  135. FILE_SHARE_READ | FILE_SHARE_WRITE,
  136. 0));
  137. if (dwErr == 0)
  138. {
  139. *pdwAccessGranted |= dwAccessDesired[i];
  140. NtClose(hFile);
  141. }
  142. }
  143. exit_gracefully:
  144. RtlFreeUnicodeString(&usNtFileName);
  145. Trace((TEXT("Access = 0x%08x"), *pdwAccessGranted));
  146. TraceLeaveResult(hr);
  147. }
  148. ///////////////////////////////////////////////////////////
  149. //
  150. // Constructor/destructor
  151. //
  152. ///////////////////////////////////////////////////////////
  153. NTFS_COMPARE_DATA::~NTFS_COMPARE_DATA()
  154. {
  155. LocalFreeString(&pszSaclConflict);
  156. LocalFreeString(&pszDaclConflict);
  157. LocalFreeString(&pszFailureMsg);
  158. }
  159. CNTFSSecurity::CNTFSSecurity(SE_OBJECT_TYPE seType, BOOL bShowLossInheritedAclWarning)
  160. : CSecurityInformation(seType),
  161. m_pszSystemDrive(NULL),
  162. m_pszSystemRoot(NULL),
  163. m_bShowLossInheritedAclWarning(bShowLossInheritedAclWarning)
  164. {
  165. }
  166. CNTFSSecurity::~CNTFSSecurity()
  167. {
  168. if (m_pCompareData != NULL)
  169. m_pCompareData->bAbortThread = TRUE;
  170. if(m_pszSystemDrive)
  171. LocalFree(m_pszSystemDrive);
  172. if(m_pszSystemRoot)
  173. LocalFree(m_pszSystemRoot);
  174. WaitForComparison();
  175. delete m_pCompareData;
  176. }
  177. STDMETHODIMP
  178. CNTFSSecurity::Initialize(HDPA hItemList,
  179. DWORD dwFlags,
  180. LPTSTR pszServer,
  181. LPTSTR pszObject)
  182. {
  183. HRESULT hr;
  184. //
  185. // If we're editing the owner on a folder, turn on the Recurse button.
  186. //
  187. if (dwFlags & SI_CONTAINER)
  188. {
  189. if ((dwFlags & (SI_EDIT_OWNER | SI_OWNER_READONLY)) == SI_EDIT_OWNER)
  190. dwFlags |= SI_OWNER_RECURSE;
  191. if (!(dwFlags & SI_READONLY))
  192. dwFlags |= SI_RESET_DACL_TREE;
  193. if (dwFlags & SI_EDIT_AUDITS)
  194. dwFlags |= SI_RESET_SACL_TREE;
  195. }
  196. //
  197. // Let the base class do its thing
  198. //
  199. hr = CSecurityInformation::Initialize(hItemList,
  200. dwFlags,
  201. pszServer,
  202. pszObject);
  203. //
  204. // If multiple selection, create thread to compare security descriptors
  205. //
  206. if (m_hItemList && DPA_GetPtrCount(m_hItemList) > 1)
  207. {
  208. m_pCompareData = new NTFS_COMPARE_DATA(m_hItemList, m_dwSIFlags);
  209. if (m_pCompareData != NULL)
  210. {
  211. DWORD dwID;
  212. m_hCompareThread = CreateThread(NULL,
  213. 0,
  214. NTFSCompareThreadProc,
  215. m_pCompareData,
  216. CREATE_SUSPENDED,
  217. &dwID);
  218. if (m_hCompareThread != NULL)
  219. {
  220. SetThreadPriority(m_hCompareThread, THREAD_PRIORITY_BELOW_NORMAL);
  221. ResumeThread(m_hCompareThread);
  222. }
  223. else
  224. {
  225. delete m_pCompareData;
  226. m_pCompareData = NULL;
  227. }
  228. }
  229. }
  230. //Get System Paths
  231. GetSystemPaths(&m_pszSystemDrive,&m_pszSystemRoot);
  232. return hr;
  233. }
  234. ///////////////////////////////////////////////////////////
  235. //
  236. // ISecurityInformation methods
  237. //
  238. ///////////////////////////////////////////////////////////
  239. STDMETHODIMP
  240. CNTFSSecurity::GetAccessRights(const GUID* /*pguidObjectType*/,
  241. DWORD dwFlags,
  242. PSI_ACCESS *ppAccesses,
  243. ULONG *pcAccesses,
  244. ULONG *piDefaultAccess)
  245. {
  246. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::GetAccessRights");
  247. TraceAssert(ppAccesses != NULL);
  248. TraceAssert(pcAccesses != NULL);
  249. TraceAssert(piDefaultAccess != NULL);
  250. //
  251. //Don't Show delete subfolder and files for files or
  252. //when applyonto is files only
  253. //
  254. if(IsFile())
  255. siNTFSAccesses[iNTFSDelChildAccess].dwFlags = 0;
  256. else
  257. siNTFSAccesses[iNTFSDelChildAccess].dwFlags = SI_ACCESS_SPECIFIC;
  258. *ppAccesses = siNTFSAccesses;
  259. *pcAccesses = ARRAYSIZE(siNTFSAccesses);
  260. *piDefaultAccess = iNTFSDefAccess;
  261. TraceLeaveResult(S_OK);
  262. }
  263. GENERIC_MAPPING NTFSMap =
  264. {
  265. FILE_GENERIC_READ_,
  266. FILE_GENERIC_WRITE_,
  267. FILE_GENERIC_EXECUTE_,
  268. FILE_GENERIC_ALL_
  269. };
  270. STDMETHODIMP
  271. CNTFSSecurity::MapGeneric(const GUID* /*pguidObjectType*/,
  272. UCHAR * /*pAceFlags*/,
  273. ACCESS_MASK *pmask)
  274. {
  275. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::MapGeneric");
  276. TraceAssert(pmask != NULL);
  277. MapGenericMask(pmask, &NTFSMap);
  278. *pmask &= ~SYNCHRONIZE;
  279. TraceLeaveResult(S_OK);
  280. }
  281. STDMETHODIMP
  282. CNTFSSecurity::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
  283. ULONG *pcInheritTypes)
  284. {
  285. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::GetInheritTypes");
  286. TraceAssert(ppInheritTypes != NULL);
  287. TraceAssert(pcInheritTypes != NULL);
  288. if (m_dwSIFlags & SI_CONTAINER)
  289. {
  290. *ppInheritTypes = siNTFSInheritTypes;
  291. *pcInheritTypes = ARRAYSIZE(siNTFSInheritTypes);
  292. TraceLeaveResult(S_OK);
  293. }
  294. TraceLeaveResult(E_NOTIMPL);
  295. }
  296. STDMETHODIMP
  297. CNTFSSecurity::GetSecurity(SECURITY_INFORMATION si,
  298. PSECURITY_DESCRIPTOR *ppSD,
  299. BOOL fDefault)
  300. {
  301. HRESULT hr = S_OK;
  302. SECURITY_INFORMATION siConflict = 0;
  303. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::GetSecurity");
  304. TraceAssert(si != 0);
  305. TraceAssert(ppSD != NULL);
  306. *ppSD = NULL;
  307. if (fDefault)
  308. {
  309. ExitGracefully(hr, E_NOTIMPL, "Default security descriptor not supported");
  310. }
  311. WaitForComparison();
  312. if (m_pCompareData != NULL)
  313. {
  314. //If comparison failed we cannot do anything.
  315. //Display the error message. Error message is
  316. //be set by DPA_CompareSecurityIntersection as
  317. //this function knows the exact casue and context
  318. //of failure.
  319. if(FAILED(m_pCompareData->hrResult))
  320. {
  321. if(m_pCompareData->pszFailureMsg)
  322. {
  323. MsgPopup(GetLastActivePopup(m_hwndOwner),
  324. m_pCompareData->pszFailureMsg,
  325. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  326. MB_OK | MB_ICONWARNING | MB_SETFOREGROUND,
  327. g_hInstance);
  328. return S_FALSE;
  329. }
  330. return m_pCompareData->hrResult;
  331. }
  332. siConflict = si & m_pCompareData->siConflict;
  333. }
  334. // Read it from the first item.
  335. hr = CSecurityInformation::GetSecurity(si, ppSD, fDefault);
  336. if (SUCCEEDED(hr) && siConflict != 0)
  337. {
  338. //
  339. // Clear out any of the parts that conflict
  340. //
  341. PISECURITY_DESCRIPTOR psd = (PISECURITY_DESCRIPTOR)*ppSD;
  342. TraceAssert(psd != NULL);
  343. if (siConflict & OWNER_SECURITY_INFORMATION)
  344. {
  345. psd->Owner = NULL;
  346. }
  347. if (siConflict & GROUP_SECURITY_INFORMATION)
  348. {
  349. psd->Group = NULL;
  350. }
  351. // The following can happen if there was an error resetting ACLs above
  352. if (siConflict & SACL_SECURITY_INFORMATION)
  353. {
  354. psd->Control &= ~SE_SACL_PRESENT;
  355. psd->Sacl = NULL;
  356. }
  357. if (siConflict & DACL_SECURITY_INFORMATION)
  358. {
  359. psd->Control &= ~SE_DACL_PRESENT;
  360. psd->Dacl = NULL;
  361. }
  362. }
  363. exit_gracefully:
  364. TraceLeaveResult(hr);
  365. }
  366. //
  367. // See comments about SYNCHRONIZE at the top of this file
  368. //
  369. void
  370. FixSynchronizeAccess(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
  371. {
  372. if (NULL != pSD && 0 != (si & DACL_SECURITY_INFORMATION))
  373. {
  374. BOOL bPresent;
  375. BOOL bDefault;
  376. PACL pDacl = NULL;
  377. GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefault);
  378. if (pDacl)
  379. {
  380. PACE_HEADER pAce;
  381. int i;
  382. for (i = 0, pAce = (PACE_HEADER)FirstAce(pDacl);
  383. i < pDacl->AceCount;
  384. i++, pAce = (PACE_HEADER)NextAce(pAce))
  385. {
  386. if (ACCESS_ALLOWED_ACE_TYPE == pAce->AceType)
  387. ((PKNOWN_ACE)pAce)->Mask |= SYNCHRONIZE;
  388. //
  389. //If full control is denied, there is no reason not
  390. //to deny Synchronize permission.
  391. //
  392. else if((ACCESS_DENIED_ACE_TYPE == pAce->AceType) &&
  393. (((PKNOWN_ACE)pAce)->Mask == FILE_GENERIC_ALL_))
  394. ((PKNOWN_ACE)pAce)->Mask = FILE_ALL_ACCESS;
  395. }
  396. }
  397. }
  398. }
  399. STDMETHODIMP
  400. CNTFSSecurity::SetSecurity(SECURITY_INFORMATION si,
  401. PSECURITY_DESCRIPTOR pSD)
  402. {
  403. HRESULT hr = S_OK;
  404. if (si & DACL_SECURITY_INFORMATION)
  405. FixSynchronizeAccess(si, pSD);
  406. if(m_bShowLossInheritedAclWarning)
  407. {
  408. if(!SetAclOnRemoteNetworkDrive(m_hItemList,
  409. si,
  410. pSD,
  411. GetLastActivePopup(m_hwndOwner)))
  412. {
  413. return S_FALSE;
  414. }
  415. }
  416. if(!SetAclOnSystemPaths(m_hItemList,
  417. m_pszSystemDrive,
  418. m_pszSystemRoot,
  419. si,
  420. GetLastActivePopup(m_hwndOwner)))
  421. {
  422. return S_FALSE;
  423. }
  424. //
  425. // If we need to recursively set the Owner, get the Owner &
  426. // Group from pSD.
  427. //
  428. if (si & ( SI_OWNER_RECURSE | SI_RESET_DACL_TREE | SI_RESET_SACL_TREE ) )
  429. {
  430. si = si & (~( SI_OWNER_RECURSE | SI_RESET_DACL_TREE | SI_RESET_SACL_TREE ));
  431. hr = SetSecurityLocal(si, pSD, NULL);
  432. // Remember whether the user cancelled, since hr gets
  433. // reset when we call the base class below.
  434. }
  435. else
  436. {
  437. // See comments about SYNCHRONIZE at the top of this file
  438. // Call the base class to do the rest
  439. hr = CSecurityInformation::SetSecurity(si, pSD);
  440. }
  441. if (S_OK == hr && m_pCompareData)
  442. {
  443. // If we successfully wrote it, then it doesn't conflict anymore
  444. m_pCompareData->siConflict &= ~(si);
  445. if (0 == m_pCompareData->siConflict)
  446. {
  447. delete m_pCompareData;
  448. m_pCompareData = NULL;
  449. }
  450. }
  451. return hr;
  452. }
  453. STDMETHODIMP
  454. CNTFSSecurity::PropertySheetPageCallback(HWND hwnd,
  455. UINT uMsg,
  456. SI_PAGE_TYPE uPage)
  457. {
  458. HRESULT hr;
  459. LPUINT pidsPrompt = NULL;
  460. LPCTSTR pszFile2 = NULL;
  461. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::PropertySheetPageCallback");
  462. hr = CSecurityInformation::PropertySheetPageCallback(hwnd, uMsg, uPage);
  463. if (uMsg == PSPCB_SI_INITDIALOG)
  464. {
  465. WaitForComparison();
  466. SECURITY_INFORMATION si = 0;
  467. if (m_pCompareData != NULL)
  468. {
  469. if (SUCCEEDED(m_pCompareData->hrResult))
  470. {
  471. switch (uPage)
  472. {
  473. case SI_PAGE_PERM:
  474. case SI_PAGE_ADVPERM:
  475. pidsPrompt = &m_pCompareData->idsDaclPrompt;
  476. pszFile2 = m_pCompareData->pszDaclConflict;
  477. si = DACL_SECURITY_INFORMATION;
  478. break;
  479. case SI_PAGE_AUDIT:
  480. pidsPrompt = &m_pCompareData->idsSaclPrompt;
  481. pszFile2 = m_pCompareData->pszSaclConflict;
  482. si = SACL_SECURITY_INFORMATION;
  483. break;
  484. }
  485. }
  486. if (pidsPrompt != NULL && *pidsPrompt != 0)
  487. {
  488. if (IDYES != MsgPopup(hwnd,
  489. MAKEINTRESOURCE(*pidsPrompt),
  490. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  491. MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND,
  492. g_hInstance,
  493. m_pszObjectName,
  494. pszFile2))
  495. {
  496. // Don't want to prompt again for the same thing, so set
  497. // this to zero.
  498. *pidsPrompt = 0;
  499. hr = E_FAIL; // abort
  500. TraceLeaveResult(hr);
  501. }
  502. // Don't want to prompt again for the same thing, so set
  503. // this to zero.
  504. *pidsPrompt = 0;
  505. //Reset the ACL
  506. // Build security descriptor with empty DACL and SACL
  507. SECURITY_DESCRIPTOR sdEmpty = {0};
  508. ACL aclEmpty = {0};
  509. if(!InitializeSecurityDescriptor(&sdEmpty, SECURITY_DESCRIPTOR_REVISION))
  510. {
  511. TraceLeaveResult(E_FAIL);
  512. }
  513. if(!InitializeAcl(&aclEmpty, sizeof(ACL), ACL_REVISION))
  514. {
  515. TraceLeaveResult(E_FAIL);
  516. }
  517. if(!SetSecurityDescriptorSacl(&sdEmpty, TRUE, &aclEmpty, FALSE))
  518. {
  519. TraceLeaveResult(E_FAIL);
  520. }
  521. if(!SetSecurityDescriptorDacl(&sdEmpty, TRUE, &aclEmpty, FALSE))
  522. {
  523. TraceLeaveResult(E_FAIL);
  524. }
  525. // Reset the DACL and/or SACL
  526. HANDLE hToken = INVALID_HANDLE_VALUE;
  527. DWORD dwPriv = SE_SECURITY_PRIVILEGE;
  528. if(SACL_SECURITY_INFORMATION == si)
  529. {
  530. hToken = EnablePrivileges(&dwPriv, 1);
  531. }
  532. hr = SetSecurity(si, (PSECURITY_DESCRIPTOR)&sdEmpty);
  533. if(SACL_SECURITY_INFORMATION == si)
  534. {
  535. // Release the privilege we enabled
  536. ReleasePrivileges(hToken);
  537. }
  538. if(FAILED(hr))
  539. {
  540. MsgPopup(hwnd,
  541. MAKEINTRESOURCE((si == DACL_SECURITY_INFORMATION) ? IDS_RESET_PERM_FAILED : IDS_RESET_AUDITING_FAILED),
  542. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  543. MB_OK | MB_ICONWARNING | MB_SETFOREGROUND,
  544. g_hInstance);
  545. return E_FAIL;
  546. }
  547. }
  548. else if(si & m_pCompareData->siConflict)
  549. {
  550. //This situation arises when advanced page is brought up first time.
  551. //We show the message prompting for reset, and either user selects no
  552. //or resets fails. In both the cases conflict is still there and we
  553. //disable the page. Now we close the advanced page and bring it up again.
  554. //This time we won't show any prompt as we have already cleared the prompt
  555. //So we should check if there is still conflict and if yes we should disable
  556. //page.
  557. TraceLeaveResult(E_FAIL);
  558. }
  559. }
  560. }
  561. TraceLeaveResult(hr);
  562. }
  563. STDMETHODIMP
  564. CNTFSSecurity::WriteObjectSecurity(LPCTSTR pszObject,
  565. SECURITY_INFORMATION si,
  566. PSECURITY_DESCRIPTOR pSD)
  567. {
  568. DWORD dwErr;
  569. HRESULT hr = S_OK;
  570. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::WriteObjectSecurity");
  571. TraceAssert(pszObject != NULL);
  572. TraceAssert(si != 0);
  573. TraceAssert(pSD != NULL);
  574. hr = CSecurityInformation::WriteObjectSecurity(pszObject, si, pSD);
  575. // This is a workaround. SetNamedSecurityInfo[Ex] fails with Access Denied
  576. // in some cases where the owner is trying to set the DACL
  577. // (typically because the propagation code can't enumerate the children
  578. // because owner doesn't have read access).
  579. if (E_ACCESSDENIED == hr)
  580. {
  581. SECURITY_DESCRIPTOR_CONTROL wControl = 0;
  582. DWORD dwRevision;
  583. // If we're setting a protected DACL (i.e. no inheritance from parent)
  584. // try SetFileSecurity. If that works, try the full write again.
  585. //
  586. // Don't do this if the DACL isn't protected since it may fool the
  587. // system into thinking that this is a downlevel DACL that should
  588. // be protected. That would be very confusing to the user.
  589. GetSecurityDescriptorControl(pSD, &wControl, &dwRevision);
  590. if ((si & DACL_SECURITY_INFORMATION)
  591. && ((wControl & SE_DACL_PROTECTED) || (m_dwSIFlags & SI_NO_ACL_PROTECT))
  592. && SetFileSecurity(pszObject, si, pSD))
  593. {
  594. hr = CSecurityInformation::WriteObjectSecurity(pszObject, si, pSD);
  595. }
  596. }
  597. //
  598. // Notify the shell if we change permissions on a folder (48220)
  599. //
  600. if (SUCCEEDED(hr) &&
  601. (si & DACL_SECURITY_INFORMATION) &&
  602. (m_dwSIFlags & SI_CONTAINER))
  603. {
  604. SHChangeNotify(SHCNE_UPDATEDIR,
  605. SHCNF_PATH | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT,
  606. pszObject,
  607. NULL);
  608. }
  609. TraceLeaveResult(hr);
  610. }
  611. void
  612. CNTFSSecurity::WaitForComparison()
  613. {
  614. if (m_hCompareThread != NULL)
  615. {
  616. DWORD dwResult;
  617. HCURSOR hcurPrevious = SetCursor(LoadCursor(NULL, IDC_WAIT));
  618. SetThreadPriority(m_hCompareThread, THREAD_PRIORITY_HIGHEST);
  619. dwResult = WaitForSingleObject(m_hCompareThread, INFINITE);
  620. if (m_pCompareData != NULL)
  621. {
  622. if (GetExitCodeThread(m_hCompareThread, &dwResult))
  623. {
  624. m_pCompareData->hrResult = dwResult;
  625. }
  626. else
  627. {
  628. dwResult = GetLastError();
  629. m_pCompareData->hrResult = HRESULT_FROM_WIN32(dwResult);
  630. }
  631. }
  632. CloseHandle(m_hCompareThread);
  633. m_hCompareThread = NULL;
  634. SetCursor(hcurPrevious);
  635. }
  636. }
  637. DWORD WINAPI
  638. CNTFSSecurity::NTFSReadSD(LPCTSTR pszObject,
  639. SECURITY_INFORMATION si,
  640. PSECURITY_DESCRIPTOR* ppSD)
  641. {
  642. DWORD dwLength = 0;
  643. DWORD dwErr = 0;
  644. TraceEnter(TRACE_NTFSSI | TRACE_NTFSCOMPARE, "CNTFSSecurity::NTFSReadSD");
  645. TraceAssert(pszObject != NULL);
  646. TraceAssert(si != 0);
  647. TraceAssert(ppSD != NULL);
  648. //
  649. // Assume that required privileges have already been
  650. // enabled, if appropriate.
  651. //
  652. GetFileSecurity(pszObject, si, NULL, 0, &dwLength);
  653. if (dwLength)
  654. {
  655. *ppSD = LocalAlloc(LPTR, dwLength);
  656. if (*ppSD &&
  657. !GetFileSecurity(pszObject, si, *ppSD, dwLength, &dwLength))
  658. {
  659. dwErr = GetLastError();
  660. LocalFree(*ppSD);
  661. *ppSD = NULL;
  662. }
  663. }
  664. else
  665. dwErr = GetLastError();
  666. TraceLeaveValue(dwErr);
  667. }
  668. DWORD WINAPI
  669. CNTFSSecurity::NTFSCompareThreadProc(LPVOID pvData)
  670. {
  671. PNTFS_COMPARE_DATA pCompareData = (PNTFS_COMPARE_DATA)pvData;
  672. HRESULT hr;
  673. DWORD dwSIFlags;
  674. BOOL bOwnerConflict = FALSE;
  675. BOOL bSaclConflict = FALSE;
  676. BOOL bDaclConflict = FALSE;
  677. TraceEnter(TRACE_NTFSCOMPARE, "CNTFSSecurity::NTFSCompareThreadProc");
  678. TraceAssert(pCompareData != NULL);
  679. dwSIFlags = pCompareData->dwSIFlags;
  680. hr = DPA_CompareSecurityIntersection(pCompareData->hItemList,
  681. NTFSReadSD,
  682. (dwSIFlags & SI_EDIT_OWNER) ? &bOwnerConflict : NULL,
  683. NULL,
  684. (dwSIFlags & SI_EDIT_AUDITS) ? &bSaclConflict : NULL,
  685. &bDaclConflict,
  686. NULL,
  687. NULL,
  688. &pCompareData->pszSaclConflict,
  689. &pCompareData->pszDaclConflict,
  690. &pCompareData->pszFailureMsg,
  691. &pCompareData->bAbortThread);
  692. if (SUCCEEDED(hr))
  693. {
  694. if (bOwnerConflict)
  695. pCompareData->siConflict |= OWNER_SECURITY_INFORMATION;
  696. if (bSaclConflict)
  697. pCompareData->siConflict |= SACL_SECURITY_INFORMATION;
  698. if (bDaclConflict)
  699. pCompareData->siConflict |= DACL_SECURITY_INFORMATION;
  700. if (pCompareData->pszSaclConflict)
  701. pCompareData->idsSaclPrompt = IDS_BAD_SACL_INTERSECTION;
  702. if (pCompareData->pszDaclConflict)
  703. pCompareData->idsDaclPrompt = IDS_BAD_DACL_INTERSECTION;
  704. }
  705. TraceLeaveResult(hr);
  706. }
  707. HRESULT
  708. CNTFSSecurity::SetSecurityLocal(SECURITY_INFORMATION si,
  709. PSECURITY_DESCRIPTOR pSD,
  710. LPBOOL pbNotAllApplied)
  711. {
  712. HRESULT hr = S_OK;
  713. HCURSOR hcur = NULL;
  714. int i;
  715. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::SetSecurityLocal");
  716. TraceAssert(pSD != NULL);
  717. TraceAssert(SI_CONTAINER & m_dwSIFlags);
  718. SECURITY_DESCRIPTOR_CONTROL wSDControl = 0;
  719. DWORD dwRevision;
  720. PSID psidOwner = NULL;
  721. PSID psidGroup = NULL;
  722. PACL pDacl = NULL;
  723. PACL pSacl = NULL;
  724. BOOL bDefaulted;
  725. BOOL bPresent;
  726. DWORD dwErr = ERROR_SUCCESS;
  727. NTFS_PF_DATA dataPF;
  728. if( !si )
  729. TraceLeaveResult(hr);
  730. dataPF.si = si;
  731. dataPF.pNTFSSec = this;
  732. dataPF.pSD = pSD;
  733. dataPF.bCancel = FALSE;
  734. //
  735. // Get pointers to various security descriptor parts for
  736. // calling SetNamedSecurityInfo
  737. //
  738. GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision);
  739. GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted);
  740. GetSecurityDescriptorGroup(pSD, &psidGroup, &bDefaulted);
  741. GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted);
  742. GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted);
  743. if (si & DACL_SECURITY_INFORMATION)
  744. {
  745. if (wSDControl & SE_DACL_PROTECTED)
  746. si |= PROTECTED_DACL_SECURITY_INFORMATION;
  747. else
  748. si |= UNPROTECTED_DACL_SECURITY_INFORMATION;
  749. }
  750. if (si & SACL_SECURITY_INFORMATION)
  751. {
  752. if (wSDControl & SE_SACL_PROTECTED)
  753. si |= PROTECTED_SACL_SECURITY_INFORMATION;
  754. else
  755. si |= UNPROTECTED_SACL_SECURITY_INFORMATION;
  756. }
  757. if (pbNotAllApplied)
  758. *pbNotAllApplied = FALSE;
  759. if (NULL == m_hItemList)
  760. ExitGracefully(hr, E_UNEXPECTED, "CSecurityInformation not initialized");
  761. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  762. CreateProgressDialog(si);
  763. for (i = 0; i < DPA_GetPtrCount(m_hItemList); i++)
  764. {
  765. LPTSTR pszItem = (LPTSTR)DPA_FastGetPtr(m_hItemList, i);
  766. if (NULL != pszItem)
  767. {
  768. dwErr = TreeResetNamedSecurityInfo( pszItem,
  769. SE_FILE_OBJECT,
  770. si,
  771. si & OWNER_SECURITY_INFORMATION ? psidOwner : NULL,
  772. NULL,
  773. si & DACL_SECURITY_INFORMATION ? pDacl : NULL,
  774. si & SACL_SECURITY_INFORMATION ? pSacl : NULL,
  775. FALSE,
  776. ProgressFunction,
  777. ProgressInvokeEveryObject,
  778. (PVOID)&dataPF);
  779. hr = HRESULT_FROM_WIN32(dwErr);
  780. FailGracefully(hr, "Unable to recursively apply security");
  781. }
  782. else
  783. {
  784. hr = E_UNEXPECTED;
  785. break;
  786. }
  787. }
  788. exit_gracefully:
  789. if(dataPF.bCancel)
  790. {
  791. //User Pressed Cancel Button. Show a warning message showing implication of
  792. //canceling the operation.
  793. UINT idMsg = IDS_PERMISSION_PROPOGATION_CANCEL;
  794. if(si & SACL_SECURITY_INFORMATION)
  795. idMsg = IDS_AUDITING_PROPOGATION_CANCEL;
  796. else if(si & OWNER_SECURITY_INFORMATION)
  797. idMsg = IDS_OWNER_PROPOGATION_CANCEL;
  798. MsgPopup(m_hwndPopupOwner,
  799. MAKEINTRESOURCE(idMsg),
  800. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  801. MB_ICONWARNING | MB_SETFOREGROUND,
  802. g_hInstance);
  803. if(pbNotAllApplied)
  804. *pbNotAllApplied = TRUE;
  805. //We should read the success in this case since
  806. //we don't know the state of acl. If we return S_OK
  807. //security page will reread the acl and display the
  808. //correct acl
  809. hr = S_OK;
  810. }
  811. CloseProgressDialog();
  812. if (m_psdOwnerFullControl)
  813. {
  814. LocalFree(m_psdOwnerFullControl);
  815. m_psdOwnerFullControl = NULL;
  816. }
  817. if (hcur)
  818. {
  819. SetCursor(hcur);
  820. }
  821. TraceLeaveResult(hr);
  822. }
  823. BOOL PathIsDotOrDotDot(LPCTSTR pszPath)
  824. {
  825. if (TEXT('.') == *pszPath++)
  826. {
  827. if (TEXT('\0') == *pszPath || (TEXT('.') == *pszPath && TEXT('\0') == *(pszPath + 1)))
  828. return TRUE;
  829. }
  830. return FALSE;
  831. }
  832. typedef struct _APPLY_SECURITY_ERROR
  833. {
  834. HWND hwndParent;
  835. DWORD dwError;
  836. LPCTSTR pszPath;
  837. UINT idMsg[1]; // Optional, string resource IDs (only 1 used so far)
  838. } APPLY_SECURITY_ERROR;
  839. INT_PTR CALLBACK
  840. FailedApplySecurityProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  841. {
  842. switch (uMsg)
  843. {
  844. case WM_INITDIALOG:
  845. {
  846. APPLY_SECURITY_ERROR* pae = (APPLY_SECURITY_ERROR*)lParam;
  847. LPTSTR pszT = NULL;
  848. // Set the message string(s)
  849. for (int i = 0; i < ARRAYSIZE(pae->idMsg); i++)
  850. {
  851. if (pae->idMsg[i])
  852. {
  853. LoadStringAlloc(&pszT, g_hInstance, pae->idMsg[i]);
  854. if (pszT)
  855. SetDlgItemText(hDlg, (IDC_MSG1 + i), pszT);
  856. LocalFreeString(&pszT);
  857. }
  858. }
  859. // Compact the path so it fits on the dialog
  860. PathSetDlgItemPath(hDlg, IDC_FILENAME, pae->pszPath);
  861. // Set the error text
  862. if (NOERROR != pae->dwError)
  863. {
  864. if (!GetSystemErrorText(&pszT, pae->dwError))
  865. FormatStringID(&pszT, g_hInstance, IDS_FMT_UNKNOWN_ERROR, pae->dwError);
  866. if (pszT)
  867. SetDlgItemText(hDlg, IDC_ERROR_TXT, pszT);
  868. LocalFreeString(&pszT);
  869. }
  870. break;
  871. }
  872. case WM_COMMAND:
  873. {
  874. WORD wControlID = GET_WM_COMMAND_ID(wParam, lParam);
  875. switch (wControlID)
  876. {
  877. case IDOK:
  878. case IDCANCEL:
  879. EndDialog(hDlg, wControlID);
  880. return TRUE;
  881. }
  882. break;
  883. }
  884. }
  885. return FALSE;
  886. }
  887. //
  888. // This function displays the "An error has occured [Continue] [Cancel]" message
  889. //
  890. // Returns IDOK or IDCANCEL
  891. //
  892. int
  893. FailedApplySecurityErrorDlg(HWND hWndParent, APPLY_SECURITY_ERROR* pae)
  894. {
  895. //The progress dialog must be visible when this error message is shown
  896. if( !IsWindowVisible( pae->hwndParent ) )
  897. {
  898. ShowWindow( pae->hwndParent, SW_SHOW);
  899. SetForegroundWindow( pae->hwndParent );
  900. }
  901. return (int)DialogBoxParam(g_hInstance,
  902. MAKEINTRESOURCE(IDD_SET_SECURITY_ERROR),
  903. hWndParent,
  904. FailedApplySecurityProc,
  905. (LPARAM)pae);
  906. }
  907. #ifndef IDA_APPLYATTRIBS
  908. // this is the resource ID of an AVI in shell32.dll. If shell32's
  909. // resource ID's change, we'll get the wrong animation (or none).
  910. // We could steal the AVI and build it into rshx32's resources, except
  911. // it almost doubles the size of rshx32.dll (~35k to ~57k).
  912. #define IDA_APPLYATTRIBS 165 // animation for applying file attributes
  913. #endif
  914. void
  915. CNTFSSecurity::CreateProgressDialog(SECURITY_INFORMATION si)
  916. {
  917. HRESULT hr = S_OK;
  918. // Shouldn't be necessary, but just in case
  919. CloseProgressDialog();
  920. // m_hwndOwner is the toplevel parent of the Security page
  921. m_hwndPopupOwner = GetLastActivePopup(m_hwndOwner);
  922. __try
  923. {
  924. hr = CoCreateInstance(CLSID_ProgressDialog,
  925. NULL,
  926. CLSCTX_INPROC_SERVER,
  927. IID_IProgressDialog,
  928. (void**)&m_pProgressDlg);
  929. }
  930. __except(EXCEPTION_EXECUTE_HANDLER)
  931. {
  932. hr = E_OUTOFMEMORY;
  933. }
  934. if (SUCCEEDED(hr) && m_pProgressDlg)
  935. {
  936. WCHAR szT[256];
  937. UINT ids = IDS_RESET_SEC_TREE;
  938. IOleWindow *pWindow;
  939. LoadStringW(g_hInstance, IDS_PROPPAGE_TITLE, szT, ARRAYSIZE(szT));
  940. m_pProgressDlg->SetTitle(szT);
  941. switch (si)
  942. {
  943. case OWNER_SECURITY_INFORMATION:
  944. ids = IDS_RESET_OWNER_TREE;
  945. break;
  946. case SACL_SECURITY_INFORMATION:
  947. ids = IDS_RESET_SACL_TREE;
  948. break;
  949. case DACL_SECURITY_INFORMATION:
  950. ids = IDS_RESET_DACL_TREE;
  951. break;
  952. }
  953. LoadStringW(g_hInstance, ids, szT, ARRAYSIZE(szT));
  954. m_pProgressDlg->SetLine(1, szT, FALSE, NULL);
  955. m_pProgressDlg->SetAnimation(GetModuleHandle(TEXT("shell32.dll")), IDA_APPLYATTRIBS);
  956. m_pProgressDlg->StartProgressDialog(m_hwndPopupOwner,
  957. NULL,
  958. PROGDLG_MODAL | PROGDLG_NOTIME
  959. | PROGDLG_NOMINIMIZE | PROGDLG_NOPROGRESSBAR,
  960. NULL);
  961. if (SUCCEEDED(m_pProgressDlg->QueryInterface(IID_IOleWindow, (void**)&pWindow)))
  962. {
  963. pWindow->GetWindow(&m_hwndPopupOwner);
  964. pWindow->Release();
  965. }
  966. }
  967. }
  968. void
  969. CNTFSSecurity::CloseProgressDialog(void)
  970. {
  971. m_hwndPopupOwner = NULL;
  972. if (m_pProgressDlg)
  973. {
  974. m_pProgressDlg->StopProgressDialog();
  975. m_pProgressDlg->Release();
  976. m_pProgressDlg = NULL;
  977. }
  978. }
  979. HRESULT
  980. CNTFSSecurity::SetProgress(LPTSTR pszFile)
  981. {
  982. USES_CONVERSION;
  983. if (m_pProgressDlg)
  984. {
  985. m_pProgressDlg->SetLine(2, T2W(pszFile), TRUE, NULL);
  986. if (m_pProgressDlg->HasUserCancelled())
  987. return S_FALSE;
  988. }
  989. return S_OK;
  990. }
  991. HRESULT
  992. CNTFSSecurity::BuildOwnerFullControlSD(PSECURITY_DESCRIPTOR pSD)
  993. {
  994. PSID psidOwner;
  995. BOOL bDefaulted;
  996. DWORD dwAclLen;
  997. PACL pAcl;
  998. PACE_HEADER pAce;
  999. if (!GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted))
  1000. return E_INVALIDARG;
  1001. dwAclLen = sizeof(ACL)
  1002. + sizeof(KNOWN_ACE) - sizeof(DWORD)
  1003. + GetLengthSid(psidOwner);
  1004. m_psdOwnerFullControl = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH + dwAclLen);
  1005. if (NULL == m_psdOwnerFullControl)
  1006. return E_OUTOFMEMORY;
  1007. HRESULT hr = S_OK;
  1008. if(!InitializeSecurityDescriptor(m_psdOwnerFullControl, SECURITY_DESCRIPTOR_REVISION))
  1009. {
  1010. DWORD dwErr = GetLastError();
  1011. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"InitializeSecurityDescriptor failed");
  1012. }
  1013. pAcl = (PACL)ByteOffset(m_psdOwnerFullControl, SECURITY_DESCRIPTOR_MIN_LENGTH);
  1014. if(!InitializeAcl(pAcl, dwAclLen, ACL_REVISION))
  1015. {
  1016. DWORD dwErr = GetLastError();
  1017. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"InitializeAcl failed");
  1018. }
  1019. if(!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidOwner))
  1020. {
  1021. DWORD dwErr = GetLastError();
  1022. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"AddAccessAllowedAce failed");
  1023. }
  1024. pAce = (PACE_HEADER)FirstAce(pAcl);
  1025. pAce->AceFlags = INHERIT_FULL;
  1026. if(!SetSecurityDescriptorDacl(m_psdOwnerFullControl, TRUE, pAcl, TRUE))
  1027. {
  1028. DWORD dwErr = GetLastError();
  1029. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"SetSecurityDescriptorDacl failed");
  1030. }
  1031. exit_gracefully:
  1032. if(FAILED(hr))
  1033. {
  1034. if (m_psdOwnerFullControl)
  1035. LocalFree(m_psdOwnerFullControl);
  1036. m_psdOwnerFullControl = NULL;
  1037. }
  1038. TraceLeaveResult(hr);
  1039. }
  1040. VOID ProgressFunction(IN LPWSTR pObjectName,
  1041. IN DWORD Status,
  1042. IN OUT PPROG_INVOKE_SETTING pInvokeSetting ,
  1043. IN PVOID Args,
  1044. BOOL bSecuritySet)
  1045. {
  1046. TraceEnter(TRACE_NTFSCOMPARE, "ProgressFunction");
  1047. TraceAssert(pObjectName != NULL);
  1048. TraceAssert(Args);
  1049. PNTFS_PF_DATA pfData = (PNTFS_PF_DATA)(Args);
  1050. CNTFSSecurity * pNTFSSec = pfData->pNTFSSec;
  1051. HRESULT hr = S_OK;
  1052. if( Status == ERROR_SUCCESS )
  1053. {
  1054. //
  1055. // Notify the shell if we change permissions on a folder (48220)
  1056. //
  1057. if ( pfData->si & DACL_SECURITY_INFORMATION)
  1058. {
  1059. SHChangeNotify(SHCNE_UPDATEDIR,
  1060. SHCNF_PATH | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT,
  1061. pObjectName,
  1062. NULL);
  1063. }
  1064. }
  1065. else
  1066. {
  1067. //
  1068. //This means it was able to set security on this folder and some error
  1069. //occured while enumerating child.
  1070. //
  1071. if(bSecuritySet && pfData->si & OWNER_SECURITY_INFORMATION)
  1072. {
  1073. BOOL bIsFile = FALSE;
  1074. hr = pNTFSSec->GiveOwnerFullControl(pObjectName, pfData->pSD, &bIsFile);
  1075. if(hr == S_OK)
  1076. {
  1077. //
  1078. //Look for comment in SetFileSecurityUsingNTName
  1079. //
  1080. *pInvokeSetting = bIsFile ?ProgressInvokeEveryObject:ProgressRetryOperation;
  1081. TraceLeaveVoid();
  1082. }
  1083. }
  1084. APPLY_SECURITY_ERROR ae = { ((PNTFS_PF_DATA)(Args))->pNTFSSec->GetHwndPopOwner(),HRESULT_FROM_WIN32(Status), pObjectName, { 0 } };
  1085. if (IDOK != FailedApplySecurityErrorDlg( ((PNTFS_PF_DATA)(Args))->pNTFSSec->GetHwndPopOwner(), &ae))
  1086. {
  1087. *pInvokeSetting = ProgressCancelOperation; // abort
  1088. pfData->bCancel = TRUE;
  1089. }
  1090. else
  1091. {
  1092. *pInvokeSetting = ProgressInvokeEveryObject; // continue
  1093. }
  1094. }
  1095. if (S_FALSE == ((PNTFS_PF_DATA)(Args))->pNTFSSec->SetProgress(pObjectName))
  1096. {
  1097. *pInvokeSetting = ProgressCancelOperation;
  1098. pfData->bCancel = TRUE;
  1099. }
  1100. TraceLeaveVoid();
  1101. }
  1102. HRESULT CNTFSSecurity::GiveOwnerFullControl( LPCWSTR lpszFileName,
  1103. PSECURITY_DESCRIPTOR pSD,
  1104. BOOL *pbIsFile)
  1105. {
  1106. HRESULT hr = S_OK;
  1107. // Ask the user if they want to grant themselves access
  1108. if (!m_psdOwnerFullControl)
  1109. {
  1110. if (IDYES == MsgPopup(m_hwndPopupOwner,
  1111. MAKEINTRESOURCE(IDS_FMT_WRITE_OWNER_ERR),
  1112. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  1113. MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND,
  1114. g_hInstance,
  1115. lpszFileName))
  1116. {
  1117. BuildOwnerFullControlSD(pSD);
  1118. }
  1119. else
  1120. {
  1121. // Continue without enumerating this folder
  1122. TraceLeaveResult(S_FALSE);
  1123. }
  1124. }
  1125. if (m_psdOwnerFullControl)
  1126. {
  1127. // Give the owner Full Control
  1128. // Use SetFileSecurity
  1129. if(!SetFileSecurityUsingNTName(lpszFileName,
  1130. m_psdOwnerFullControl,
  1131. pbIsFile))
  1132. {
  1133. hr = E_FAIL;
  1134. }
  1135. if(SUCCEEDED(hr))
  1136. TraceLeaveResult(S_OK);
  1137. }
  1138. TraceLeaveResult(S_FALSE);
  1139. }
  1140. GENERIC_MAPPING STANDARD_FILE_MAP=
  1141. {
  1142. FILE_GENERIC_READ,
  1143. FILE_GENERIC_WRITE,
  1144. FILE_GENERIC_EXECUTE,
  1145. FILE_ALL_ACCESS
  1146. };
  1147. STDMETHODIMP
  1148. CNTFSSecurity::GetInheritSource( SECURITY_INFORMATION si,
  1149. PACL pACL,
  1150. PINHERITED_FROM *ppInheritArray)
  1151. {
  1152. HRESULT hr = S_OK;
  1153. LPTSTR pszItem;
  1154. DWORD dwErr = ERROR_SUCCESS;
  1155. PINHERITED_FROM pTempInherit = NULL;
  1156. PINHERITED_FROM pTempInherit2 = NULL;
  1157. LPWSTR pStrTemp = NULL;
  1158. BOOL bFreeInheritedFromArray = FALSE;
  1159. TraceEnter(TRACE_SI, "CNTFSSecurity::GetInheritSource");
  1160. TraceAssert(pACL != 0);
  1161. TraceAssert(ppInheritArray != NULL);
  1162. if( pACL == NULL || ppInheritArray == NULL )
  1163. ExitGracefully(hr, E_POINTER, "Invalid Parameters, CNTFSSecurity::GetInheritSource");
  1164. // Get the name of the first item
  1165. pszItem = (LPTSTR)DPA_GetPtr(m_hItemList, 0);
  1166. if (NULL == pszItem)
  1167. ExitGracefully(hr, E_UNEXPECTED, "CSecurityInformation not initialized");
  1168. pTempInherit = (PINHERITED_FROM)LocalAlloc( LPTR, sizeof(INHERITED_FROM)*pACL->AceCount);
  1169. if(pTempInherit == NULL)
  1170. ExitGracefully(hr, E_OUTOFMEMORY,"OUT of Memory");
  1171. dwErr = GetInheritanceSource(pszItem,
  1172. SE_FILE_OBJECT,
  1173. si,
  1174. m_dwSIFlags & SI_CONTAINER,
  1175. NULL,
  1176. 0,
  1177. pACL,
  1178. NULL,
  1179. &STANDARD_FILE_MAP,
  1180. pTempInherit);
  1181. hr = HRESULT_FROM_WIN32(dwErr);
  1182. FailGracefully( hr, "GetInheritanceSource Failed");
  1183. bFreeInheritedFromArray = TRUE;
  1184. DWORD nSize;
  1185. UINT i;
  1186. nSize = sizeof(INHERITED_FROM)*pACL->AceCount;
  1187. for(i = 0; i < pACL->AceCount; ++i)
  1188. {
  1189. if(pTempInherit[i].AncestorName)
  1190. nSize += StringByteSize(pTempInherit[i].AncestorName);
  1191. }
  1192. pTempInherit2 = (PINHERITED_FROM)LocalAlloc( LPTR, nSize );
  1193. if(pTempInherit2 == NULL)
  1194. ExitGracefully(hr, E_OUTOFMEMORY,"OUT of Memory");
  1195. pStrTemp = (LPWSTR)(pTempInherit2 + pACL->AceCount);
  1196. for(i = 0; i < pACL->AceCount; ++i)
  1197. {
  1198. pTempInherit2[i].GenerationGap = pTempInherit[i].GenerationGap;
  1199. if(pTempInherit[i].AncestorName)
  1200. {
  1201. pTempInherit2[i].AncestorName = pStrTemp;
  1202. wcscpy(pStrTemp,pTempInherit[i].AncestorName);
  1203. pStrTemp += (wcslen(pTempInherit[i].AncestorName)+1);
  1204. }
  1205. }
  1206. exit_gracefully:
  1207. if(bFreeInheritedFromArray)
  1208. FreeInheritedFromArray(pTempInherit, pACL->AceCount,NULL);
  1209. if(SUCCEEDED(hr))
  1210. {
  1211. *ppInheritArray = pTempInherit2;
  1212. }
  1213. if(pTempInherit)
  1214. LocalFree(pTempInherit);
  1215. TraceLeaveResult(hr);
  1216. }
  1217. BOOL SetFileSecurityUsingNTName(IN LPCWSTR pszFileName,
  1218. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1219. IN PBOOL pbIsFile)
  1220. {
  1221. //
  1222. //Set File Security
  1223. //
  1224. if (!SetFileSecurity(pszFileName,
  1225. DACL_SECURITY_INFORMATION,
  1226. pSecurityDescriptor))
  1227. return FALSE;
  1228. //When resetting the owner, if user is not owner and he doesn't have any permissions
  1229. //TreeResetNamedSecurityInfo cannot determine if its a file or directory. So after
  1230. //setting the ownership TreeResetNamedSecurityInfo tries to enumerate the file, which fails
  1231. //as there is nothing to enumerate and TreeResetNamedSecurityInfo calls ProgressFunction
  1232. //which stamps a FullControl on the file and ask TreeResetNamedSecurityInfo to retry
  1233. //which again fails and we are infinte loop. The way to break this is ask TreeResetNamedSecurityInfo
  1234. //not to retry if its a file. which is what we are doing below. Ugly, yup.
  1235. //
  1236. //default we assume its a file
  1237. //if its a file and we assume its a dir, we are infinite loop
  1238. //if its a dir and we assume its a file, we skip that dir which
  1239. //is lesser evil
  1240. //
  1241. *pbIsFile = TRUE;
  1242. //
  1243. //Open the file for Generic_read
  1244. //
  1245. WIN32_FILE_ATTRIBUTE_DATA fileAttrData;
  1246. if (GetFileAttributesEx(pszFileName,
  1247. GetFileExInfoStandard,
  1248. &fileAttrData))
  1249. {
  1250. if(fileAttrData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1251. *pbIsFile = FALSE;
  1252. }
  1253. return TRUE;
  1254. }