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.

2483 lines
78 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 2000.
  5. //
  6. // File: shrpage2.cxx
  7. //
  8. // Contents: "Simple Sharing" shell property page extension
  9. //
  10. // History: 06-Oct-00 jeffreys Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "headers.hxx"
  14. #pragma hdrstop
  15. #include "resource.h"
  16. #include "helpids.h"
  17. #include "dlgnew.hxx"
  18. #include "cache.hxx"
  19. #include "share.hxx"
  20. #include "acl.hxx"
  21. #include "shrinfo.hxx"
  22. #include "shrpage2.hxx"
  23. #include "util.hxx"
  24. #include <userenv.h> // GetProfilesDirectory
  25. #include <sddl.h> // ConvertSidToStringSid, ConvertStringSecurityDescriptorToSecurityDescriptor
  26. #include <seopaque.h> // FirstAce, etc.
  27. #include <shgina.h> // ILocalMachine, ILogonUser
  28. #include <shpriv.h> // IHomeNetworkWizard
  29. extern GENERIC_MAPPING ShareMap; // permpage.cpp
  30. //
  31. // Forward Decl.
  32. //
  33. INT_PTR
  34. WarningDlgProc(
  35. IN HWND hWnd,
  36. IN UINT msg,
  37. IN WPARAM wParam,
  38. IN LPARAM lParam
  39. );
  40. // Security descriptor stuff used on this page
  41. //
  42. // (A;OICI;GA;;;SY) == Allow GENERIC_ALL to SYSTEM
  43. // (A;OICI;GA;;;%s) == Allow GENERIC_ALL to <current user>
  44. // (A;OICI;GA;;;BA) == Allow GENERIC_ALL to Builtin (local) Administrators
  45. // (A;OICI;GRGWGXSD;;;WD) == Allow Modify access to Everyone (Read, Write, eXecute, Delete)
  46. //
  47. // "OI" == Object Inherit (inherit onto files)
  48. // "CI" == Container Inherit (inherit onto subfolders)
  49. //
  50. // See sddl.h for more info.
  51. // Share permissions
  52. const WCHAR c_szFullShareSD[] = L"D:(A;;GRGWGXSD;;;WD)";
  53. const WCHAR c_szReadonlyShareSD[] = L"D:(A;;GRGX;;;WD)";
  54. // Folder permissions (used only on profile folders)
  55. const WCHAR c_szPrivateFolderSD[] = L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;%s)";
  56. const WCHAR c_szDefaultProfileSD[]= L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;%s)(A;OICI;GA;;;BA)";
  57. // Root folder permissions (see SDDLRoot in ds\security\services\scerpc\headers.h)
  58. const WCHAR c_szRootSDSecure[] = L"D:(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)(A;OICIIO;GA;;;CO)(A;CIOI;GRGX;;;BU)(A;CI;4;;;BU)(A;CIIO;2;;;BU)(A;;GRGX;;;WD)";
  59. const WCHAR c_szRootSDUnsecure[]= L"D:P(A;OICI;GA;;;WD)";
  60. typedef struct
  61. {
  62. SID sid; // contains 1 subauthority
  63. DWORD dwSubAuth[1]; // we currently need at most 2 subauthorities
  64. } _SID2;
  65. const SID g_WorldSid = {SID_REVISION,1,SECURITY_WORLD_SID_AUTHORITY, {SECURITY_WORLD_RID} };
  66. const _SID2 g_AdminsSid = {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ADMINS}};
  67. const _SID2 g_PowerUSid = {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_POWER_USERS}};
  68. const _SID2 g_UsersSid = {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_USERS}};
  69. const _SID2 g_GuestsSid = {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_GUESTS}};
  70. static const UINT g_rgHideTheseControlsOnDriveBlockade[] = {
  71. IDC_GB_SECURITY
  72. , IDC_GB_NETWORK_SHARING
  73. , IDC_SIMPLE_SHARE_SECURITY_STATIC
  74. , IDC_SHARE_NOTSHARED
  75. , IDC_LNK_SHARE_PARENT_PROTECTED
  76. , IDC_SHARE_ICON
  77. , IDC_SIMPLE_SHARE_NETWORKING_STATIC
  78. , IDC_SHARE_SHAREDAS
  79. , IDC_SHARE_SHARENAME_TEXT
  80. , IDC_SHARE_SHARENAME
  81. , IDC_SHARE_PERMISSIONS
  82. , IDC_I_SHARE_INFORMATION
  83. , IDC_LNK_SHARE_NETWORK_WIZARD
  84. , IDC_LNK_SHARE_OPEN_SHARED_DOCS
  85. , IDC_LNK_SHARE_HELP_SHARING_AND_SECURITY
  86. , IDC_LNK_SHARE_HELP_ON_SECURITY
  87. , IDC_S_SHARE_SYSTEM_FOLDER
  88. , IDC_LNK_SHARE_SECURITY_OVERRIDE
  89. };
  90. //+-------------------------------------------------------------------------
  91. //
  92. // Method: _GetUserSid
  93. //
  94. // Synopsis: Get the current user's SID from the thread or process token.
  95. //
  96. //--------------------------------------------------------------------------
  97. BOOL
  98. _GetUserSid(
  99. OUT PWSTR *ppszSID
  100. )
  101. {
  102. BOOL bResult = FALSE;
  103. HANDLE hToken;
  104. *ppszSID = NULL;
  105. if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken)
  106. || OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
  107. {
  108. BYTE buffer[sizeof(TOKEN_USER) + sizeof(SID) + SID_MAX_SUB_AUTHORITIES*sizeof(DWORD)];
  109. ULONG cbBuffer = sizeof(buffer);
  110. if (GetTokenInformation(hToken,
  111. TokenUser,
  112. buffer,
  113. cbBuffer,
  114. &cbBuffer))
  115. {
  116. PTOKEN_USER ptu = (PTOKEN_USER)buffer;
  117. bResult = ConvertSidToStringSidW(ptu->User.Sid, ppszSID);
  118. }
  119. CloseHandle(hToken);
  120. }
  121. return bResult;
  122. }
  123. //+-------------------------------------------------------------------------
  124. //
  125. // Method: _GetUserProfilePath
  126. //
  127. // Synopsis: Retrieve the profile path for a particular user.
  128. //
  129. //--------------------------------------------------------------------------
  130. HRESULT _GetUserProfilePath(PCWSTR pszUserSID, PWSTR szPath, DWORD cchPath)
  131. {
  132. WCHAR szKey[MAX_PATH];
  133. DWORD cbSize;
  134. DWORD dwErr;
  135. PathCombineW(szKey, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList", pszUserSID);
  136. cbSize = cchPath * sizeof(WCHAR);
  137. dwErr = SHGetValue(HKEY_LOCAL_MACHINE, szKey, L"ProfileImagePath", NULL, szPath, &cbSize);
  138. return HRESULT_FROM_WIN32(dwErr);
  139. }
  140. //+-------------------------------------------------------------------------
  141. //
  142. // Method: _CheckFolderType
  143. //
  144. // Synopsis: Check whether the target folder is contained in a
  145. // special folder, such as the user's profile.
  146. //
  147. //--------------------------------------------------------------------------
  148. static const struct
  149. {
  150. int csidl;
  151. BOOL bTestSubfolder;
  152. BOOL bUserSpecific;
  153. DWORD dwFlags;
  154. PCWSTR pszDefaultSD; // needed if CFT_FLAG_CAN_MAKE_PRIVATE is on
  155. } c_rgFolderInfo[] =
  156. {
  157. // NOTE: Order is important here!
  158. {CSIDL_SYSTEM, TRUE, FALSE, CFT_FLAG_ALWAYS_SHARED | CFT_FLAG_SYSTEM_FOLDER, NULL},
  159. {CSIDL_PROGRAM_FILES, FALSE, FALSE, CFT_FLAG_ALWAYS_SHARED | CFT_FLAG_SYSTEM_FOLDER, NULL},
  160. {CSIDL_COMMON_DOCUMENTS, TRUE, FALSE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_ALWAYS_SHARED, NULL},
  161. {CSIDL_COMMON_DESKTOPDIRECTORY, TRUE, FALSE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_ALWAYS_SHARED, NULL},
  162. {CSIDL_COMMON_PICTURES, TRUE, FALSE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_ALWAYS_SHARED, NULL},
  163. {CSIDL_COMMON_MUSIC, TRUE, FALSE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_ALWAYS_SHARED, NULL},
  164. {CSIDL_COMMON_VIDEO, TRUE, FALSE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_ALWAYS_SHARED, NULL},
  165. {CSIDL_PROFILE, TRUE, TRUE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_CAN_MAKE_PRIVATE, c_szDefaultProfileSD},
  166. {CSIDL_DESKTOPDIRECTORY, TRUE, TRUE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_CAN_MAKE_PRIVATE, c_szDefaultProfileSD},
  167. {CSIDL_PERSONAL, TRUE, TRUE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_CAN_MAKE_PRIVATE, c_szDefaultProfileSD},
  168. {CSIDL_MYPICTURES, TRUE, TRUE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_CAN_MAKE_PRIVATE, c_szDefaultProfileSD},
  169. {CSIDL_MYMUSIC, TRUE, TRUE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_CAN_MAKE_PRIVATE, c_szDefaultProfileSD},
  170. {CSIDL_MYVIDEO, TRUE, TRUE, CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_CAN_MAKE_PRIVATE, c_szDefaultProfileSD},
  171. {CSIDL_WINDOWS, TRUE, FALSE, CFT_FLAG_ALWAYS_SHARED | CFT_FLAG_SYSTEM_FOLDER, NULL},
  172. };
  173. // Some of the folders above are normally contained within another, e.g. MyDocs
  174. // inside Profile, but may be redirected elsewhere. In such cases, the child
  175. // folder should be listed *after* the parent folder. This is important for
  176. // correctly finding the point at which the protected ACL is set.
  177. //
  178. // Also, upgrades from previous OS's can leave profiles under CSIDL_WINDOWS.
  179. // We don't allow sharing under CSIDL_WINDOWS, except we want to allow the user
  180. // to share folders in their profile. So leave CSIDL_WINDOWS last.
  181. BOOL
  182. _PathIsEqualOrSubFolder(
  183. PWSTR pszParent,
  184. PCWSTR pszSubFolder
  185. )
  186. {
  187. WCHAR szCommon[MAX_PATH];
  188. // PathCommonPrefix() always removes the slash on common
  189. return (pszParent[0] && PathRemoveBackslashW(pszParent)
  190. && PathCommonPrefixW(pszParent, pszSubFolder, szCommon)
  191. && lstrcmpiW(pszParent, szCommon) == 0);
  192. }
  193. DWORD
  194. _CheckFolderType(
  195. PCWSTR pszFolder,
  196. PCWSTR pszUserSID,
  197. BOOL *pbFolderRoot,
  198. PCWSTR *ppszDefaultAcl
  199. )
  200. {
  201. // Default is to allow sharing, unless there is a reason not to
  202. DWORD dwSharingFlags = CFT_FLAG_SHARING_ALLOWED;
  203. if (pbFolderRoot)
  204. {
  205. *pbFolderRoot = FALSE;
  206. }
  207. if (ppszDefaultAcl)
  208. {
  209. *ppszDefaultAcl = NULL;
  210. }
  211. // Note that we don't mess with UNC paths
  212. if (NULL == pszFolder ||
  213. L'\0' == *pszFolder ||
  214. PathIsUNC(pszFolder))
  215. {
  216. return CFT_FLAG_NO_SHARING;
  217. }
  218. // We warn about sharing out the root folder of drives.
  219. if (PathIsRoot(pszFolder))
  220. {
  221. return CFT_FLAG_ROOT_FOLDER;
  222. }
  223. WCHAR szPath[MAX_PATH];
  224. BOOL bFolderRoot = FALSE;
  225. int i;
  226. HRESULT hr;
  227. if (NULL != pszUserSID)
  228. {
  229. LPWSTR pszCurrentSID = NULL;
  230. if (_GetUserSid(&pszCurrentSID))
  231. {
  232. appAssert(NULL != pszCurrentSID);
  233. if (0 == lstrcmpiW(pszUserSID, pszCurrentSID))
  234. {
  235. // Use NULL for current user to avoid E_NOTIMPL cases below
  236. pszUserSID = NULL;
  237. }
  238. LocalFree(pszCurrentSID);
  239. }
  240. }
  241. for (i = 0; i < ARRAYLEN(c_rgFolderInfo); i++)
  242. {
  243. // If the user is specified, need to check the correct profile
  244. if (c_rgFolderInfo[i].bUserSpecific && NULL != pszUserSID)
  245. {
  246. switch (c_rgFolderInfo[i].csidl)
  247. {
  248. case CSIDL_PROFILE:
  249. hr = _GetUserProfilePath(pszUserSID, szPath, ARRAYLEN(szPath));
  250. break;
  251. case CSIDL_DESKTOPDIRECTORY:
  252. case CSIDL_PERSONAL:
  253. case CSIDL_MYPICTURES:
  254. case CSIDL_MYMUSIC:
  255. case CSIDL_MYVIDEO:
  256. default:
  257. // Need to load the user's hive and read the shell folder
  258. // path from there.
  259. //
  260. // For now, we don't really need these, so just skip them.
  261. appAssert(FALSE);
  262. hr = E_NOTIMPL;
  263. break;
  264. }
  265. }
  266. else
  267. {
  268. hr = SHGetFolderPathW(NULL, c_rgFolderInfo[i].csidl | CSIDL_FLAG_DONT_VERIFY, NULL, SHGFP_TYPE_CURRENT, szPath);
  269. }
  270. if (S_OK == hr)
  271. {
  272. bFolderRoot = (lstrcmpiW(szPath, pszFolder) == 0);
  273. if (bFolderRoot ||
  274. (c_rgFolderInfo[i].bTestSubfolder && _PathIsEqualOrSubFolder(szPath, pszFolder)))
  275. {
  276. if (bFolderRoot && ppszDefaultAcl)
  277. {
  278. *ppszDefaultAcl = c_rgFolderInfo[i].pszDefaultSD;
  279. }
  280. dwSharingFlags = c_rgFolderInfo[i].dwFlags;
  281. break;
  282. }
  283. }
  284. }
  285. if (ARRAYLEN(c_rgFolderInfo) == i)
  286. {
  287. // Check for other profile dirs. If there were a CSIDL for this we
  288. // could just add it to the list above.
  289. DWORD cchPath = ARRAYLEN(szPath);
  290. if (GetProfilesDirectoryW(szPath, &cchPath))
  291. {
  292. bFolderRoot = (lstrcmpiW(szPath, pszFolder) == 0);
  293. if (bFolderRoot || _PathIsEqualOrSubFolder(szPath, pszFolder))
  294. {
  295. // No sharing
  296. dwSharingFlags = CFT_FLAG_NO_SHARING;
  297. }
  298. }
  299. }
  300. if (pbFolderRoot)
  301. {
  302. *pbFolderRoot = bFolderRoot;
  303. }
  304. return dwSharingFlags;
  305. }
  306. //+-------------------------------------------------------------------------
  307. //
  308. // Method: IsGuestEnabledForNetworkAccess
  309. //
  310. // Synopsis: Test whether the Guest account can be used for incoming
  311. // network connections.
  312. //
  313. //--------------------------------------------------------------------------
  314. BOOL IsGuestEnabledForNetworkAccess()
  315. {
  316. BOOL bResult = FALSE;
  317. ILocalMachine *pLM;
  318. if (SUCCEEDED(CoCreateInstance(CLSID_ShellLocalMachine, NULL, CLSCTX_INPROC_SERVER, IID_ILocalMachine, (void**)&pLM)))
  319. {
  320. VARIANT_BOOL vbEnabled = VARIANT_FALSE;
  321. bResult = (SUCCEEDED(pLM->get_isGuestEnabled(ILM_GUEST_NETWORK_LOGON, &vbEnabled)) && VARIANT_TRUE == vbEnabled);
  322. pLM->Release();
  323. }
  324. return bResult;
  325. }
  326. //////////////////////////////////////////////////////////////////////
  327. // Construction/Destruction
  328. //////////////////////////////////////////////////////////////////////
  329. CSimpleSharingPage::CSimpleSharingPage(
  330. IN PWSTR pszPath
  331. )
  332. :
  333. CShareBase(pszPath, FALSE),
  334. _bSharingEnabled(TRUE),
  335. _bShareNameChanged(FALSE),
  336. _bSecDescChanged(FALSE),
  337. _bIsPrivateVisible(FALSE),
  338. _bDriveRootBlockade(TRUE),
  339. _dwPermType(0),
  340. _pszInheritanceSource(NULL)
  341. {
  342. INIT_SIG(CSimpleSharingPage);
  343. }
  344. CSimpleSharingPage::~CSimpleSharingPage()
  345. {
  346. CHECK_SIG(CSimpleSharingPage);
  347. if (NULL != _pszInheritanceSource)
  348. {
  349. LocalFree(_pszInheritanceSource);
  350. }
  351. }
  352. //+-------------------------------------------------------------------------
  353. //
  354. // Method: CSimpleSharingPage::_PageProc, private
  355. //
  356. // Synopsis: Dialog Procedure for this object
  357. //
  358. //--------------------------------------------------------------------------
  359. BOOL
  360. CSimpleSharingPage::_PageProc(
  361. IN HWND hwnd,
  362. IN UINT msg,
  363. IN WPARAM wParam,
  364. IN LPARAM lParam
  365. )
  366. {
  367. CHECK_SIG(CSimpleSharingPage);
  368. switch (msg)
  369. {
  370. case WM_SETTINGCHANGE:
  371. // Reinitialize the dialog
  372. _InitializeControls(hwnd);
  373. break;
  374. }
  375. return CShareBase::_PageProc(hwnd, msg, wParam, lParam);
  376. }
  377. //+-------------------------------------------------------------------------
  378. //
  379. // Method: CSimpleSharingPage::_OnInitDialog, private
  380. //
  381. // Synopsis: WM_INITDIALOG handler
  382. //
  383. //--------------------------------------------------------------------------
  384. BOOL
  385. CSimpleSharingPage::_OnInitDialog(
  386. IN HWND hwnd,
  387. IN HWND hwndFocus,
  388. IN LPARAM lInitParam
  389. )
  390. {
  391. CHECK_SIG(CSimpleSharingPage);
  392. appDebugOut((DEB_ITRACE, "_OnInitDialog\n"));
  393. // use LanMan API constant to set maximum share name length
  394. SendDlgItemMessage(hwnd, IDC_SHARE_SHARENAME, EM_LIMITTEXT, NNLEN, 0L);
  395. _InitializeControls(hwnd);
  396. return TRUE;
  397. }
  398. //+-------------------------------------------------------------------------
  399. //
  400. // Method: CSimpleSharingPage::_OnCommand, private
  401. //
  402. // Synopsis: WM_COMMAND handler
  403. //
  404. //--------------------------------------------------------------------------
  405. BOOL
  406. CSimpleSharingPage::_OnCommand(
  407. IN HWND hwnd,
  408. IN WORD wNotifyCode,
  409. IN WORD wID,
  410. IN HWND hwndCtl
  411. )
  412. {
  413. CHECK_SIG(CSimpleSharingPage);
  414. switch (wID)
  415. {
  416. case IDC_SHARE_SHAREDAS:
  417. if (BST_UNCHECKED == IsDlgButtonChecked(hwnd, IDC_SHARE_SHAREDAS))
  418. {
  419. _ReadControls(hwnd);
  420. }
  421. // Fall through...
  422. case IDC_SHARE_NOTSHARED:
  423. if (BN_CLICKED == wNotifyCode)
  424. {
  425. _SetControlsFromData(hwnd);
  426. _MarkPageDirty();
  427. }
  428. return TRUE;
  429. case IDC_SHARE_SHARENAME:
  430. if (EN_CHANGE == wNotifyCode && !_fInitializingPage)
  431. {
  432. _bShareNameChanged = TRUE;
  433. _MarkPageDirty();
  434. }
  435. return TRUE;
  436. case IDC_SHARE_PERMISSIONS:
  437. if (BN_CLICKED == wNotifyCode)
  438. {
  439. _bSecDescChanged = TRUE;
  440. _MarkPageDirty();
  441. }
  442. return TRUE;
  443. }
  444. return CShareBase::_OnCommand(hwnd, wNotifyCode, wID, hwndCtl);
  445. }
  446. BOOL
  447. RunTheNetworkSharingWizard(
  448. HWND hwnd
  449. )
  450. {
  451. HRESULT hr;
  452. IHomeNetworkWizard *pHNW;
  453. hr = CoCreateInstance( CLSID_HomeNetworkWizard, NULL, CLSCTX_INPROC_SERVER, IID_IHomeNetworkWizard, (void**)&pHNW );
  454. if (SUCCEEDED(hr))
  455. {
  456. BOOL bRebootRequired = FALSE;
  457. hr = pHNW->ShowWizard(hwnd, &bRebootRequired);
  458. if ( SUCCEEDED(hr) && bRebootRequired )
  459. {
  460. RestartDialogEx(hwnd, NULL, EWX_REBOOT, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG);
  461. }
  462. pHNW->Release();
  463. }
  464. return (SUCCEEDED(hr));
  465. }
  466. //+-------------------------------------------------------------------------
  467. //
  468. // Method: CSimpleSharingPage::_OnPropertySheetNotify, private
  469. //
  470. // Synopsis: WM_NOTIFY handler
  471. //
  472. //--------------------------------------------------------------------------
  473. BOOL
  474. CSimpleSharingPage::_OnPropertySheetNotify(
  475. IN HWND hwnd,
  476. IN LPNMHDR phdr
  477. )
  478. {
  479. CHECK_SIG(CSimpleSharingPage);
  480. switch (phdr->code)
  481. {
  482. case NM_RETURN:
  483. case NM_CLICK:
  484. switch (phdr->idFrom)
  485. {
  486. case IDC_LNK_SHARE_PARENT_PROTECTED:
  487. {
  488. HWND hwndFrame = _GetFrameWindow();
  489. // Close the current propsheet
  490. PropSheet_PressButton(hwndFrame, PSBTN_CANCEL);
  491. appAssert(NULL != _pszInheritanceSource);
  492. // Show the sharing page for the ancestor folder
  493. WCHAR szCaption[50];
  494. LoadStringW(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
  495. SHObjectProperties(GetParent(hwndFrame), SHOP_FILEPATH, _pszInheritanceSource, szCaption);
  496. }
  497. return TRUE;
  498. case IDC_LNK_SHARE_NETWORK_WIZARD:
  499. appAssert(!_bSharingEnabled);
  500. if ( RunTheNetworkSharingWizard( hwnd ) )
  501. {
  502. // Reinitialize the dialog
  503. _InitializeControls(hwnd);
  504. }
  505. break;
  506. case IDC_LNK_SHARE_SECURITY_OVERRIDE:
  507. {
  508. UINT iRet = (UINT) DialogBox( g_hInstance, MAKEINTRESOURCE(IDD_SIMPLE_SHARE_ENABLE_WARNING), hwnd, WarningDlgProc );
  509. if ( IDC_RB_RUN_THE_WIZARD == iRet )
  510. {
  511. appAssert(!_bSharingEnabled);
  512. if ( RunTheNetworkSharingWizard( hwnd ) )
  513. {
  514. //
  515. // Now that we changed the "networking state," re-initialize the dialog
  516. // and update the control to the new state.
  517. //
  518. _InitializeControls(hwnd);
  519. }
  520. }
  521. else if ( IDC_RB_ENABLE_FILE_SHARING == iRet )
  522. {
  523. ILocalMachine *pLM;
  524. HRESULT hr = CoCreateInstance(CLSID_ShellLocalMachine, NULL, CLSCTX_INPROC_SERVER, IID_ILocalMachine, (void**)&pLM);
  525. if (SUCCEEDED(hr))
  526. {
  527. hr = pLM->EnableGuest(ILM_GUEST_NETWORK_LOGON);
  528. pLM->Release();
  529. SendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
  530. }
  531. //
  532. // Now that we changed the "networking state," re-initialize the dialog
  533. // and update the control to the new state.
  534. //
  535. _InitializeControls(hwnd);
  536. }
  537. }
  538. break;
  539. case IDC_LNK_SHARE_DRIVE_BLOCADE:
  540. if (_bDriveRootBlockade)
  541. {
  542. // Unhide the other controls
  543. for (ULONG idx = 0; idx < ARRAYLEN(g_rgHideTheseControlsOnDriveBlockade); idx ++ )
  544. {
  545. ShowWindow(GetDlgItem(hwnd, g_rgHideTheseControlsOnDriveBlockade[idx]), SW_SHOW);
  546. }
  547. _bDriveRootBlockade = FALSE;
  548. _InitializeControls( hwnd );
  549. }
  550. return TRUE;
  551. case IDC_LNK_SHARE_OPEN_SHARED_DOCS:
  552. {
  553. WCHAR szPath[MAX_PATH];
  554. BOOL b = SHGetSpecialFolderPath(NULL, szPath, CSIDL_COMMON_DOCUMENTS, TRUE);
  555. if (b)
  556. {
  557. DWORD_PTR dwRet = (DWORD_PTR) ShellExecute(hwnd, L"Open", szPath, NULL, NULL, SW_SHOW);
  558. if ( 32 < dwRet )
  559. {
  560. HWND hwndFrame = _GetFrameWindow();
  561. // Close the current propsheet
  562. PropSheet_PressButton(hwndFrame, PSBTN_CANCEL);
  563. }
  564. }
  565. }
  566. return TRUE;
  567. case IDC_LNK_SHARE_HELP_SHARING_AND_SECURITY:
  568. {
  569. WCHAR szPath[MAX_PATH];
  570. HWND hwndFrame = _GetFrameWindow();
  571. if (IsOS(OS_PERSONAL))
  572. {
  573. LoadString(g_hInstance, IDS_SHARE_HELP_SHARING_AND_SECURITY_PER, szPath, ARRAYLEN(szPath));
  574. }
  575. else
  576. {
  577. LoadString(g_hInstance, IDS_SHARE_HELP_SHARING_AND_SECURITY_WKS, szPath, ARRAYLEN(szPath));
  578. }
  579. ShellExecute(hwndFrame, NULL, szPath, NULL, NULL, SW_NORMAL);
  580. }
  581. break;
  582. }
  583. break;
  584. default:
  585. break;
  586. }
  587. return CShareBase::_OnPropertySheetNotify(hwnd, phdr);
  588. }
  589. //+-------------------------------------------------------------------------
  590. //
  591. // Method: CSimpleSharingPage::_OnHelp, private
  592. //
  593. // Synopsis: WM_HELP handler
  594. //
  595. //--------------------------------------------------------------------------
  596. static const DWORD aHelpIds[] =
  597. {
  598. IDC_SHARE_SHARENAME, IDH_SHARE2_ShareName,
  599. IDC_SHARE_SHARENAME_TEXT, IDH_SHARE2_ShareName,
  600. IDC_SHARE_NOTSHARED, IDH_SHARE2_MakePrivate,
  601. IDC_SHARE_SHAREDAS, IDH_SHARE2_ShareOnNet,
  602. IDC_SHARE_PERMISSIONS, IDH_SHARE2_ReadOnly,
  603. IDC_LNK_SHARE_DRIVE_BLOCADE, -1, // no help
  604. 0,0
  605. };
  606. BOOL
  607. CSimpleSharingPage::_OnHelp(
  608. IN HWND hwnd,
  609. IN LPHELPINFO lphi
  610. )
  611. {
  612. CHECK_SIG(CSimpleSharingPage);
  613. if (lphi->iContextType == HELPINFO_WINDOW) // a control
  614. {
  615. WCHAR szHelp[50];
  616. LoadString(g_hInstance, IDS_SIMPLE_SHARE_HELPFILE, szHelp, ARRAYLEN(szHelp));
  617. WinHelp(
  618. (HWND)lphi->hItemHandle,
  619. szHelp,
  620. HELP_WM_HELP,
  621. (DWORD_PTR)aHelpIds);
  622. }
  623. return TRUE;
  624. }
  625. //+-------------------------------------------------------------------------
  626. //
  627. // Method: CSimpleSharingPage::_OnContextMenu, private
  628. //
  629. // Synopsis: WM_CONTEXTMENU handler
  630. //
  631. //--------------------------------------------------------------------------
  632. BOOL
  633. CSimpleSharingPage::_OnContextMenu(
  634. IN HWND hwnd,
  635. IN HWND hwndCtl,
  636. IN int xPos,
  637. IN int yPos
  638. )
  639. {
  640. CHECK_SIG(CSimpleSharingPage);
  641. WCHAR szHelp[50];
  642. LoadString(g_hInstance, IDS_SIMPLE_SHARE_HELPFILE, szHelp, ARRAYLEN(szHelp));
  643. WinHelp(
  644. hwndCtl,
  645. szHelp,
  646. HELP_CONTEXTMENU,
  647. (DWORD_PTR)aHelpIds);
  648. return TRUE;
  649. }
  650. //+-------------------------------------------------------------------------
  651. //
  652. // Method: CSimpleSharingPage::_InitializeControls, private
  653. //
  654. // Synopsis: Initialize the controls from scratch
  655. //
  656. //--------------------------------------------------------------------------
  657. VOID
  658. CSimpleSharingPage::_InitializeControls(
  659. IN HWND hwnd
  660. )
  661. {
  662. CHECK_SIG(CSimpleSharingPage);
  663. _fInitializingPage++;
  664. _dwPermType = IFPFU_NOT_NTFS;
  665. _bIsPrivateVisible = FALSE;
  666. if (NULL != _pszInheritanceSource)
  667. {
  668. LocalFree(_pszInheritanceSource);
  669. _pszInheritanceSource = NULL;
  670. }
  671. // Check whether to show the "Make Private" stuff
  672. DWORD dwFolderFlags = _CheckFolderType(_pszPath, NULL, NULL, NULL);
  673. if (dwFolderFlags & CFT_FLAG_CAN_MAKE_PRIVATE)
  674. {
  675. _dwPermType = IFPFU_NOT_PRIVATE;
  676. LPWSTR pszSID = NULL;
  677. if (_GetUserSid(&pszSID))
  678. {
  679. appAssert(NULL != pszSID);
  680. IsFolderPrivateForUser(_pszPath, pszSID, &_dwPermType, &_pszInheritanceSource);
  681. LocalFree(pszSID);
  682. }
  683. if ((_dwPermType & IFPFU_NOT_NTFS) == 0)
  684. {
  685. _bIsPrivateVisible = TRUE;
  686. }
  687. }
  688. CheckDlgButton(hwnd, IDC_SHARE_NOTSHARED, (_bIsPrivateVisible && (_dwPermType & IFPFU_PRIVATE) != 0) ? BST_CHECKED : BST_UNCHECKED);
  689. EnableWindow(GetDlgItem(hwnd, IDC_SHARE_NOTSHARED), _bIsPrivateVisible);
  690. BOOL bIsFolderNetworkShared = FALSE;
  691. if ( g_fSharingEnabled )
  692. {
  693. // Is there a net share?
  694. if (_cShares > 0)
  695. {
  696. // It's shared, but check for hidden (admin$) shares and
  697. // ignore them by removing them from the list.
  698. appAssert(_bNewShare == FALSE);
  699. for (CShareInfo* p = (CShareInfo*)_pInfoList->Next();
  700. p != _pInfoList && _cShares > 0;
  701. )
  702. {
  703. CShareInfo* pNext = (CShareInfo*)p->Next();
  704. if (STYPE_SPECIAL & p->GetType())
  705. {
  706. // remove p from the list
  707. p->Unlink();
  708. delete p;
  709. _cShares--;
  710. }
  711. p = pNext;
  712. }
  713. if (_cShares == 0)
  714. {
  715. // No shares left, so construct an element to be used
  716. // by the UI to stash the new share's data.
  717. _ConstructNewShareInfo();
  718. }
  719. }
  720. // Now is it shared?
  721. if (_cShares > 0)
  722. {
  723. CheckDlgButton(hwnd, IDC_SHARE_SHAREDAS, BST_CHECKED);
  724. bIsFolderNetworkShared = TRUE;
  725. }
  726. else
  727. {
  728. SetDlgItemText(hwnd, IDC_SHARE_SHARENAME, L"");
  729. CheckDlgButton(hwnd, IDC_SHARE_SHAREDAS, BST_UNCHECKED);
  730. }
  731. }
  732. //
  733. // The Simple Sharing page (shrpage2.cxx) assumes ForceGuest
  734. // mode is in effect for incoming network access. This mode uses
  735. // the Guest account for all network connections.
  736. //
  737. // Out of the box, the Guest account is disabled, effectively
  738. // disabling network sharing. The Home Networking Wizard is
  739. // used to enable network sharing (and the Guest account).
  740. //
  741. // So we test whether the Guest account is enabled for network
  742. // logon to determine whether to enable the sharing UI. If
  743. // network sharing is disabled, we disable the UI and offer
  744. // to launch the Home Networking Wizard.
  745. //
  746. // Note that it is possible for a net share to exist even though
  747. // the Guest account is disabled.
  748. //
  749. _bSharingEnabled = IsGuestEnabledForNetworkAccess();
  750. BOOL bShowPrivateWarning = (_bIsPrivateVisible && (_dwPermType & IFPFU_PRIVATE_INHERITED));
  751. BOOL bInheritanceSource = (NULL == _pszInheritanceSource);
  752. BOOL bIsRootFolder = (dwFolderFlags & CFT_FLAG_ROOT_FOLDER);
  753. BOOL bIsSystemFolder = (dwFolderFlags & CFT_FLAG_SYSTEM_FOLDER);
  754. BOOL bIsInSharedFolder = (dwFolderFlags & CFT_FLAG_ALWAYS_SHARED);
  755. // see if the path is the root of a drive. if so, put up the blockade.
  756. if (_bDriveRootBlockade && bIsRootFolder && !bIsFolderNetworkShared)
  757. {
  758. _MyShow(hwnd, IDC_LNK_SHARE_DRIVE_BLOCADE, TRUE);
  759. // Hide all the other controls when the blockade is up.
  760. for (ULONG idx = 0; idx < ARRAYLEN(g_rgHideTheseControlsOnDriveBlockade); idx ++ )
  761. {
  762. ShowWindow(GetDlgItem(hwnd, g_rgHideTheseControlsOnDriveBlockade[idx]), SW_HIDE);
  763. }
  764. }
  765. else
  766. {
  767. BOOL bShowInfoIcon = FALSE;
  768. BOOL bShowNetworkWizard = FALSE;
  769. BOOL bShowParentProteced = FALSE;
  770. BOOL bShowSystemFolder = FALSE;
  771. // Hide the blockade
  772. _MyShow(hwnd, IDC_LNK_SHARE_DRIVE_BLOCADE, FALSE );
  773. // Turn on the "special info" as nessecary.
  774. if (bIsSystemFolder)
  775. {
  776. _bSharingEnabled = FALSE;
  777. bShowSystemFolder = TRUE;
  778. bShowInfoIcon = TRUE;
  779. }
  780. else if (bShowPrivateWarning && !bInheritanceSource)
  781. {
  782. bShowParentProteced = TRUE;
  783. bShowInfoIcon = TRUE;
  784. }
  785. else if (!bShowPrivateWarning && !_bSharingEnabled && g_fSharingEnabled)
  786. {
  787. bShowNetworkWizard = TRUE;
  788. }
  789. _MyShow(hwnd, IDC_LNK_SHARE_PARENT_PROTECTED , bShowParentProteced);
  790. _MyShow(hwnd, IDC_LNK_SHARE_NETWORK_WIZARD , bShowNetworkWizard);
  791. _MyShow(hwnd, IDC_LNK_SHARE_SECURITY_OVERRIDE , bShowNetworkWizard);
  792. _MyShow(hwnd, IDC_SIMPLE_SHARE_NETWORKING_STATIC, !bShowNetworkWizard);
  793. _MyShow(hwnd, IDC_SHARE_SHAREDAS , !bShowNetworkWizard);
  794. _MyShow(hwnd, IDC_SHARE_SHARENAME_TEXT , !bShowNetworkWizard);
  795. _MyShow(hwnd, IDC_SHARE_PERMISSIONS , !bShowNetworkWizard);
  796. _MyShow(hwnd, IDC_S_SHARE_SYSTEM_FOLDER , bShowSystemFolder);
  797. _MyShow(hwnd, IDC_I_SHARE_INFORMATION , bShowInfoIcon);
  798. }
  799. _SetControlsFromData(hwnd);
  800. _fInitializingPage--;
  801. }
  802. //+-------------------------------------------------------------------------
  803. //
  804. // Method: CSimpleSharingPage::SetControlsFromData, private
  805. //
  806. // Synopsis: From the class variables and current state of the radio
  807. // buttons, set the enabled/disabled state of the buttons, as
  808. // well as filling the controls with the appropriate values.
  809. //
  810. //--------------------------------------------------------------------------
  811. VOID
  812. CSimpleSharingPage::_SetControlsFromData(
  813. IN HWND hwnd
  814. )
  815. {
  816. CHECK_SIG(CSimpleSharingPage);
  817. _fInitializingPage++;
  818. BOOL bIsPrivate = (BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_SHARE_NOTSHARED));
  819. BOOL bIsShared = (BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_SHARE_SHAREDAS));
  820. // We don't allow both to be checked at the same time
  821. appAssert(!(bIsPrivate && bIsShared));
  822. EnableWindow(GetDlgItem(hwnd, IDC_SHARE_NOTSHARED), !bIsShared && _bIsPrivateVisible && !(_dwPermType & IFPFU_PRIVATE_INHERITED));
  823. EnableWindow(GetDlgItem(hwnd, IDC_SHARE_SHAREDAS), _bSharingEnabled && !bIsPrivate);
  824. EnableWindow(GetDlgItem(hwnd, IDC_SHARE_SHARENAME_TEXT), _bSharingEnabled && bIsShared);
  825. EnableWindow(GetDlgItem(hwnd, IDC_SHARE_SHARENAME), _bSharingEnabled && bIsShared);
  826. EnableWindow(GetDlgItem(hwnd, IDC_SHARE_PERMISSIONS), _bSharingEnabled && bIsShared);
  827. if (bIsShared)
  828. {
  829. appDebugOut((DEB_ITRACE, "_SetControlsFromData: path is shared\n"));
  830. _pCurInfo = (CShareInfo*)_pInfoList->Next();
  831. if (NULL != _pCurInfo)
  832. {
  833. SetDlgItemText(hwnd, IDC_SHARE_SHARENAME, _pCurInfo->GetNetname());
  834. // If the share really exists, then make the name read-only.
  835. // This corresponds to the non-editable combo-box on the full
  836. // sharing page.
  837. SendDlgItemMessage(hwnd, IDC_SHARE_SHARENAME, EM_SETREADONLY, (_cShares > 0), 0);
  838. CheckDlgButton(hwnd, IDC_SHARE_PERMISSIONS, _IsReadonlyShare(_pCurInfo) ? BST_UNCHECKED : BST_CHECKED);
  839. }
  840. else
  841. {
  842. CheckDlgButton(hwnd, IDC_SHARE_SHAREDAS, BST_UNCHECKED );
  843. }
  844. }
  845. else
  846. {
  847. appDebugOut((DEB_ITRACE, "_SetControlsFromData: path is not shared\n"));
  848. _pCurInfo = NULL;
  849. }
  850. _fInitializingPage--;
  851. }
  852. //+-------------------------------------------------------------------------
  853. //
  854. // Method: CSimpleSharingPage::_ReadControls, private
  855. //
  856. // Synopsis: Load the data in the controls into internal data structures.
  857. //
  858. //--------------------------------------------------------------------------
  859. BOOL
  860. CSimpleSharingPage::_ReadControls(
  861. IN HWND hwnd
  862. )
  863. {
  864. CHECK_SIG(CSimpleSharingPage);
  865. if (_bShareNameChanged)
  866. {
  867. appDebugOut((DEB_ITRACE, "_ReadControls: share name changed\n"));
  868. if (NULL != _pCurInfo)
  869. {
  870. WCHAR szShareName[NNLEN + 1];
  871. GetDlgItemText(hwnd, IDC_SHARE_SHARENAME, szShareName, ARRAYLEN(szShareName));
  872. TrimLeadingAndTrailingSpaces(szShareName);
  873. _pCurInfo->SetNetname(szShareName);
  874. _bShareNameChanged = FALSE;
  875. }
  876. else
  877. {
  878. appDebugOut((DEB_ITRACE, "_ReadControls: _pCurInfo is NULL\n"));
  879. }
  880. }
  881. if (_bSecDescChanged)
  882. {
  883. appDebugOut((DEB_ITRACE, "_ReadControls: permissions changed\n"));
  884. if(NULL != _pCurInfo)
  885. {
  886. PSECURITY_DESCRIPTOR pSD;
  887. BOOL bIsReadonly = (BST_UNCHECKED == IsDlgButtonChecked(hwnd, IDC_SHARE_PERMISSIONS));
  888. if (ConvertStringSecurityDescriptorToSecurityDescriptorW(
  889. bIsReadonly ? c_szReadonlyShareSD : c_szFullShareSD,
  890. SDDL_REVISION_1,
  891. &pSD,
  892. NULL))
  893. {
  894. appAssert(IsValidSecurityDescriptor(pSD));
  895. // _pCurInfo takes ownership of pSD; no need to free on success
  896. if (FAILED(_pCurInfo->TransferSecurityDescriptor(pSD)))
  897. {
  898. LocalFree(pSD);
  899. }
  900. }
  901. _bSecDescChanged = FALSE;
  902. }
  903. else
  904. {
  905. appDebugOut((DEB_ITRACE, "_ReadControls: _pCurInfo is NULL\n"));
  906. }
  907. }
  908. return TRUE;
  909. }
  910. //+-------------------------------------------------------------------------
  911. //
  912. // Method: CSimpleSharingPage::_ValidatePage, private
  913. //
  914. // Synopsis: Return TRUE if the current page is valid
  915. //
  916. //--------------------------------------------------------------------------
  917. BOOL
  918. CSimpleSharingPage::_ValidatePage(
  919. IN HWND hwnd
  920. )
  921. {
  922. CHECK_SIG(CSimpleSharingPage);
  923. _ReadControls(hwnd); // read current stuff
  924. if (BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_SHARE_SHAREDAS))
  925. {
  926. // If the user is creating a share on the property sheet (as
  927. // opposed to using the "new share" dialog), we must validate the
  928. // share.... Note that _bNewShare is still TRUE if the the user has
  929. // clicked on "Not Shared", so we must check that too.
  930. // Validate the share
  931. if (!_ValidateNewShareName())
  932. {
  933. SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
  934. return FALSE;
  935. }
  936. }
  937. #if DBG == 1
  938. Dump(L"_ValidatePage finished");
  939. #endif // DBG == 1
  940. return TRUE;
  941. }
  942. //+-------------------------------------------------------------------------
  943. //
  944. // Method: CSimpleSharingPage::_DoApply, private
  945. //
  946. // Synopsis: If anything has changed, apply the data
  947. //
  948. //--------------------------------------------------------------------------
  949. BOOL
  950. CSimpleSharingPage::_DoApply(
  951. IN HWND hwnd,
  952. IN BOOL bClose
  953. )
  954. {
  955. CHECK_SIG(CSimpleSharingPage);
  956. if (_bDirty)
  957. {
  958. HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  959. BOOL bIsShared = (BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_SHARE_SHAREDAS));
  960. if (bIsShared)
  961. {
  962. _ReadControls(hwnd);
  963. //
  964. // NTRAID#NTBUG9-382492-2001/05/05-jeffreys
  965. //
  966. // Win9x boxes can't see the share if the name is longer than LM20_NNLEN
  967. //
  968. if (NULL != _pCurInfo)
  969. {
  970. if (_pCurInfo->GetFlag() == SHARE_FLAG_ADDED)
  971. {
  972. PCWSTR pszName = _pCurInfo->GetNetname();
  973. if (NULL != pszName &&
  974. wcslen(pszName) > LM20_NNLEN &&
  975. IDNO == MyConfirmationDialog(hwnd, MSG_LONGNAMECONFIRM, MB_YESNO | MB_ICONWARNING, pszName))
  976. {
  977. return FALSE;
  978. }
  979. }
  980. }
  981. }
  982. _CommitShares(!bIsShared);
  983. if (_bDirty)
  984. {
  985. DWORD dwLevel;
  986. BOOL bIsPrivate = (_bIsPrivateVisible && BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_SHARE_NOTSHARED));
  987. appAssert(!(bIsShared && bIsPrivate));
  988. if (bIsPrivate)
  989. {
  990. // Private to the current user
  991. dwLevel = 0;
  992. }
  993. else if (!bIsShared)
  994. {
  995. // Default ACL (neither private nor shared)
  996. dwLevel = 1;
  997. }
  998. else if (BST_UNCHECKED == IsDlgButtonChecked(hwnd, IDC_SHARE_PERMISSIONS))
  999. {
  1000. // Read-only share
  1001. dwLevel = 2;
  1002. }
  1003. else
  1004. {
  1005. // Read-write share
  1006. dwLevel = 3;
  1007. }
  1008. _SetFolderPermissions(dwLevel);
  1009. }
  1010. CShareBase::_DoApply(hwnd, bClose);
  1011. if (!bClose)
  1012. {
  1013. _InitializeControls(hwnd);
  1014. }
  1015. SetCursor(hcur);
  1016. }
  1017. return TRUE;
  1018. }
  1019. //+-------------------------------------------------------------------------
  1020. //
  1021. // Method: CSimpleSharingPage::_DoCancel, private
  1022. //
  1023. // Synopsis: Do whatever is necessary to cancel the changes
  1024. //
  1025. //--------------------------------------------------------------------------
  1026. BOOL
  1027. CSimpleSharingPage::_DoCancel(
  1028. IN HWND hwnd
  1029. )
  1030. {
  1031. CHECK_SIG(CSimpleSharingPage);
  1032. if (_bDirty)
  1033. {
  1034. _bShareNameChanged = FALSE;
  1035. }
  1036. return CShareBase::_DoCancel(hwnd);
  1037. }
  1038. //+-------------------------------------------------------------------------
  1039. //
  1040. // Method: CSimpleSharingPage::_SetFolderPermissions, private
  1041. //
  1042. // Synopsis: Set new permissions on the subtree, either restricting
  1043. // access to the current user or making the folder accessible
  1044. // to everyone.
  1045. //
  1046. //--------------------------------------------------------------------------
  1047. typedef struct _SET_PERM_THREAD_DATA
  1048. {
  1049. DWORD dwLevel;
  1050. HWND hwndOwner;
  1051. WCHAR szPath[1];
  1052. } SET_PERM_THREAD_DATA;
  1053. DWORD WINAPI _SetFolderPermissionsThread(LPVOID pv)
  1054. {
  1055. DWORD dwError = ERROR_INVALID_DATA;
  1056. SET_PERM_THREAD_DATA *ptd = (SET_PERM_THREAD_DATA*)pv;
  1057. if (ptd)
  1058. {
  1059. dwError = ERROR_SUCCESS;
  1060. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
  1061. if (!SetFolderPermissionsForSharing(ptd->szPath, NULL, ptd->dwLevel, ptd->hwndOwner))
  1062. {
  1063. dwError = GetLastError();
  1064. }
  1065. LocalFree(ptd);
  1066. }
  1067. FreeLibraryAndExitThread(g_hInstance, dwError);
  1068. return 0;
  1069. }
  1070. BOOL
  1071. CSimpleSharingPage::_SetFolderPermissions(
  1072. IN DWORD dwLevel
  1073. )
  1074. {
  1075. CHECK_SIG(CSimpleSharingPage);
  1076. BOOL bResult = FALSE;
  1077. IActionProgressDialog *papd = NULL;
  1078. IActionProgress *pap = NULL;
  1079. // Show progress UI so the user understands that we're doing a lengthy
  1080. // operation, even though there's no way to cancel SetNamedSecurityInfo
  1081. // or get progress from it. This requires us to call SetNamedSecurityInfo
  1082. // on a different thread.
  1083. //
  1084. // Also, if the user cancels the progress dialog, we'll release the UI
  1085. // thread even though we can't stop the SetNamedSecurityInfo call. Just
  1086. // abandon the thread and let it run.
  1087. //
  1088. // This can lead to weird results when toggling the "Make private" checkbox
  1089. // on a large subtree:
  1090. // 1. toggle "Make private" and click Apply
  1091. // 2. cancel the progress UI
  1092. // 3. the "Make private" checkbox reverts to the previous state
  1093. // 4. Cancel the property sheet and reopen after the disk stops grinding
  1094. // 5. the "Make private" checkbox shows the new state
  1095. // Apparently, SetNamedSecurityInfo sets folder security in post-order, so
  1096. // the top folder doesn't get the new permissions until then end.
  1097. //
  1098. // Hopefully, this is rare enough that we don't need to do anything about it.
  1099. HRESULT hr = CoCreateInstance(CLSID_ProgressDialog,
  1100. NULL,
  1101. CLSCTX_INPROC_SERVER,
  1102. IID_IActionProgressDialog,
  1103. (void**)&papd);
  1104. if (SUCCEEDED(hr))
  1105. {
  1106. WCHAR szTitle[64];
  1107. IUnknown_SetSite(papd, this); // needed for modality
  1108. LoadStringW(g_hInstance, IDS_PERM_PROGRESS_TITLE, szTitle, ARRAYLEN(szTitle));
  1109. hr = papd->Initialize(SPINITF_MODAL | SPINITF_NOMINIMIZE, szTitle, NULL);
  1110. if (SUCCEEDED(hr))
  1111. {
  1112. hr = papd->QueryInterface(IID_IActionProgress, (void**)&pap);
  1113. if (SUCCEEDED(hr))
  1114. {
  1115. hr = pap->Begin(SPACTION_APPLYINGATTRIBS, SPBEGINF_MARQUEEPROGRESS);
  1116. }
  1117. }
  1118. }
  1119. // Kick off a thread to do the grunge work
  1120. SET_PERM_THREAD_DATA *ptd = (SET_PERM_THREAD_DATA*)LocalAlloc(LPTR, sizeof(SET_PERM_THREAD_DATA) + wcslen(_pszPath)*sizeof(WCHAR));
  1121. if (NULL != ptd)
  1122. {
  1123. DWORD dwT;
  1124. // It is possible to make a folder private with net sharing disabled.
  1125. // It is also possible that net sharing was previously enabled and net
  1126. // shares may still exist. Let's not confuse the user with a warning
  1127. // about deleting net shares on child folders if we happen to have this
  1128. // rare combination. That is, pass NULL for the HWND when sharing is
  1129. // disabled.
  1130. ptd->dwLevel = dwLevel;
  1131. ptd->hwndOwner = _bSharingEnabled ? _hwndPage : NULL;
  1132. wcscpy(ptd->szPath, _pszPath);
  1133. LoadLibraryW(L"ntshrui.dll");
  1134. HANDLE hThread = CreateThread(NULL, 0, _SetFolderPermissionsThread, ptd, 0, &dwT);
  1135. if (NULL == hThread)
  1136. {
  1137. // CreateThread failed? Do it synchronously
  1138. bResult = SetFolderPermissionsForSharing(ptd->szPath, NULL, ptd->dwLevel, ptd->hwndOwner);
  1139. LocalFree(ptd);
  1140. FreeLibrary(g_hInstance);
  1141. }
  1142. else
  1143. {
  1144. // Poll for cancel every 1/2 second
  1145. dwT = pap ? 500 : INFINITE;
  1146. while (WAIT_TIMEOUT == WaitForSingleObject(hThread, dwT))
  1147. {
  1148. BOOL bCancelled;
  1149. hr = pap->QueryCancel(&bCancelled);
  1150. // QueryCancel pumps messages, which somehow resets
  1151. // the cursor to normal. (_DoApply sets the hourglass)
  1152. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1153. if (SUCCEEDED(hr) && bCancelled)
  1154. {
  1155. // Abandon the worker thread
  1156. break;
  1157. }
  1158. }
  1159. // Check the result
  1160. bResult = TRUE;
  1161. dwT = ERROR_SUCCESS;
  1162. GetExitCodeThread(hThread, &dwT);
  1163. // If the exit code is STILL_ACTIVE, assume success.
  1164. // (failure tends to happen quickly -- access denied, etc.)
  1165. if (STILL_ACTIVE == dwT)
  1166. {
  1167. dwT = ERROR_SUCCESS;
  1168. }
  1169. if (ERROR_SUCCESS != dwT)
  1170. {
  1171. SetLastError(dwT);
  1172. bResult = FALSE;
  1173. }
  1174. CloseHandle(hThread);
  1175. }
  1176. }
  1177. if (pap)
  1178. {
  1179. pap->End();
  1180. pap->Release();
  1181. }
  1182. if (papd)
  1183. {
  1184. papd->Stop();
  1185. papd->Release();
  1186. }
  1187. // If we just made the folder private, check whether the user has
  1188. // a password. If not, offer to launch the User Accounts CPL.
  1189. if (bResult && 0 == dwLevel && !_UserHasPassword())
  1190. {
  1191. WCHAR szMsg[MAX_PATH];
  1192. WCHAR szCaption[50];
  1193. LoadStringW(g_hInstance, IDS_PRIVATE_CREATE_PASSWORD, szMsg, ARRAYLEN(szMsg));
  1194. LoadStringW(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
  1195. if (IDYES == MessageBoxW(_hwndPage, szMsg, szCaption, MB_YESNO | MB_ICONWARNING))
  1196. {
  1197. // Launch the User Accounts CPL to the password page
  1198. SHELLEXECUTEINFO sei = {0};
  1199. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  1200. sei.fMask = SEE_MASK_DOENVSUBST;
  1201. sei.hwnd = _hwndPage;
  1202. sei.nShow = SW_SHOWNORMAL;
  1203. sei.lpFile = TEXT("%SystemRoot%\\system32\\rundll32.exe");
  1204. sei.lpParameters = TEXT("shell32,Control_RunDLL nusrmgr.cpl ,initialTask=ChangePassword");
  1205. sei.lpDirectory = TEXT("%SystemRoot%\\system32");
  1206. ShellExecuteEx(&sei);
  1207. }
  1208. }
  1209. return bResult;
  1210. }
  1211. //+-------------------------------------------------------------------------
  1212. //
  1213. // Method: CSimpleSharingPage::_IsReadonlyShare, private
  1214. //
  1215. // Synopsis: Test whether the share ACL grants more than read access to
  1216. // Everyone or Guest.
  1217. //
  1218. //--------------------------------------------------------------------------
  1219. BOOL
  1220. CSimpleSharingPage::_IsReadonlyShare(
  1221. IN CShareInfo *pShareInfo
  1222. )
  1223. {
  1224. CHECK_SIG(CSimpleSharingPage);
  1225. BOOL bReadonly = TRUE;
  1226. // Get the current share ACL and check for read-only
  1227. PSECURITY_DESCRIPTOR pSD = pShareInfo->GetSecurityDescriptor();
  1228. if (NULL == pSD)
  1229. {
  1230. // Default security allows anyone to connect with Full Control
  1231. bReadonly = FALSE;
  1232. }
  1233. else
  1234. {
  1235. PACL pDacl;
  1236. BOOL bPresent;
  1237. BOOL bDefault;
  1238. if (GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefault) && NULL != pDacl)
  1239. {
  1240. TRUSTEE tEveryone;
  1241. TRUSTEE tGuests;
  1242. ACCESS_MASK dwAllMask = 0;
  1243. ACCESS_MASK dwGuestMask = 0;
  1244. // The masks are all initialized to zero. If one or more of the
  1245. // calls to GetEffectiveRightsFromAcl fails, then it will look like
  1246. // that trustee has no rights and the UI will adjust accordingly.
  1247. // There is nothing we could do better by trapping errors from
  1248. // GetEffectiveRightsFromAcl, so don't bother.
  1249. BuildTrusteeWithSid(&tEveryone, (PSID)&g_WorldSid);
  1250. tEveryone.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  1251. GetEffectiveRightsFromAcl(pDacl, &tEveryone, &dwAllMask);
  1252. BuildTrusteeWithSid(&tGuests, (PSID)&g_GuestsSid);
  1253. tGuests.TrusteeType = TRUSTEE_IS_ALIAS;
  1254. GetEffectiveRightsFromAcl(pDacl, &tGuests, &dwGuestMask);
  1255. if ((dwAllMask & ~(FILE_GENERIC_READ | FILE_GENERIC_EXECUTE)) != 0
  1256. || (dwGuestMask & ~(FILE_GENERIC_READ | FILE_GENERIC_EXECUTE)) != 0)
  1257. {
  1258. bReadonly = FALSE;
  1259. }
  1260. }
  1261. else
  1262. {
  1263. // NULL DACL means no security
  1264. bReadonly = FALSE;
  1265. }
  1266. }
  1267. return bReadonly;
  1268. }
  1269. //+-------------------------------------------------------------------------
  1270. //
  1271. // Method: CSimpleSharingPage::_UserHasPassword, private
  1272. //
  1273. // Synopsis: Test whether the current user has a non-blank password.
  1274. //
  1275. //--------------------------------------------------------------------------
  1276. BOOL
  1277. CSimpleSharingPage::_UserHasPassword(
  1278. VOID
  1279. )
  1280. {
  1281. CHECK_SIG(CSimpleSharingPage);
  1282. // If anything fails, we assume the user has a password
  1283. BOOL bHasPassword = TRUE;
  1284. ILogonEnumUsers *pEnumUsers;
  1285. HRESULT hr = CoCreateInstance(
  1286. CLSID_ShellLogonEnumUsers,
  1287. NULL,
  1288. CLSCTX_INPROC_SERVER,
  1289. IID_ILogonEnumUsers,
  1290. (void**)&pEnumUsers);
  1291. if (SUCCEEDED(hr))
  1292. {
  1293. ILogonUser *pUser;
  1294. // Currently, this function always returns S_OK, so need to check NULL
  1295. hr = pEnumUsers->get_currentUser(&pUser);
  1296. if (SUCCEEDED(hr) && NULL != pUser)
  1297. {
  1298. VARIANT_BOOL vb = VARIANT_TRUE;
  1299. hr = pUser->get_passwordRequired(&vb);
  1300. if (SUCCEEDED(hr))
  1301. {
  1302. if (VARIANT_FALSE == vb)
  1303. {
  1304. bHasPassword = FALSE;
  1305. }
  1306. }
  1307. pUser->Release();
  1308. }
  1309. pEnumUsers->Release();
  1310. }
  1311. return bHasPassword;
  1312. }
  1313. #if DBG == 1
  1314. //+-------------------------------------------------------------------------
  1315. //
  1316. // Method: CSimpleSharingPage::Dump, private
  1317. //
  1318. // Synopsis:
  1319. //
  1320. //--------------------------------------------------------------------------
  1321. VOID
  1322. CSimpleSharingPage::Dump(
  1323. IN PWSTR pszCaption
  1324. )
  1325. {
  1326. CHECK_SIG(CSimpleSharingPage);
  1327. appDebugOut((DEB_TRACE,
  1328. "CSimpleSharingPage::Dump, %ws\n",
  1329. pszCaption));
  1330. appDebugOut((DEB_TRACE | DEB_NOCOMPNAME,
  1331. "\t This: 0x%08lx\n"
  1332. "\t Path: %ws\n"
  1333. "\t Page: 0x%08lx\n"
  1334. "\t Initializing?: %ws\n"
  1335. "\t Dirty?: %ws\n"
  1336. "\t Share changed?: %ws\n"
  1337. "\tPrivate visible?: %ws\n"
  1338. "\t _dwPermType: 0x%08lx\n"
  1339. "\t _pInfoList: 0x%08lx\n"
  1340. "\t _pCurInfo: 0x%08lx\n"
  1341. "\t Shares: %d\n"
  1342. ,
  1343. this,
  1344. _pszPath,
  1345. _hwndPage,
  1346. _fInitializingPage ? L"yes" : L"no",
  1347. _bDirty ? L"yes" : L"no",
  1348. _bShareNameChanged ? L"yes" : L"no",
  1349. _bIsPrivateVisible ? L"yes" : L"no",
  1350. _dwPermType,
  1351. _pInfoList,
  1352. _pCurInfo,
  1353. _cShares
  1354. ));
  1355. CShareInfo* p;
  1356. for (p = (CShareInfo*) _pInfoList->Next();
  1357. p != _pInfoList;
  1358. p = (CShareInfo*) p->Next())
  1359. {
  1360. p->Dump(L"Prop page list");
  1361. }
  1362. for (p = (CShareInfo*) _pReplaceList->Next();
  1363. p != _pReplaceList;
  1364. p = (CShareInfo*) p->Next())
  1365. {
  1366. p->Dump(L"Replace list");
  1367. }
  1368. }
  1369. #endif // DBG == 1
  1370. //+-------------------------------------------------------------------------
  1371. //
  1372. // Method: _IsDaclPrivateForUser
  1373. //
  1374. // Synopsis: See whether the DACL grants Full Control to the user
  1375. // and locks everyone else out
  1376. //
  1377. //--------------------------------------------------------------------------
  1378. BOOL WINAPI
  1379. _IsDaclPrivateForUser(
  1380. IN PACL pDacl,
  1381. IN PCWSTR pszUserSID
  1382. )
  1383. {
  1384. BOOL bResult = FALSE;
  1385. static const struct
  1386. {
  1387. PSID psid;
  1388. TRUSTEE_TYPE type;
  1389. } rgTrustees[] =
  1390. {
  1391. {(PSID)&g_WorldSid, TRUSTEE_IS_WELL_KNOWN_GROUP},
  1392. {(PSID)&g_AdminsSid, TRUSTEE_IS_ALIAS},
  1393. {(PSID)&g_PowerUSid, TRUSTEE_IS_ALIAS},
  1394. {(PSID)&g_UsersSid, TRUSTEE_IS_ALIAS},
  1395. };
  1396. if (pDacl)
  1397. {
  1398. PSID psidUser = NULL;
  1399. TRUSTEE tTemp;
  1400. ACCESS_MASK dwUserMask = 0;
  1401. // The masks are all initialized to zero. If one or more of the
  1402. // calls to GetEffectiveRightsFromAcl fails, then it will look like
  1403. // that trustee has no rights and the UI will adjust accordingly.
  1404. // There is nothing we could do better by trapping errors from
  1405. // GetEffectiveRightsFromAcl, so don't bother.
  1406. if (ConvertStringSidToSid(pszUserSID, &psidUser))
  1407. {
  1408. BuildTrusteeWithSid(&tTemp, psidUser);
  1409. tTemp.TrusteeType = TRUSTEE_IS_USER;
  1410. GetEffectiveRightsFromAcl(pDacl, &tTemp, &dwUserMask);
  1411. LocalFree(psidUser);
  1412. }
  1413. //
  1414. // These tests may need some fine tuning
  1415. //
  1416. if ((dwUserMask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS)
  1417. {
  1418. ACCESS_MASK dwOtherMask = 0;
  1419. UINT i;
  1420. for (i = 0; i < ARRAYLEN(rgTrustees); i++)
  1421. {
  1422. ACCESS_MASK dwTempMask = 0;
  1423. BuildTrusteeWithSid(&tTemp, rgTrustees[i].psid);
  1424. tTemp.TrusteeType = rgTrustees[i].type;
  1425. GetEffectiveRightsFromAcl(pDacl, &tTemp, &dwTempMask);
  1426. dwOtherMask |= dwTempMask;
  1427. }
  1428. if ((dwOtherMask & ~(READ_CONTROL | SYNCHRONIZE)) == 0)
  1429. {
  1430. // Looks like the folder is private for this user
  1431. bResult = TRUE;
  1432. }
  1433. }
  1434. }
  1435. return bResult;
  1436. }
  1437. BOOL _IsVolumeNTFS(PCWSTR pszFolder)
  1438. {
  1439. WCHAR szVolume[MAX_PATH];
  1440. DWORD dwFSFlags = 0;
  1441. return (GetVolumePathNameW(pszFolder, szVolume, ARRAYLEN(szVolume)) &&
  1442. GetVolumeInformationW(szVolume, NULL, 0, NULL, NULL, &dwFSFlags, NULL, 0) &&
  1443. 0 != (FS_PERSISTENT_ACLS & dwFSFlags));
  1444. }
  1445. //+-------------------------------------------------------------------------
  1446. //
  1447. // Method: IsFolderPrivateForUser, exported
  1448. //
  1449. // Synopsis: Check the DACL on a folder
  1450. //
  1451. //--------------------------------------------------------------------------
  1452. BOOL WINAPI
  1453. IsFolderPrivateForUser(
  1454. IN PCWSTR pszFolderPath,
  1455. IN PCWSTR pszUserSID,
  1456. OUT PDWORD pdwPrivateType,
  1457. OUT PWSTR* ppszInheritanceSource
  1458. )
  1459. {
  1460. if (NULL != ppszInheritanceSource)
  1461. {
  1462. *ppszInheritanceSource = NULL;
  1463. }
  1464. if (NULL == pdwPrivateType)
  1465. {
  1466. return FALSE;
  1467. }
  1468. *pdwPrivateType = IFPFU_NOT_PRIVATE;
  1469. if (NULL == pszFolderPath || NULL == pszUserSID)
  1470. {
  1471. return FALSE;
  1472. }
  1473. // One would think that we could call GetNamedSecurityInfo without first
  1474. // checking for NTFS, and just let it fail on FAT volumes. However,
  1475. // GetNamedSecurityInfo succeeds on FAT and returns a valid security
  1476. // descriptor with a NULL DACL. This is actually correct in that
  1477. // a NULL DACL means no security, which is true on FAT.
  1478. //
  1479. // We then have the problem of trying to differentiate between a NULL
  1480. // DACL on an NTFS volume (it can happen), and a NULL DACL from a FAT
  1481. // volume. Let's just check for NTFS first.
  1482. if (!_IsVolumeNTFS(pszFolderPath))
  1483. {
  1484. // No ACLs, so we're done
  1485. *pdwPrivateType = IFPFU_NOT_NTFS;
  1486. return TRUE;
  1487. }
  1488. PSECURITY_DESCRIPTOR pSD = NULL;
  1489. PACL pDacl = NULL;
  1490. DWORD dwErr = GetNamedSecurityInfoW(
  1491. (PWSTR)pszFolderPath,
  1492. SE_FILE_OBJECT,
  1493. DACL_SECURITY_INFORMATION,
  1494. NULL,
  1495. NULL,
  1496. &pDacl,
  1497. NULL,
  1498. &pSD);
  1499. if (ERROR_SUCCESS == dwErr)
  1500. {
  1501. appAssert(NULL != pSD);
  1502. if (_IsDaclPrivateForUser(pDacl, pszUserSID))
  1503. {
  1504. SECURITY_DESCRIPTOR_CONTROL wControl = 0;
  1505. DWORD dwRevision;
  1506. *pdwPrivateType = IFPFU_PRIVATE;
  1507. // Check the control bits to see if we are inheriting
  1508. GetSecurityDescriptorControl(pSD, &wControl, &dwRevision);
  1509. if ((wControl & SE_DACL_PROTECTED) == 0)
  1510. {
  1511. // The DACL is not protected; assume the rights are inherited.
  1512. //
  1513. // When making a folder private, we always protect the DACL
  1514. // on the folder and reset child ACLs, so the assumption
  1515. // about inheriting is correct when using the simple UI.
  1516. //
  1517. // If someone uses the old Security page or cacls.exe to
  1518. // modify ACLs, then the safest thing is to disable the
  1519. // page and only let them reset everything from higher up.
  1520. // Well, it turns out that that's exactly what happens when
  1521. // we set IFPFU_PRIVATE_INHERITED.
  1522. *pdwPrivateType |= IFPFU_PRIVATE_INHERITED;
  1523. // Does the caller want the ancestor that made this
  1524. // subtree private?
  1525. if (NULL != ppszInheritanceSource)
  1526. {
  1527. PINHERITED_FROMW pInheritedFrom = (PINHERITED_FROMW)LocalAlloc(LPTR, sizeof(INHERITED_FROMW)*pDacl->AceCount);
  1528. if (pInheritedFrom != NULL)
  1529. {
  1530. dwErr = GetInheritanceSourceW(
  1531. (PWSTR)pszFolderPath,
  1532. SE_FILE_OBJECT,
  1533. DACL_SECURITY_INFORMATION,
  1534. TRUE,
  1535. NULL,
  1536. 0,
  1537. pDacl,
  1538. NULL,
  1539. &ShareMap,
  1540. pInheritedFrom);
  1541. if (ERROR_SUCCESS == dwErr)
  1542. {
  1543. PACE_HEADER pAceHeader;
  1544. UINT i;
  1545. PSID psidUser = NULL;
  1546. if (ConvertStringSidToSid(pszUserSID, &psidUser))
  1547. {
  1548. // Enumerate the ACEs looking for the ACE that grants
  1549. // Full Control to the current user
  1550. for (i = 0, pAceHeader = (PACE_HEADER)FirstAce(pDacl);
  1551. i < pDacl->AceCount;
  1552. i++, pAceHeader = (PACE_HEADER)NextAce(pAceHeader))
  1553. {
  1554. PKNOWN_ACE pAce = (PKNOWN_ACE)pAceHeader;
  1555. if (IsKnownAceType(pAceHeader) &&
  1556. EqualSid(psidUser, &pAce->SidStart) &&
  1557. (pAce->Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS)
  1558. {
  1559. // Found it. But we only want the inheritance
  1560. // source if it's not explicit.
  1561. if (pInheritedFrom[i].GenerationGap > 0)
  1562. {
  1563. *ppszInheritanceSource = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*wcslen(pInheritedFrom[i].AncestorName) + sizeof(L'\0'));
  1564. if (NULL != *ppszInheritanceSource)
  1565. {
  1566. wcscpy(*ppszInheritanceSource, pInheritedFrom[i].AncestorName);
  1567. }
  1568. }
  1569. // Stop looking
  1570. break;
  1571. }
  1572. }
  1573. LocalFree(psidUser);
  1574. }
  1575. }
  1576. LocalFree(pInheritedFrom);
  1577. }
  1578. }
  1579. }
  1580. }
  1581. LocalFree(pSD);
  1582. }
  1583. else
  1584. {
  1585. // GetNamedSecurityInfo failed. The path may not exist, or it may
  1586. // be FAT. In any case, assume permissions are not available.
  1587. *pdwPrivateType = IFPFU_NOT_NTFS;
  1588. }
  1589. return TRUE;
  1590. }
  1591. //+-------------------------------------------------------------------------
  1592. //
  1593. // Method: _MakeSecurityDescriptorForUser
  1594. //
  1595. // Synopsis: Insert a SID string into a string SD and convert it
  1596. // to a binary SD.
  1597. //
  1598. //--------------------------------------------------------------------------
  1599. BOOL
  1600. _MakeSecurityDescriptorForUser(PCWSTR pszSD, PCWSTR pszUserSID, PSECURITY_DESCRIPTOR *ppSD, PACL *ppDacl)
  1601. {
  1602. BOOL bResult;
  1603. WCHAR szSD[MAX_PATH];
  1604. PSECURITY_DESCRIPTOR pSD;
  1605. szSD[0] = L'\0';
  1606. wnsprintfW(szSD, ARRAYLEN(szSD), pszSD, pszUserSID);
  1607. bResult = ConvertStringSecurityDescriptorToSecurityDescriptorW(szSD, SDDL_REVISION_1, &pSD, NULL);
  1608. if (bResult)
  1609. {
  1610. *ppSD = pSD;
  1611. if (ppDacl)
  1612. {
  1613. BOOL bPresent;
  1614. BOOL bDefault;
  1615. GetSecurityDescriptorDacl(pSD, &bPresent, ppDacl, &bDefault);
  1616. }
  1617. }
  1618. return bResult;
  1619. }
  1620. int _ShowDeleteShareWarning(HWND hwndParent)
  1621. {
  1622. WCHAR szMsg[MAX_PATH];
  1623. WCHAR szCaption[50];
  1624. LoadStringW(g_hInstance, IDS_PRIVATE_CONFIRM_DELSHARE, szMsg, ARRAYLEN(szMsg));
  1625. LoadStringW(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
  1626. return MessageBoxW(hwndParent, szMsg, szCaption, MB_YESNO | MB_ICONWARNING);
  1627. }
  1628. BOOL _IsRootACLSecure(PACL pDacl)
  1629. {
  1630. TRUSTEE tTemp;
  1631. ACCESS_MASK dwMask = 0;
  1632. BuildTrusteeWithSid(&tTemp, (PSID)&g_WorldSid);
  1633. tTemp.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  1634. GetEffectiveRightsFromAcl(pDacl, &tTemp, &dwMask);
  1635. return !(dwMask & (WRITE_DAC | WRITE_OWNER));
  1636. }
  1637. //+-------------------------------------------------------------------------
  1638. //
  1639. // Method: SetFolderPermissionsForSharing, exported
  1640. //
  1641. // Parameters:
  1642. // pszFolderPath - Folder to adjust permissions on
  1643. // pszUserSID - User SID (NULL for current user)
  1644. // dwLevel - 0 = "private". Only the user and local system get access.
  1645. // 1 = "not shared". Remove explicit Everyone ACE.
  1646. // 2 = "shared read-only". Grant explicit RX to Everyone.
  1647. // 3 = "shared read/write". Grant explicit RWXD to Everyone.
  1648. // hwndParent - MessageBox parent. Set to NULL to prevent warnings.
  1649. //
  1650. // Synopsis: Set the DACL on a folder according to the sharing level
  1651. //
  1652. //--------------------------------------------------------------------------
  1653. #define SIZEOF_EVERYONE_ACE (sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG) + sizeof(g_WorldSid))
  1654. static const struct
  1655. {
  1656. DWORD AceFlags;
  1657. DWORD AccessMask;
  1658. } c_rgEveryoneAces[] =
  1659. {
  1660. {0, 0},
  1661. {CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, FILE_GENERIC_READ | FILE_GENERIC_EXECUTE},
  1662. {CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE},
  1663. };
  1664. //
  1665. // Hash algorithm borrowed from shell32\hash.c
  1666. //
  1667. ULONG _HashString(PCWSTR psz)
  1668. {
  1669. UINT hash = 314159269;
  1670. for(; *psz; psz++)
  1671. {
  1672. hash ^= (hash<<11) + (hash<<5) + (hash>>2) + (UINT)*psz;
  1673. }
  1674. return (hash & 0x7FFFFFFF);
  1675. }
  1676. BOOL WINAPI
  1677. SetFolderPermissionsForSharing(
  1678. IN PCWSTR pszFolderPath,
  1679. IN PCWSTR pszUserSID,
  1680. IN DWORD dwLevel,
  1681. IN HWND hwndParent
  1682. )
  1683. {
  1684. BOOL bResult = FALSE;
  1685. DWORD dwFolderFlags;
  1686. BOOL bSpecialFolderRoot = FALSE;
  1687. PCWSTR pszDefaultSD = NULL;
  1688. LPWSTR pszUserSIDToFree = NULL;
  1689. appDebugOut((DEB_ITRACE, "SetFolderPermissionsForSharing\n"));
  1690. if (dwLevel > 3)
  1691. {
  1692. appDebugOut((DEB_ITRACE, "Invalid sharing level\n"));
  1693. return FALSE;
  1694. }
  1695. dwFolderFlags = _CheckFolderType(pszFolderPath, pszUserSID, &bSpecialFolderRoot, &pszDefaultSD);
  1696. if (0 == (dwFolderFlags & (CFT_FLAG_SHARING_ALLOWED | CFT_FLAG_ROOT_FOLDER)))
  1697. {
  1698. appDebugOut((DEB_ITRACE, "Sharing not allowed on this folder\n"));
  1699. return FALSE;
  1700. }
  1701. if (0 == (dwFolderFlags & CFT_FLAG_CAN_MAKE_PRIVATE) && 0 == dwLevel)
  1702. {
  1703. appDebugOut((DEB_ITRACE, "Can't make this folder private\n"));
  1704. return FALSE;
  1705. }
  1706. // One would think that we could call GetNamedSecurityInfo without first
  1707. // checking for NTFS, and just let it fail on FAT volumes. However,
  1708. // GetNamedSecurityInfo succeeds on FAT and returns a valid security
  1709. // descriptor with a NULL DACL. This is actually correct in that
  1710. // a NULL DACL means no security, which is true on FAT.
  1711. //
  1712. // We then have the problem of trying to differentiate between a NULL
  1713. // DACL on an NTFS volume (it can happen), and a NULL DACL from a FAT
  1714. // volume. Let's just check for NTFS first.
  1715. if (!_IsVolumeNTFS(pszFolderPath))
  1716. {
  1717. // No ACLs, so we're done
  1718. return (0 != dwLevel);
  1719. }
  1720. // If we are making the folder private, first check whether any child
  1721. // folders are shared on the net. If so, warn that we are going to nuke them.
  1722. CShareInfo* pWarnList = NULL;
  1723. if (0 == dwLevel &&
  1724. SUCCEEDED(g_ShareCache.ConstructParentWarnList(pszFolderPath, &pWarnList)) &&
  1725. NULL != pWarnList &&
  1726. NULL != hwndParent)
  1727. {
  1728. if (IDNO == _ShowDeleteShareWarning(hwndParent))
  1729. {
  1730. DeleteShareInfoList(pWarnList, TRUE);
  1731. return FALSE;
  1732. }
  1733. // JonN 4/04/01 328512
  1734. // Explorer Sharing Tab (NTSHRUI) should popup warning on deleting
  1735. // SYSVOL,NETLOGON and C$, D$... shares
  1736. for (CShareInfo* p = (CShareInfo*)pWarnList->Next();
  1737. p != pWarnList;
  1738. )
  1739. {
  1740. CShareInfo* pNext = (CShareInfo*)p->Next();
  1741. DWORD id = ConfirmStopShare( hwndParent, MB_YESNO, p->GetNetname() );
  1742. if ( IDYES != id )
  1743. {
  1744. DeleteShareInfoList(pWarnList, TRUE);
  1745. return FALSE;
  1746. }
  1747. p = pNext;
  1748. }
  1749. }
  1750. // No more early returns after this point (have to free pWarnList)
  1751. if (NULL == pszUserSID || L'\0' == pszUserSID[0])
  1752. {
  1753. _GetUserSid(&pszUserSIDToFree);
  1754. pszUserSID = pszUserSIDToFree;
  1755. }
  1756. // Use a mutex to prevent multiple threads from setting permissions on the
  1757. // same folder at the same time. The mutex name cannot contain '\' so hash
  1758. // the path to obtain a name unique to this folder.
  1759. WCHAR szMutex[30];
  1760. wsprintfW(szMutex, L"share perms %x", _HashString(pszFolderPath));
  1761. HANDLE hMutex = CreateMutex(NULL, FALSE, szMutex);
  1762. if (NULL != hMutex)
  1763. {
  1764. WaitForSingleObject(hMutex, INFINITE);
  1765. if (pszUserSID)
  1766. {
  1767. PSECURITY_DESCRIPTOR pSD = NULL;
  1768. PACL pDacl = NULL;
  1769. DWORD dwErr = GetNamedSecurityInfoW(
  1770. (PWSTR)pszFolderPath,
  1771. SE_FILE_OBJECT,
  1772. DACL_SECURITY_INFORMATION,
  1773. NULL,
  1774. NULL,
  1775. &pDacl,
  1776. NULL,
  1777. &pSD);
  1778. if (ERROR_SUCCESS == dwErr)
  1779. {
  1780. PACL pDaclToFree = NULL;
  1781. appAssert(NULL != pSD);
  1782. if (dwFolderFlags & CFT_FLAG_CAN_MAKE_PRIVATE)
  1783. {
  1784. if (_IsDaclPrivateForUser(pDacl, pszUserSID))
  1785. {
  1786. // _IsDaclPrivateForUser returns FALSE if pDacl is NULL
  1787. appAssert(NULL != pDacl);
  1788. if (0 == dwLevel)
  1789. {
  1790. // Already private, nothing to do
  1791. bResult = TRUE;
  1792. pDacl = NULL;
  1793. }
  1794. else // making public
  1795. {
  1796. if (bSpecialFolderRoot)
  1797. {
  1798. // Taking a special folder that was private, and making
  1799. // it public. First need to reset the DACL to default.
  1800. // (Special folders often have protected DACLs.)
  1801. if (pszDefaultSD)
  1802. {
  1803. LocalFree(pSD);
  1804. pSD = NULL;
  1805. pDacl = NULL;
  1806. // If this fails, pDacl will be NULL and we will fail below
  1807. _MakeSecurityDescriptorForUser(pszDefaultSD, pszUserSID, &pSD, &pDacl);
  1808. appDebugOut((DEB_ITRACE, "Using default security descriptor\n"));
  1809. }
  1810. }
  1811. else // not root of special folder
  1812. {
  1813. SECURITY_DESCRIPTOR_CONTROL wControl = 0;
  1814. DWORD dwRevision;
  1815. // Check the control bits to see if we are inheriting
  1816. GetSecurityDescriptorControl(pSD, &wControl, &dwRevision);
  1817. if ((wControl & SE_DACL_PROTECTED) == 0)
  1818. {
  1819. // Inheriting from parent, assume the parent folder
  1820. // is private. Can't make a subfolder public.
  1821. pDacl = NULL;
  1822. appDebugOut((DEB_ITRACE, "Can't make private subfolder public\n"));
  1823. }
  1824. else
  1825. {
  1826. // This folder is private and we're making it public.
  1827. // Eliminate all explicit ACEs and reset the protected
  1828. // bit so it inherits normal permissions from its parent.
  1829. pDacl->AceCount = 0;
  1830. SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED, 0);
  1831. }
  1832. }
  1833. }
  1834. }
  1835. else // Not currently private
  1836. {
  1837. if (0 == dwLevel)
  1838. {
  1839. // Reset the DACL to private before continuing below
  1840. LocalFree(pSD);
  1841. pSD = NULL;
  1842. pDacl = NULL;
  1843. // If this fails, pDacl will be NULL and we will fail below
  1844. _MakeSecurityDescriptorForUser(c_szPrivateFolderSD, pszUserSID, &pSD, &pDacl);
  1845. }
  1846. }
  1847. }
  1848. else // can't make private
  1849. {
  1850. // We check for this above
  1851. appAssert(0 != dwLevel);
  1852. }
  1853. if ((dwFolderFlags & CFT_FLAG_ROOT_FOLDER) && NULL != pDacl)
  1854. {
  1855. // Currently can't make root folders private
  1856. appAssert(0 != dwLevel);
  1857. //
  1858. // NTRAID#NTBUG9-378617-2001/05/04-jeffreys
  1859. //
  1860. // Root ACLs tend to have an explicit Everyone ACE, which
  1861. // screws us up in some cases. Easiest thing is to start
  1862. // with a new ACL and don't touch the Everyone entry below.
  1863. //
  1864. BOOL bRootIsSecure = _IsRootACLSecure(pDacl);
  1865. LocalFree(pSD);
  1866. pSD = NULL;
  1867. pDacl = NULL;
  1868. // If this fails, pDacl will be NULL and we will fail below
  1869. _MakeSecurityDescriptorForUser(bRootIsSecure ? c_szRootSDSecure : c_szRootSDUnsecure, pszUserSID, &pSD, &pDacl);
  1870. appDebugOut((DEB_ITRACE, "Using default security descriptor\n"));
  1871. }
  1872. //
  1873. // If we're making the folder public, adjust the existing ACL
  1874. //
  1875. if (NULL != pDacl && 0 != dwLevel)
  1876. {
  1877. PKNOWN_ACE pAce;
  1878. int iEntry;
  1879. USHORT cAces = 0;
  1880. ULONG cbExplicitAces = 0;
  1881. // Adjust the level to use as an index into c_rgEveryoneAces
  1882. DWORD dwPublicLevel = dwLevel - 1;
  1883. appAssert(dwPublicLevel < ARRAYLEN(c_rgEveryoneAces));
  1884. for (iEntry = 0, pAce = (PKNOWN_ACE)FirstAce(pDacl);
  1885. iEntry < pDacl->AceCount;
  1886. iEntry++, pAce = (PKNOWN_ACE)NextAce(pAce))
  1887. {
  1888. // Assuming the ACL is canonical, we can stop as soon as we find
  1889. // an inherited ACE, since the rest will all be inherited and we
  1890. // can't modify those.
  1891. if (AceInherited(&pAce->Header))
  1892. break;
  1893. cAces++;
  1894. cbExplicitAces += pAce->Header.AceSize;
  1895. if (!(dwFolderFlags & CFT_FLAG_ROOT_FOLDER) &&
  1896. IsKnownAceType(pAce) &&
  1897. EqualSid((PSID)&pAce->SidStart, (PSID)&g_WorldSid))
  1898. {
  1899. pAce->Header.AceFlags = (UCHAR)c_rgEveryoneAces[dwPublicLevel].AceFlags;
  1900. pAce->Mask = c_rgEveryoneAces[dwPublicLevel].AccessMask;
  1901. // We don't need to add another Everyone ACE below
  1902. dwPublicLevel = 0;
  1903. }
  1904. }
  1905. // Trim off inherited ACEs. We don't need to include them when
  1906. // saving the new ACL, and this generally leaves enough space
  1907. // in the ACL to add an Everyone ACE if we need to.
  1908. pDacl->AceCount = cAces;
  1909. if (0 != dwPublicLevel)
  1910. {
  1911. // Need to add an explicit entry for Everyone.
  1912. ULONG cbAclSize = sizeof(ACL) + SIZEOF_EVERYONE_ACE + cbExplicitAces;
  1913. if (cbAclSize > (ULONG)pDacl->AclSize)
  1914. {
  1915. // No room in the existing ACL. Allocate a new
  1916. // ACL and copy existing entries (if any)
  1917. pDaclToFree = (PACL)LocalAlloc(LPTR, cbAclSize);
  1918. if (NULL != pDaclToFree)
  1919. {
  1920. CopyMemory(pDaclToFree, pDacl, pDacl->AclSize);
  1921. pDaclToFree->AclSize = (USHORT)cbAclSize;
  1922. pDacl = pDaclToFree;
  1923. }
  1924. else
  1925. {
  1926. // Fail
  1927. pDacl = NULL;
  1928. appDebugOut((DEB_ITRACE, "Unable to alloc buffer for new ACL\n"));
  1929. }
  1930. }
  1931. if (NULL != pDacl)
  1932. {
  1933. appAssert(cbAclSize <= (ULONG)pDacl->AclSize);
  1934. if (!AddAccessAllowedAceEx(pDacl,
  1935. ACL_REVISION2,
  1936. c_rgEveryoneAces[dwPublicLevel].AceFlags,
  1937. c_rgEveryoneAces[dwPublicLevel].AccessMask,
  1938. (PSID)&g_WorldSid))
  1939. {
  1940. // Fail
  1941. pDacl = NULL;
  1942. appDebugOut((DEB_ITRACE, "Unable to add Everyone ACE\n"));
  1943. }
  1944. }
  1945. }
  1946. }
  1947. //
  1948. // Set the new DACL on the folder
  1949. //
  1950. if (NULL != pDacl)
  1951. {
  1952. SECURITY_INFORMATION si;
  1953. SECURITY_DESCRIPTOR_CONTROL wControl = 0;
  1954. DWORD dwRevision;
  1955. GetSecurityDescriptorControl(pSD, &wControl, &dwRevision);
  1956. if (SE_DACL_PROTECTED & wControl)
  1957. {
  1958. // The security descriptor specifies SE_DACL_PROTECTED
  1959. si = DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION;
  1960. }
  1961. else
  1962. {
  1963. // Prevent the system from automagically protecting the DACL
  1964. si = DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
  1965. }
  1966. if (0 == dwLevel)
  1967. {
  1968. // To make the folder private, we have to make sure we blow
  1969. // away any explicit permissions on children, so use
  1970. // TreeResetNamedSecurityInfo with KeepExplicit = FALSE.
  1971. // TreeResetNamedSecurityInfo has a callback mechanism, but
  1972. // we currently don't use it. Note that the paths passed to
  1973. // the callback look like
  1974. // "\Device\HarddiskVolume1\dir\name"
  1975. appDebugOut((DEB_ITRACE, "Making folder private; resetting child ACLs\n"));
  1976. appAssert(si == (DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION));
  1977. dwErr = TreeResetNamedSecurityInfoW(
  1978. (PWSTR)pszFolderPath,
  1979. SE_FILE_OBJECT,
  1980. si,
  1981. NULL,
  1982. NULL,
  1983. pDacl,
  1984. NULL,
  1985. FALSE, // KeepExplicit (perms on children)
  1986. NULL,
  1987. ProgressInvokeNever,
  1988. NULL
  1989. );
  1990. if (ERROR_SUCCESS == dwErr && NULL != pWarnList)
  1991. {
  1992. // Nuke child shares
  1993. for (CShareInfo* p = (CShareInfo*)pWarnList->Next();
  1994. p != pWarnList;
  1995. )
  1996. {
  1997. CShareInfo* pNext = (CShareInfo*)p->Next();
  1998. if (p->GetFlag() != SHARE_FLAG_ADDED)
  1999. {
  2000. p->SetDirtyFlag(SHARE_FLAG_REMOVE);
  2001. p->Commit(NULL);
  2002. SHChangeNotify(SHCNE_NETSHARE, SHCNF_PATH, p->GetPath(), NULL);
  2003. }
  2004. // get rid of p
  2005. p->Unlink();
  2006. delete p;
  2007. p = pNext;
  2008. }
  2009. }
  2010. }
  2011. else
  2012. {
  2013. // To make the folder public, we grant access at this level
  2014. // without blowing away child permissions, including DACL
  2015. // protection. This means that a private subfolder will still
  2016. // be private. Use SetNamedSecurityInfo for these, since
  2017. // TreeResetNamedSecurityInfo always removes SE_DACL_PROTECTED
  2018. // from children.
  2019. dwErr = SetNamedSecurityInfoW(
  2020. (PWSTR)pszFolderPath,
  2021. SE_FILE_OBJECT,
  2022. si,
  2023. NULL,
  2024. NULL,
  2025. pDacl,
  2026. NULL);
  2027. }
  2028. if (ERROR_SUCCESS == dwErr)
  2029. {
  2030. bResult = TRUE;
  2031. }
  2032. }
  2033. LocalFree(pDaclToFree);
  2034. LocalFree(pSD);
  2035. }
  2036. }
  2037. ReleaseMutex(hMutex);
  2038. CloseHandle(hMutex);
  2039. }
  2040. LocalFree(pszUserSIDToFree);
  2041. if (NULL != pWarnList)
  2042. {
  2043. DeleteShareInfoList(pWarnList, TRUE);
  2044. }
  2045. return bResult;
  2046. }
  2047. //
  2048. // Description:
  2049. // Dialog proc for the enabling sharing warning dialog.
  2050. //
  2051. INT_PTR
  2052. WarningDlgProc(
  2053. IN HWND hWnd,
  2054. IN UINT msg,
  2055. IN WPARAM wParam,
  2056. IN LPARAM lParam
  2057. )
  2058. {
  2059. switch (msg)
  2060. {
  2061. case WM_INITDIALOG:
  2062. {
  2063. //
  2064. // Load warning icon from USER32.
  2065. //
  2066. HICON hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_WARNING));
  2067. if (hIcon)
  2068. {
  2069. SendDlgItemMessage(hWnd, IDC_ICON_INFO, STM_SETICON, (WPARAM )hIcon, 0L);
  2070. }
  2071. //
  2072. // Set default radio item.
  2073. //
  2074. SendDlgItemMessage(hWnd, IDC_RB_RUN_THE_WIZARD, BM_SETCHECK, BST_CHECKED, 0);
  2075. }
  2076. break;
  2077. case WM_COMMAND:
  2078. switch (LOWORD(wParam))
  2079. {
  2080. case IDOK:
  2081. if ( BN_CLICKED == HIWORD(wParam) )
  2082. {
  2083. UINT iRet = (UINT) SendDlgItemMessage(hWnd, IDC_RB_RUN_THE_WIZARD, BM_GETCHECK, 0, 0 );
  2084. if ( BST_CHECKED == iRet )
  2085. {
  2086. EndDialog(hWnd, IDC_RB_RUN_THE_WIZARD );
  2087. }
  2088. else
  2089. {
  2090. EndDialog(hWnd, IDC_RB_ENABLE_FILE_SHARING );
  2091. }
  2092. }
  2093. break;
  2094. case IDCANCEL:
  2095. if ( BN_CLICKED == HIWORD(wParam) )
  2096. {
  2097. EndDialog(hWnd, IDCANCEL);
  2098. return TRUE;
  2099. }
  2100. break;
  2101. }
  2102. break;
  2103. }
  2104. return FALSE;
  2105. }