Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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