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.

1553 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 PUNICODE_STRING pFileName,
  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. DWORD
  149. GetCurrentToken(DWORD dwDesiredAccess, PHANDLE phToken)
  150. {
  151. DWORD dwErr = NOERROR;
  152. if (!OpenThreadToken(GetCurrentThread(), dwDesiredAccess, TRUE, phToken)
  153. && !OpenProcessToken(GetCurrentProcess(), dwDesiredAccess, phToken))
  154. {
  155. dwErr = GetLastError();
  156. }
  157. return dwErr;
  158. }
  159. ///////////////////////////////////////////////////////////
  160. //
  161. // Constructor/destructor
  162. //
  163. ///////////////////////////////////////////////////////////
  164. NTFS_COMPARE_DATA::~NTFS_COMPARE_DATA()
  165. {
  166. LocalFreeString(&pszSaclConflict);
  167. LocalFreeString(&pszDaclConflict);
  168. }
  169. CNTFSSecurity::CNTFSSecurity(SE_OBJECT_TYPE seType)
  170. : CSecurityInformation(seType)
  171. {
  172. }
  173. CNTFSSecurity::~CNTFSSecurity()
  174. {
  175. if (m_pCompareData != NULL)
  176. m_pCompareData->bAbortThread = TRUE;
  177. WaitForComparison();
  178. delete m_pCompareData;
  179. }
  180. STDMETHODIMP
  181. CNTFSSecurity::Initialize(HDPA hItemList,
  182. DWORD dwFlags,
  183. LPTSTR pszServer,
  184. LPTSTR pszObject)
  185. {
  186. HRESULT hr;
  187. //
  188. // If we're editing the owner on a folder, turn on the Recurse button.
  189. //
  190. if (dwFlags & SI_CONTAINER)
  191. {
  192. if ((dwFlags & (SI_EDIT_OWNER | SI_OWNER_READONLY)) == SI_EDIT_OWNER)
  193. dwFlags |= SI_OWNER_RECURSE;
  194. if (!(dwFlags & SI_READONLY))
  195. dwFlags |= SI_RESET_DACL_TREE;
  196. if (dwFlags & SI_EDIT_AUDITS)
  197. dwFlags |= SI_RESET_SACL_TREE;
  198. }
  199. //
  200. // Let the base class do its thing
  201. //
  202. hr = CSecurityInformation::Initialize(hItemList,
  203. dwFlags,
  204. pszServer,
  205. pszObject);
  206. //
  207. // If multiple selection, create thread to compare security descriptors
  208. //
  209. if (m_hItemList && DPA_GetPtrCount(m_hItemList) > 1)
  210. {
  211. m_pCompareData = new NTFS_COMPARE_DATA(m_hItemList, m_dwSIFlags);
  212. if (m_pCompareData != NULL)
  213. {
  214. DWORD dwID;
  215. m_hCompareThread = CreateThread(NULL,
  216. 0,
  217. NTFSCompareThreadProc,
  218. m_pCompareData,
  219. CREATE_SUSPENDED,
  220. &dwID);
  221. if (m_hCompareThread != NULL)
  222. {
  223. SetThreadPriority(m_hCompareThread, THREAD_PRIORITY_BELOW_NORMAL);
  224. ResumeThread(m_hCompareThread);
  225. }
  226. else
  227. {
  228. delete m_pCompareData;
  229. m_pCompareData = NULL;
  230. }
  231. }
  232. }
  233. return hr;
  234. }
  235. ///////////////////////////////////////////////////////////
  236. //
  237. // ISecurityInformation methods
  238. //
  239. ///////////////////////////////////////////////////////////
  240. STDMETHODIMP
  241. CNTFSSecurity::GetAccessRights(const GUID* /*pguidObjectType*/,
  242. DWORD dwFlags,
  243. PSI_ACCESS *ppAccesses,
  244. ULONG *pcAccesses,
  245. ULONG *piDefaultAccess)
  246. {
  247. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::GetAccessRights");
  248. TraceAssert(ppAccesses != NULL);
  249. TraceAssert(pcAccesses != NULL);
  250. TraceAssert(piDefaultAccess != NULL);
  251. //
  252. //Don't Show delete subfolder and files for files or
  253. //when applyonto is files only
  254. //
  255. if(IsFile())
  256. siNTFSAccesses[iNTFSDelChildAccess].dwFlags = 0;
  257. else
  258. siNTFSAccesses[iNTFSDelChildAccess].dwFlags = SI_ACCESS_SPECIFIC;
  259. *ppAccesses = siNTFSAccesses;
  260. *pcAccesses = ARRAYSIZE(siNTFSAccesses);
  261. *piDefaultAccess = iNTFSDefAccess;
  262. TraceLeaveResult(S_OK);
  263. }
  264. GENERIC_MAPPING NTFSMap =
  265. {
  266. FILE_GENERIC_READ_,
  267. FILE_GENERIC_WRITE_,
  268. FILE_GENERIC_EXECUTE_,
  269. FILE_GENERIC_ALL_
  270. };
  271. STDMETHODIMP
  272. CNTFSSecurity::MapGeneric(const GUID* /*pguidObjectType*/,
  273. UCHAR * /*pAceFlags*/,
  274. ACCESS_MASK *pmask)
  275. {
  276. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::MapGeneric");
  277. TraceAssert(pmask != NULL);
  278. MapGenericMask(pmask, &NTFSMap);
  279. *pmask &= ~SYNCHRONIZE;
  280. TraceLeaveResult(S_OK);
  281. }
  282. STDMETHODIMP
  283. CNTFSSecurity::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
  284. ULONG *pcInheritTypes)
  285. {
  286. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::GetInheritTypes");
  287. TraceAssert(ppInheritTypes != NULL);
  288. TraceAssert(pcInheritTypes != NULL);
  289. if (m_dwSIFlags & SI_CONTAINER)
  290. {
  291. *ppInheritTypes = siNTFSInheritTypes;
  292. *pcInheritTypes = ARRAYSIZE(siNTFSInheritTypes);
  293. TraceLeaveResult(S_OK);
  294. }
  295. TraceLeaveResult(E_NOTIMPL);
  296. }
  297. STDMETHODIMP
  298. CNTFSSecurity::GetSecurity(SECURITY_INFORMATION si,
  299. PSECURITY_DESCRIPTOR *ppSD,
  300. BOOL fDefault)
  301. {
  302. HRESULT hr = S_OK;
  303. SECURITY_INFORMATION siConflict = 0;
  304. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::GetSecurity");
  305. TraceAssert(si != 0);
  306. TraceAssert(ppSD != NULL);
  307. *ppSD = NULL;
  308. if (fDefault)
  309. {
  310. #ifdef SUPPORT_NTFS_DEFAULT
  311. hr = GetDefaultSecurity(si, ppSD);
  312. ExitGracefully(hr, hr, "Returning default security descriptor");
  313. #else
  314. ExitGracefully(hr, E_NOTIMPL, "Default security descriptor not supported");
  315. #endif
  316. }
  317. WaitForComparison();
  318. if (m_pCompareData != NULL)
  319. {
  320. // Of the bits requested (si) figure out which ones
  321. // conflict and which ones don't.
  322. // First check DACL and SACL
  323. SECURITY_INFORMATION siAcl = si & m_pCompareData->siConflict;
  324. siAcl &= (SACL_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION);
  325. if (siAcl)
  326. {
  327. // To get here, we've already told the user there is a conflict
  328. // and they said to reset the ACL(s) and continue.
  329. // Build security descriptor with empty DACL and NULL SACL
  330. SECURITY_DESCRIPTOR sdEmpty = {0};
  331. ACL aclEmpty = {0};
  332. InitializeSecurityDescriptor(&sdEmpty, SECURITY_DESCRIPTOR_REVISION);
  333. InitializeAcl(&aclEmpty, sizeof(ACL), ACL_REVISION);
  334. SetSecurityDescriptorSacl(&sdEmpty, TRUE, &aclEmpty, FALSE);
  335. SetSecurityDescriptorDacl(&sdEmpty, TRUE, &aclEmpty, FALSE);
  336. // Reset the DACL and/or SACL
  337. hr = SetSecurity(siAcl, (PSECURITY_DESCRIPTOR)&sdEmpty);
  338. }
  339. // Note that SetSecurity will free m_pCompareData if there are
  340. // no more conflicts, so check the pointer again here.
  341. if (m_pCompareData != NULL)
  342. siConflict = si & m_pCompareData->siConflict;
  343. }
  344. // Read it from the first item.
  345. hr = CSecurityInformation::GetSecurity(si, ppSD, fDefault);
  346. if (SUCCEEDED(hr) && siConflict != 0)
  347. {
  348. //
  349. // Clear out any of the parts that conflict
  350. //
  351. PISECURITY_DESCRIPTOR psd = (PISECURITY_DESCRIPTOR)*ppSD;
  352. TraceAssert(psd != NULL);
  353. if (siConflict & OWNER_SECURITY_INFORMATION)
  354. {
  355. psd->Owner = NULL;
  356. }
  357. if (siConflict & GROUP_SECURITY_INFORMATION)
  358. {
  359. psd->Group = NULL;
  360. }
  361. // The following can happen if there was an error resetting ACLs above
  362. if (siConflict & SACL_SECURITY_INFORMATION)
  363. {
  364. psd->Control &= ~SE_SACL_PRESENT;
  365. psd->Sacl = NULL;
  366. }
  367. if (siConflict & DACL_SECURITY_INFORMATION)
  368. {
  369. psd->Control &= ~SE_DACL_PRESENT;
  370. psd->Dacl = NULL;
  371. }
  372. }
  373. exit_gracefully:
  374. TraceLeaveResult(hr);
  375. }
  376. //
  377. // See comments about SYNCHRONIZE at the top of this file
  378. //
  379. void
  380. FixSynchronizeAccess(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
  381. {
  382. if (NULL != pSD && 0 != (si & DACL_SECURITY_INFORMATION))
  383. {
  384. BOOL bPresent;
  385. BOOL bDefault;
  386. PACL pDacl = NULL;
  387. GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefault);
  388. if (pDacl)
  389. {
  390. PACE_HEADER pAce;
  391. int i;
  392. for (i = 0, pAce = (PACE_HEADER)FirstAce(pDacl);
  393. i < pDacl->AceCount;
  394. i++, pAce = (PACE_HEADER)NextAce(pAce))
  395. {
  396. if (ACCESS_ALLOWED_ACE_TYPE == pAce->AceType)
  397. ((PKNOWN_ACE)pAce)->Mask |= SYNCHRONIZE;
  398. }
  399. }
  400. }
  401. }
  402. STDMETHODIMP
  403. CNTFSSecurity::SetSecurity(SECURITY_INFORMATION si,
  404. PSECURITY_DESCRIPTOR pSD)
  405. {
  406. HRESULT hr = S_OK;
  407. if (si & DACL_SECURITY_INFORMATION)
  408. FixSynchronizeAccess(si, pSD);
  409. if(!SetAclOnRemoteNetworkDrive(m_hItemList,
  410. si,
  411. pSD,
  412. GetLastActivePopup(m_hwndOwner)))
  413. {
  414. return S_FALSE;
  415. }
  416. //
  417. // If we need to recursively set the Owner, get the Owner &
  418. // Group from pSD.
  419. //
  420. if (si & ( SI_OWNER_RECURSE | SI_RESET_DACL_TREE | SI_RESET_SACL_TREE ) )
  421. {
  422. si = si & (~( SI_OWNER_RECURSE | SI_RESET_DACL_TREE | SI_RESET_SACL_TREE ));
  423. hr = SetSecurityLocal(si, pSD, NULL);
  424. // Remember whether the user cancelled, since hr gets
  425. // reset when we call the base class below.
  426. }
  427. else
  428. {
  429. // See comments about SYNCHRONIZE at the top of this file
  430. // Call the base class to do the rest
  431. hr = CSecurityInformation::SetSecurity(si, pSD);
  432. }
  433. if (S_OK == hr && m_pCompareData)
  434. {
  435. // If we successfully wrote it, then it doesn't conflict anymore
  436. m_pCompareData->siConflict &= ~(si);
  437. if (0 == m_pCompareData->siConflict)
  438. {
  439. delete m_pCompareData;
  440. m_pCompareData = NULL;
  441. }
  442. }
  443. return hr;
  444. }
  445. STDMETHODIMP
  446. CNTFSSecurity::PropertySheetPageCallback(HWND hwnd,
  447. UINT uMsg,
  448. SI_PAGE_TYPE uPage)
  449. {
  450. HRESULT hr;
  451. LPUINT pidsPrompt = NULL;
  452. LPCTSTR pszFile2 = NULL;
  453. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::PropertySheetPageCallback");
  454. hr = CSecurityInformation::PropertySheetPageCallback(hwnd, uMsg, uPage);
  455. if (uMsg == PSPCB_SI_INITDIALOG)
  456. {
  457. WaitForComparison();
  458. if (m_pCompareData != NULL)
  459. {
  460. if (SUCCEEDED(m_pCompareData->hrResult))
  461. {
  462. switch (uPage)
  463. {
  464. case SI_PAGE_PERM:
  465. case SI_PAGE_ADVPERM:
  466. pidsPrompt = &m_pCompareData->idsDaclPrompt;
  467. pszFile2 = m_pCompareData->pszDaclConflict;
  468. break;
  469. case SI_PAGE_AUDIT:
  470. pidsPrompt = &m_pCompareData->idsSaclPrompt;
  471. pszFile2 = m_pCompareData->pszSaclConflict;
  472. break;
  473. }
  474. }
  475. }
  476. if (pidsPrompt != NULL && *pidsPrompt != 0)
  477. {
  478. if (IDYES != MsgPopup(hwnd,
  479. MAKEINTRESOURCE(*pidsPrompt),
  480. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  481. MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND,
  482. g_hInstance,
  483. m_pszObjectName,
  484. pszFile2))
  485. {
  486. hr = E_FAIL; // abort
  487. }
  488. // Don't want to prompt again for the same thing, so set
  489. // this to zero.
  490. *pidsPrompt = 0;
  491. }
  492. }
  493. TraceLeaveResult(hr);
  494. }
  495. #ifdef SUPPORT_NTFS_DEFAULT
  496. HRESULT
  497. CNTFSSecurity::GetParentSecurity(SECURITY_INFORMATION si,
  498. PSECURITY_DESCRIPTOR *ppSD)
  499. {
  500. HRESULT hr = S_OK;
  501. LPTSTR pszItem;
  502. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::GetParentSecurity");
  503. TraceAssert(m_hItemList && DPA_GetPtrCount(m_hItemList));
  504. // Get the name of the first item
  505. pszItem = (LPTSTR)DPA_GetPtr(m_hItemList, 0);
  506. if (NULL != pszItem && !PathIsRoot(pszItem))
  507. {
  508. TCHAR szParent[MAX_PATH];
  509. lstrcpyn(szParent, pszItem, ARRAYSIZE(szParent));
  510. PathRemoveFileSpec(szParent);
  511. // Read the parent DACL/SACL
  512. hr = ReadObjectSecurity(szParent, si, ppSD);
  513. }
  514. TraceLeaveResult(hr);
  515. }
  516. STDMETHODIMP
  517. CNTFSSecurity::GetDefaultSecurity(SECURITY_INFORMATION si,
  518. PSECURITY_DESCRIPTOR *ppSD)
  519. {
  520. HRESULT hr = S_OK;
  521. DWORD dwErr;
  522. PSECURITY_DESCRIPTOR psdParent = NULL;
  523. SECURITY_INFORMATION siLocal;
  524. HANDLE hToken = INVALID_HANDLE_VALUE;
  525. ULONG ulAutoInheritFlags = (SEF_DACL_AUTO_INHERIT |
  526. SEF_SACL_AUTO_INHERIT |
  527. SEF_AVOID_PRIVILEGE_CHECK |
  528. SEF_AVOID_OWNER_CHECK);
  529. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::GetDefaultSecurity");
  530. TraceAssert(m_hItemList && DPA_GetPtrCount(m_hItemList));
  531. dwErr = GetCurrentToken(TOKEN_QUERY, &hToken);
  532. if (NOERROR != dwErr)
  533. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "Unable to get current token");
  534. // Only DACL and SACL get inherited
  535. siLocal = si & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
  536. if (siLocal)
  537. {
  538. hr = GetParentSecurity(si, &psdParent);
  539. FailGracefully(hr, "Unable to get parent security descriptor");
  540. }
  541. #if(_WIN32_WINNT >= 0x0500)
  542. if(!CreatePrivateObjectSecurityEx(psdParent,// Inherited ACEs come from here
  543. NULL,
  544. ppSD,
  545. NULL,
  546. !!(m_dwSIFlags & SI_CONTAINER),
  547. ulAutoInheritFlags,
  548. hToken, // owner & group come from here
  549. &NTFSMap))
  550. #else
  551. if(!CreatePrivateObjectSecurity(psdParent,
  552. NULL,
  553. ppSD,
  554. !!(m_dwSIFlags & SI_CONTAINER),
  555. hToken,
  556. &NTFSMap))
  557. #endif
  558. {
  559. dwErr = GetLastError();
  560. hr = HRESULT_FROM_WIN32(dwErr);
  561. }
  562. exit_gracefully:
  563. if (hToken != INVALID_HANDLE_VALUE)
  564. CloseHandle(hToken);
  565. if (psdParent)
  566. LocalFree(psdParent);
  567. TraceLeaveResult(hr);
  568. }
  569. #endif // SUPPORT_NTFS_DEFAULT
  570. #ifdef DONT_USE_ACLAPI
  571. STDMETHODIMP
  572. CNTFSSecurity::ReadObjectSecurity(LPCTSTR pszObject,
  573. SECURITY_INFORMATION si,
  574. PSECURITY_DESCRIPTOR *ppSD)
  575. {
  576. DWORD dwErr;
  577. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::ReadObjectSecurity");
  578. dwErr = NTFSReadSD(pszObject, si, ppSD);
  579. TraceLeaveResult(HRESULT_FROM_WIN32(dwErr));
  580. }
  581. #endif // DONT_USE_ACLAPI
  582. STDMETHODIMP
  583. CNTFSSecurity::WriteObjectSecurity(LPCTSTR pszObject,
  584. SECURITY_INFORMATION si,
  585. PSECURITY_DESCRIPTOR pSD)
  586. {
  587. DWORD dwErr;
  588. HRESULT hr = S_OK;
  589. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::WriteObjectSecurity");
  590. TraceAssert(pszObject != NULL);
  591. TraceAssert(si != 0);
  592. TraceAssert(pSD != NULL);
  593. #ifdef DONT_USE_ACLAPI
  594. //
  595. // Assume that required privileges have already been
  596. // enabled, if appropriate.
  597. //
  598. if (!SetFileSecurity(pszObject, si, pSD))
  599. {
  600. dwErr = GetLastError();
  601. hr = HRESULT_FROM_WIN32(dwErr);
  602. }
  603. #else
  604. hr = CSecurityInformation::WriteObjectSecurity(pszObject, si, pSD);
  605. // This is a workaround. SetNamedSecurityInfo[Ex] fails with Access Denied
  606. // in some cases where the owner is trying to set the DACL
  607. // (typically because the propagation code can't enumerate the children
  608. // because owner doesn't have read access).
  609. if (E_ACCESSDENIED == hr)
  610. {
  611. SECURITY_DESCRIPTOR_CONTROL wControl = 0;
  612. DWORD dwRevision;
  613. // If we're setting a protected DACL (i.e. no inheritance from parent)
  614. // try SetFileSecurity. If that works, try the full write again.
  615. //
  616. // Don't do this if the DACL isn't protected since it may fool the
  617. // system into thinking that this is a downlevel DACL that should
  618. // be protected. That would be very confusing to the user.
  619. GetSecurityDescriptorControl(pSD, &wControl, &dwRevision);
  620. if ((si & DACL_SECURITY_INFORMATION)
  621. && ((wControl & SE_DACL_PROTECTED) || (m_dwSIFlags & SI_NO_ACL_PROTECT))
  622. && SetFileSecurity(pszObject, si, pSD))
  623. {
  624. hr = CSecurityInformation::WriteObjectSecurity(pszObject, si, pSD);
  625. }
  626. }
  627. #endif // DONT_USE_ACLAPI
  628. //
  629. // Notify the shell if we change permissions on a folder (48220)
  630. //
  631. if (SUCCEEDED(hr) &&
  632. (si & DACL_SECURITY_INFORMATION) &&
  633. (m_dwSIFlags & SI_CONTAINER))
  634. {
  635. SHChangeNotify(SHCNE_UPDATEDIR,
  636. SHCNF_PATH | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT,
  637. pszObject,
  638. NULL);
  639. }
  640. TraceLeaveResult(hr);
  641. }
  642. void
  643. CNTFSSecurity::WaitForComparison()
  644. {
  645. if (m_hCompareThread != NULL)
  646. {
  647. DWORD dwResult;
  648. HCURSOR hcurPrevious = SetCursor(LoadCursor(NULL, IDC_WAIT));
  649. SetThreadPriority(m_hCompareThread, THREAD_PRIORITY_HIGHEST);
  650. dwResult = WaitForSingleObject(m_hCompareThread, INFINITE);
  651. if (m_pCompareData != NULL)
  652. {
  653. if (GetExitCodeThread(m_hCompareThread, &dwResult))
  654. {
  655. m_pCompareData->hrResult = dwResult;
  656. }
  657. else
  658. {
  659. dwResult = GetLastError();
  660. m_pCompareData->hrResult = HRESULT_FROM_WIN32(dwResult);
  661. }
  662. }
  663. CloseHandle(m_hCompareThread);
  664. m_hCompareThread = NULL;
  665. SetCursor(hcurPrevious);
  666. }
  667. }
  668. DWORD WINAPI
  669. CNTFSSecurity::NTFSReadSD(LPCTSTR pszObject,
  670. SECURITY_INFORMATION si,
  671. PSECURITY_DESCRIPTOR* ppSD)
  672. {
  673. DWORD dwLength = 0;
  674. DWORD dwErr = 0;
  675. TraceEnter(TRACE_NTFSSI | TRACE_NTFSCOMPARE, "CNTFSSecurity::NTFSReadSD");
  676. TraceAssert(pszObject != NULL);
  677. TraceAssert(si != 0);
  678. TraceAssert(ppSD != NULL);
  679. //
  680. // Assume that required privileges have already been
  681. // enabled, if appropriate.
  682. //
  683. GetFileSecurity(pszObject, si, NULL, 0, &dwLength);
  684. if (dwLength)
  685. {
  686. *ppSD = LocalAlloc(LPTR, dwLength);
  687. if (*ppSD &&
  688. !GetFileSecurity(pszObject, si, *ppSD, dwLength, &dwLength))
  689. {
  690. dwErr = GetLastError();
  691. LocalFree(*ppSD);
  692. *ppSD = NULL;
  693. }
  694. }
  695. else
  696. dwErr = GetLastError();
  697. TraceLeaveValue(dwErr);
  698. }
  699. DWORD WINAPI
  700. CNTFSSecurity::NTFSCompareThreadProc(LPVOID pvData)
  701. {
  702. PNTFS_COMPARE_DATA pCompareData = (PNTFS_COMPARE_DATA)pvData;
  703. HRESULT hr;
  704. DWORD dwSIFlags;
  705. BOOL bOwnerConflict = FALSE;
  706. BOOL bSaclConflict = FALSE;
  707. BOOL bDaclConflict = FALSE;
  708. TraceEnter(TRACE_NTFSCOMPARE, "CNTFSSecurity::NTFSCompareThreadProc");
  709. TraceAssert(pCompareData != NULL);
  710. dwSIFlags = pCompareData->dwSIFlags;
  711. hr = DPA_CompareSecurityIntersection(pCompareData->hItemList,
  712. NTFSReadSD,
  713. (dwSIFlags & SI_EDIT_OWNER) ? &bOwnerConflict : NULL,
  714. NULL,
  715. (dwSIFlags & SI_EDIT_AUDITS) ? &bSaclConflict : NULL,
  716. &bDaclConflict,
  717. NULL,
  718. NULL,
  719. &pCompareData->pszSaclConflict,
  720. &pCompareData->pszDaclConflict,
  721. &pCompareData->bAbortThread);
  722. if (SUCCEEDED(hr))
  723. {
  724. if (bOwnerConflict)
  725. pCompareData->siConflict |= OWNER_SECURITY_INFORMATION;
  726. if (bSaclConflict)
  727. pCompareData->siConflict |= SACL_SECURITY_INFORMATION;
  728. if (bDaclConflict)
  729. pCompareData->siConflict |= DACL_SECURITY_INFORMATION;
  730. if (pCompareData->pszSaclConflict)
  731. pCompareData->idsSaclPrompt = IDS_BAD_SACL_INTERSECTION;
  732. if (pCompareData->pszDaclConflict)
  733. pCompareData->idsDaclPrompt = IDS_BAD_DACL_INTERSECTION;
  734. }
  735. TraceLeaveResult(hr);
  736. }
  737. HRESULT
  738. CNTFSSecurity::SetSecurityLocal(SECURITY_INFORMATION si,
  739. PSECURITY_DESCRIPTOR pSD,
  740. LPBOOL pbNotAllApplied)
  741. {
  742. HRESULT hr = S_OK;
  743. HCURSOR hcur = NULL;
  744. int i;
  745. TraceEnter(TRACE_NTFSSI, "CNTFSSecurity::SetSecurityLocal");
  746. TraceAssert(pSD != NULL);
  747. TraceAssert(SI_CONTAINER & m_dwSIFlags);
  748. SECURITY_DESCRIPTOR_CONTROL wSDControl = 0;
  749. DWORD dwRevision;
  750. PSID psidOwner = NULL;
  751. PSID psidGroup = NULL;
  752. PACL pDacl = NULL;
  753. PACL pSacl = NULL;
  754. BOOL bDefaulted;
  755. BOOL bPresent;
  756. DWORD dwErr = ERROR_SUCCESS;
  757. NTFS_PF_DATA dataPF;
  758. if( !si )
  759. TraceLeaveResult(hr);
  760. dataPF.si = si;
  761. dataPF.pNTFSSec = this;
  762. dataPF.pSD = pSD;
  763. dataPF.bCancel = FALSE;
  764. //
  765. // Get pointers to various security descriptor parts for
  766. // calling SetNamedSecurityInfo
  767. //
  768. GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision);
  769. GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted);
  770. GetSecurityDescriptorGroup(pSD, &psidGroup, &bDefaulted);
  771. GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted);
  772. GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted);
  773. if (si & DACL_SECURITY_INFORMATION)
  774. {
  775. if (wSDControl & SE_DACL_PROTECTED)
  776. si |= PROTECTED_DACL_SECURITY_INFORMATION;
  777. else
  778. si |= UNPROTECTED_DACL_SECURITY_INFORMATION;
  779. }
  780. if (si & SACL_SECURITY_INFORMATION)
  781. {
  782. if (wSDControl & SE_SACL_PROTECTED)
  783. si |= PROTECTED_SACL_SECURITY_INFORMATION;
  784. else
  785. si |= UNPROTECTED_SACL_SECURITY_INFORMATION;
  786. }
  787. if (pbNotAllApplied)
  788. *pbNotAllApplied = FALSE;
  789. if (NULL == m_hItemList)
  790. ExitGracefully(hr, E_UNEXPECTED, "CSecurityInformation not initialized");
  791. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  792. CreateProgressDialog(si);
  793. for (i = 0; i < DPA_GetPtrCount(m_hItemList); i++)
  794. {
  795. LPTSTR pszItem = (LPTSTR)DPA_FastGetPtr(m_hItemList, i);
  796. if (NULL != pszItem)
  797. {
  798. dwErr = TreeResetNamedSecurityInfo( pszItem,
  799. SE_FILE_OBJECT,
  800. si,
  801. si & OWNER_SECURITY_INFORMATION ? psidOwner : NULL,
  802. NULL,
  803. si & DACL_SECURITY_INFORMATION ? pDacl : NULL,
  804. si & SACL_SECURITY_INFORMATION ? pSacl : NULL,
  805. FALSE,
  806. ProgressFunction,
  807. ProgressInvokeEveryObject,
  808. (PVOID)&dataPF);
  809. hr = HRESULT_FROM_WIN32(dwErr);
  810. FailGracefully(hr, "Unable to recursively apply security");
  811. if(dataPF.bCancel)
  812. {
  813. if(pbNotAllApplied)
  814. *pbNotAllApplied = TRUE;
  815. ExitGracefully(hr, S_FALSE, "User canceled the operation");
  816. }
  817. }
  818. else
  819. {
  820. hr = E_UNEXPECTED;
  821. break;
  822. }
  823. }
  824. exit_gracefully:
  825. CloseProgressDialog();
  826. if (m_psdOwnerFullControl)
  827. {
  828. LocalFree(m_psdOwnerFullControl);
  829. m_psdOwnerFullControl = NULL;
  830. }
  831. if (hcur)
  832. {
  833. SetCursor(hcur);
  834. }
  835. TraceLeaveResult(hr);
  836. }
  837. BOOL PathIsDotOrDotDot(LPCTSTR pszPath)
  838. {
  839. if (TEXT('.') == *pszPath++)
  840. {
  841. if (TEXT('\0') == *pszPath || (TEXT('.') == *pszPath && TEXT('\0') == *(pszPath + 1)))
  842. return TRUE;
  843. }
  844. return FALSE;
  845. }
  846. typedef struct _APPLY_SECURITY_ERROR
  847. {
  848. HWND hwndParent;
  849. DWORD dwError;
  850. LPCTSTR pszPath;
  851. UINT idMsg[1]; // Optional, string resource IDs (only 1 used so far)
  852. } APPLY_SECURITY_ERROR;
  853. INT_PTR CALLBACK
  854. FailedApplySecurityProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  855. {
  856. switch (uMsg)
  857. {
  858. case WM_INITDIALOG:
  859. {
  860. APPLY_SECURITY_ERROR* pae = (APPLY_SECURITY_ERROR*)lParam;
  861. LPTSTR pszT = NULL;
  862. // Set the message string(s)
  863. for (int i = 0; i < ARRAYSIZE(pae->idMsg); i++)
  864. {
  865. if (pae->idMsg[i])
  866. {
  867. LoadStringAlloc(&pszT, g_hInstance, pae->idMsg[i]);
  868. if (pszT)
  869. SetDlgItemText(hDlg, (IDC_MSG1 + i), pszT);
  870. LocalFreeString(&pszT);
  871. }
  872. }
  873. // Compact the path so it fits on the dialog
  874. PathSetDlgItemPath(hDlg, IDC_FILENAME, pae->pszPath);
  875. // Set the error text
  876. if (NOERROR != pae->dwError)
  877. {
  878. if (!GetSystemErrorText(&pszT, pae->dwError))
  879. FormatStringID(&pszT, g_hInstance, IDS_FMT_UNKNOWN_ERROR, pae->dwError);
  880. if (pszT)
  881. SetDlgItemText(hDlg, IDC_ERROR_TXT, pszT);
  882. LocalFreeString(&pszT);
  883. }
  884. break;
  885. }
  886. case WM_COMMAND:
  887. {
  888. WORD wControlID = GET_WM_COMMAND_ID(wParam, lParam);
  889. switch (wControlID)
  890. {
  891. case IDOK:
  892. case IDCANCEL:
  893. EndDialog(hDlg, wControlID);
  894. return TRUE;
  895. }
  896. break;
  897. }
  898. }
  899. return FALSE;
  900. }
  901. //
  902. // This function displays the "An error has occured [Continue] [Cancel]" message
  903. //
  904. // Returns IDOK or IDCANCEL
  905. //
  906. int
  907. FailedApplySecurityErrorDlg(HWND hWndParent, APPLY_SECURITY_ERROR* pae)
  908. {
  909. //The progress dialog must be visible when this error message is shown
  910. if( !IsWindowVisible( pae->hwndParent ) )
  911. {
  912. ShowWindow( pae->hwndParent, SW_SHOW);
  913. SetForegroundWindow( pae->hwndParent );
  914. }
  915. return (int)DialogBoxParam(g_hInstance,
  916. MAKEINTRESOURCE(IDD_SET_SECURITY_ERROR),
  917. hWndParent,
  918. FailedApplySecurityProc,
  919. (LPARAM)pae);
  920. }
  921. #ifndef IDA_APPLYATTRIBS
  922. // this is the resource ID of an AVI in shell32.dll. If shell32's
  923. // resource ID's change, we'll get the wrong animation (or none).
  924. // We could steal the AVI and build it into rshx32's resources, except
  925. // it almost doubles the size of rshx32.dll (~35k to ~57k).
  926. #define IDA_APPLYATTRIBS 165 // animation for applying file attributes
  927. #endif
  928. void
  929. CNTFSSecurity::CreateProgressDialog(SECURITY_INFORMATION si)
  930. {
  931. HRESULT hr = S_OK;
  932. // Shouldn't be necessary, but just in case
  933. CloseProgressDialog();
  934. // m_hwndOwner is the toplevel parent of the Security page
  935. m_hwndPopupOwner = GetLastActivePopup(m_hwndOwner);
  936. __try
  937. {
  938. hr = CoCreateInstance(CLSID_ProgressDialog,
  939. NULL,
  940. CLSCTX_INPROC_SERVER,
  941. IID_IProgressDialog,
  942. (void**)&m_pProgressDlg);
  943. }
  944. __except(EXCEPTION_EXECUTE_HANDLER)
  945. {
  946. hr = E_OUTOFMEMORY;
  947. }
  948. if (SUCCEEDED(hr) && m_pProgressDlg)
  949. {
  950. WCHAR szT[256];
  951. UINT ids = IDS_RESET_SEC_TREE;
  952. IOleWindow *pWindow;
  953. LoadStringW(g_hInstance, IDS_PROPPAGE_TITLE, szT, ARRAYSIZE(szT));
  954. m_pProgressDlg->SetTitle(szT);
  955. switch (si)
  956. {
  957. case OWNER_SECURITY_INFORMATION:
  958. ids = IDS_RESET_OWNER_TREE;
  959. break;
  960. case SACL_SECURITY_INFORMATION:
  961. ids = IDS_RESET_SACL_TREE;
  962. break;
  963. case DACL_SECURITY_INFORMATION:
  964. ids = IDS_RESET_DACL_TREE;
  965. break;
  966. }
  967. LoadStringW(g_hInstance, ids, szT, ARRAYSIZE(szT));
  968. m_pProgressDlg->SetLine(1, szT, FALSE, NULL);
  969. m_pProgressDlg->SetAnimation(GetModuleHandle(TEXT("shell32.dll")), IDA_APPLYATTRIBS);
  970. m_pProgressDlg->StartProgressDialog(m_hwndPopupOwner,
  971. NULL,
  972. PROGDLG_MODAL | PROGDLG_NOTIME
  973. | PROGDLG_NOMINIMIZE | PROGDLG_NOPROGRESSBAR,
  974. NULL);
  975. if (SUCCEEDED(m_pProgressDlg->QueryInterface(IID_IOleWindow, (void**)&pWindow)))
  976. {
  977. pWindow->GetWindow(&m_hwndPopupOwner);
  978. pWindow->Release();
  979. }
  980. }
  981. }
  982. void
  983. CNTFSSecurity::CloseProgressDialog(void)
  984. {
  985. m_hwndPopupOwner = NULL;
  986. if (m_pProgressDlg)
  987. {
  988. m_pProgressDlg->StopProgressDialog();
  989. m_pProgressDlg->Release();
  990. m_pProgressDlg = NULL;
  991. }
  992. }
  993. HRESULT
  994. CNTFSSecurity::SetProgress(LPTSTR pszFile)
  995. {
  996. USES_CONVERSION;
  997. if (m_pProgressDlg)
  998. {
  999. m_pProgressDlg->SetLine(2, T2W(pszFile), TRUE, NULL);
  1000. if (m_pProgressDlg->HasUserCancelled())
  1001. return S_FALSE;
  1002. }
  1003. return S_OK;
  1004. }
  1005. HRESULT
  1006. CNTFSSecurity::BuildOwnerFullControlSD(PSECURITY_DESCRIPTOR pSD)
  1007. {
  1008. PSID psidOwner;
  1009. BOOL bDefaulted;
  1010. DWORD dwAclLen;
  1011. PACL pAcl;
  1012. PACE_HEADER pAce;
  1013. if (!GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted))
  1014. return E_INVALIDARG;
  1015. dwAclLen = sizeof(ACL)
  1016. + sizeof(KNOWN_ACE) - sizeof(DWORD)
  1017. + GetLengthSid(psidOwner);
  1018. m_psdOwnerFullControl = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH + dwAclLen);
  1019. if (NULL == m_psdOwnerFullControl)
  1020. return E_OUTOFMEMORY;
  1021. InitializeSecurityDescriptor(m_psdOwnerFullControl, SECURITY_DESCRIPTOR_REVISION);
  1022. pAcl = (PACL)ByteOffset(m_psdOwnerFullControl, SECURITY_DESCRIPTOR_MIN_LENGTH);
  1023. InitializeAcl(pAcl, dwAclLen, ACL_REVISION);
  1024. AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidOwner);
  1025. pAce = (PACE_HEADER)FirstAce(pAcl);
  1026. pAce->AceFlags = INHERIT_FULL;
  1027. SetSecurityDescriptorDacl(m_psdOwnerFullControl, TRUE, pAcl, TRUE);
  1028. return S_OK;
  1029. }
  1030. VOID ProgressFunction(IN LPWSTR pObjectName,
  1031. IN DWORD Status,
  1032. IN OUT PPROG_INVOKE_SETTING pInvokeSetting ,
  1033. IN PVOID Args,
  1034. BOOL bSecuritySet)
  1035. {
  1036. TraceEnter(TRACE_NTFSCOMPARE, "ProgressFunction");
  1037. TraceAssert(pObjectName != NULL);
  1038. TraceAssert(Args);
  1039. PNTFS_PF_DATA pfData = (PNTFS_PF_DATA)(Args);
  1040. CNTFSSecurity * pNTFSSec = pfData->pNTFSSec;
  1041. HRESULT hr = S_OK;
  1042. if( Status == ERROR_SUCCESS )
  1043. {
  1044. //
  1045. // Notify the shell if we change permissions on a folder (48220)
  1046. //
  1047. if ( pfData->si & DACL_SECURITY_INFORMATION)
  1048. {
  1049. SHChangeNotify(SHCNE_UPDATEDIR,
  1050. SHCNF_PATH | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT,
  1051. pObjectName,
  1052. NULL);
  1053. }
  1054. }
  1055. else
  1056. {
  1057. //
  1058. //This means it was able to set security on this folder and some error
  1059. //occured while enumerating child.
  1060. //
  1061. if(bSecuritySet && pfData->si & OWNER_SECURITY_INFORMATION)
  1062. {
  1063. BOOL bIsFile = FALSE;
  1064. hr = pNTFSSec->GiveOwnerFullControl(pObjectName, pfData->pSD, &bIsFile);
  1065. if(hr == S_OK)
  1066. {
  1067. //
  1068. //Look for comment in SetFileSecurityUsingNTName
  1069. //
  1070. *pInvokeSetting = bIsFile ?ProgressInvokeEveryObject:ProgressRetryOperation;
  1071. TraceLeaveVoid();
  1072. }
  1073. }
  1074. APPLY_SECURITY_ERROR ae = { ((PNTFS_PF_DATA)(Args))->pNTFSSec->GetHwndPopOwner(),HRESULT_FROM_WIN32(Status), pObjectName, { 0 } };
  1075. if (IDOK != FailedApplySecurityErrorDlg( ((PNTFS_PF_DATA)(Args))->pNTFSSec->GetHwndPopOwner(), &ae))
  1076. {
  1077. *pInvokeSetting = ProgressCancelOperation; // abort
  1078. pfData->bCancel = TRUE;
  1079. }
  1080. else
  1081. {
  1082. *pInvokeSetting = ProgressInvokeEveryObject; // continue
  1083. }
  1084. }
  1085. if (S_FALSE == ((PNTFS_PF_DATA)(Args))->pNTFSSec->SetProgress(pObjectName))
  1086. *pInvokeSetting = ProgressCancelOperation;
  1087. TraceLeaveVoid();
  1088. }
  1089. HRESULT CNTFSSecurity::GiveOwnerFullControl( LPCWSTR lpszFileName,
  1090. PSECURITY_DESCRIPTOR pSD,
  1091. BOOL *pbIsFile)
  1092. {
  1093. HRESULT hr = S_OK;
  1094. // Ask the user if they want to grant themselves access
  1095. if (!m_psdOwnerFullControl)
  1096. {
  1097. if (IDYES == MsgPopup(m_hwndPopupOwner,
  1098. MAKEINTRESOURCE(IDS_FMT_WRITE_OWNER_ERR),
  1099. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  1100. MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND,
  1101. g_hInstance,
  1102. lpszFileName))
  1103. {
  1104. BuildOwnerFullControlSD(pSD);
  1105. }
  1106. else
  1107. {
  1108. // Continue without enumerating this folder
  1109. TraceLeaveResult(S_FALSE);
  1110. }
  1111. }
  1112. if (m_psdOwnerFullControl)
  1113. {
  1114. // Give the owner Full Control
  1115. // Use SetFileSecurity instead?, yes Use SetFileSecurity instead
  1116. UNICODE_STRING usFileName;
  1117. RtlInitUnicodeString(&usFileName,lpszFileName);
  1118. if(!SetFileSecurityUsingNTName(&usFileName,
  1119. m_psdOwnerFullControl,
  1120. pbIsFile))
  1121. {
  1122. hr = E_FAIL;
  1123. }
  1124. if(SUCCEEDED(hr))
  1125. TraceLeaveResult(S_OK);
  1126. }
  1127. TraceLeaveResult(S_FALSE);
  1128. }
  1129. GENERIC_MAPPING STANDARD_FILE_MAP=
  1130. {
  1131. FILE_GENERIC_READ,
  1132. FILE_GENERIC_WRITE,
  1133. FILE_GENERIC_EXECUTE,
  1134. FILE_ALL_ACCESS
  1135. };
  1136. STDMETHODIMP
  1137. CNTFSSecurity::GetInheritSource( SECURITY_INFORMATION si,
  1138. PACL pACL,
  1139. PINHERITED_FROM *ppInheritArray)
  1140. {
  1141. HRESULT hr = S_OK;
  1142. LPTSTR pszItem;
  1143. DWORD dwErr = ERROR_SUCCESS;
  1144. PINHERITED_FROM pTempInherit = NULL;
  1145. PINHERITED_FROM pTempInherit2 = NULL;
  1146. LPWSTR pStrTemp = NULL;
  1147. TraceEnter(TRACE_SI, "CNTFSSecurity::GetInheritSource");
  1148. TraceAssert(pACL != 0);
  1149. TraceAssert(ppInheritArray != NULL);
  1150. if( pACL == NULL || ppInheritArray == NULL )
  1151. ExitGracefully(hr, E_POINTER, "Invalid Parameters, CNTFSSecurity::GetInheritSource");
  1152. // Get the name of the first item
  1153. pszItem = (LPTSTR)DPA_GetPtr(m_hItemList, 0);
  1154. if (NULL == pszItem)
  1155. ExitGracefully(hr, E_UNEXPECTED, "CSecurityInformation not initialized");
  1156. pTempInherit = (PINHERITED_FROM)LocalAlloc( LPTR, sizeof(INHERITED_FROM)*pACL->AceCount);
  1157. if(pTempInherit == NULL)
  1158. ExitGracefully(hr, E_OUTOFMEMORY,"OUT of Memory");
  1159. dwErr = GetInheritanceSource(pszItem,
  1160. SE_FILE_OBJECT,
  1161. si,
  1162. m_dwSIFlags & SI_CONTAINER,
  1163. NULL,
  1164. 0,
  1165. pACL,
  1166. NULL,
  1167. &STANDARD_FILE_MAP,
  1168. pTempInherit);
  1169. hr = HRESULT_FROM_WIN32(dwErr);
  1170. FailGracefully( hr, "GetInheritanceSource Failed");
  1171. DWORD nSize;
  1172. UINT i;
  1173. nSize = sizeof(INHERITED_FROM)*pACL->AceCount;
  1174. for(i = 0; i < pACL->AceCount; ++i)
  1175. {
  1176. if(pTempInherit[i].AncestorName)
  1177. nSize += StringByteSize(pTempInherit[i].AncestorName);
  1178. }
  1179. pTempInherit2 = (PINHERITED_FROM)LocalAlloc( LPTR, nSize );
  1180. if(pTempInherit2 == NULL)
  1181. ExitGracefully(hr, E_OUTOFMEMORY,"OUT of Memory");
  1182. pStrTemp = (LPWSTR)(pTempInherit2 + pACL->AceCount);
  1183. for(i = 0; i < pACL->AceCount; ++i)
  1184. {
  1185. pTempInherit2[i].GenerationGap = pTempInherit[i].GenerationGap;
  1186. if(pTempInherit[i].AncestorName)
  1187. {
  1188. pTempInherit2[i].AncestorName = pStrTemp;
  1189. wcscpy(pStrTemp,pTempInherit[i].AncestorName);
  1190. pStrTemp += (wcslen(pTempInherit[i].AncestorName)+1);
  1191. }
  1192. }
  1193. exit_gracefully:
  1194. if(SUCCEEDED(hr))
  1195. {
  1196. //FreeInheritedFromArray(pTempInherit, pACL->AceCount,NULL);
  1197. *ppInheritArray = pTempInherit2;
  1198. }
  1199. if(pTempInherit)
  1200. LocalFree(pTempInherit);
  1201. TraceLeaveResult(hr);
  1202. }
  1203. BOOL SetFileSecurityUsingNTName(IN PUNICODE_STRING pFileName,
  1204. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1205. IN PBOOL pbIsFile)
  1206. {
  1207. NTSTATUS Status;
  1208. OBJECT_ATTRIBUTES Obja;
  1209. IO_STATUS_BLOCK IoStatusBlock;
  1210. HANDLE hFile = NULL;
  1211. InitializeObjectAttributes(
  1212. &Obja,
  1213. pFileName,
  1214. OBJ_CASE_INSENSITIVE,
  1215. NULL,
  1216. NULL
  1217. );
  1218. Status = NtOpenFile(
  1219. &hFile,
  1220. WRITE_DAC,
  1221. &Obja,
  1222. &IoStatusBlock,
  1223. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1224. FILE_OPEN_REPARSE_POINT
  1225. );
  1226. if ( Status == STATUS_INVALID_PARAMETER ) {
  1227. Status = NtOpenFile(
  1228. &hFile,
  1229. WRITE_DAC,
  1230. &Obja,
  1231. &IoStatusBlock,
  1232. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1233. 0
  1234. );
  1235. }
  1236. if (!NT_SUCCESS(Status)) {
  1237. return FALSE;
  1238. }
  1239. if (!SetKernelObjectSecurity(
  1240. hFile,
  1241. DACL_SECURITY_INFORMATION,
  1242. pSecurityDescriptor
  1243. ))
  1244. {
  1245. ASSERT(FALSE);
  1246. NtClose(hFile);
  1247. return FALSE;
  1248. }
  1249. NtClose(hFile);
  1250. //
  1251. //When resetting the owner, if user is not owner and he doesn't have any permissions
  1252. //TreeResetNamedSecurityInfo cannot determine if its a file or directory. So after
  1253. //setting the ownership TreeResetNamedSecurityInfo tries to enumerate the file, which fails
  1254. //as there is nothing to enumerate and TreeResetNamedSecurityInfo calls ProgressFunction
  1255. //which stamps a FullControl on the file and ask TreeResetNamedSecurityInfo to retry
  1256. //which again fails and we are infinte loop. The way to break this is ask TreeResetNamedSecurityInfo
  1257. //not to retry if its a file. which is what we are doing below. Ugly, yup.
  1258. //
  1259. //default we assume its a file
  1260. //if its a file and we assume its a dir, we are infinite loop
  1261. //if its a dir and we assume its a file, we skip that dir which
  1262. //is lesser evil
  1263. //
  1264. *pbIsFile = TRUE;
  1265. //
  1266. //Open the file for Generic_read
  1267. //
  1268. if (NT_SUCCESS(Status = NtOpenFile(
  1269. &hFile,
  1270. FILE_GENERIC_READ,
  1271. &Obja,
  1272. &IoStatusBlock,
  1273. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1274. 0
  1275. )))
  1276. {
  1277. //
  1278. // Query the attributes for the file/dir.
  1279. // In case of error, assume that it is a dir.
  1280. //
  1281. FILE_BASIC_INFORMATION BasicFileInfo;
  1282. if (NT_SUCCESS(Status = NtQueryInformationFile(
  1283. hFile,
  1284. &IoStatusBlock,
  1285. &BasicFileInfo,
  1286. sizeof(BasicFileInfo),
  1287. FileBasicInformation)))
  1288. {
  1289. if(BasicFileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1290. *pbIsFile = FALSE;
  1291. }
  1292. NtClose(hFile);
  1293. }
  1294. return TRUE;
  1295. }