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.

1266 lines
32 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-1997 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // EditAcl.cpp
  7. //
  8. // Abstract:
  9. // Implementation of ACL editor methods.
  10. //
  11. // Author:
  12. // David Potter (davidp) October 9, 1996
  13. // From \nt\private\window\shell\lmui\ntshrui\acl.cxx
  14. // by BruceFo
  15. //
  16. // Revision History:
  17. //
  18. // Notes:
  19. //
  20. /////////////////////////////////////////////////////////////////////////////
  21. #include "stdafx.h"
  22. #include <lmerr.h>
  23. extern "C"
  24. {
  25. #include <sedapi.h>
  26. }
  27. #include "EditAcl.h"
  28. #include "AclHelp.h"
  29. #include "resource.h"
  30. #ifdef _DEBUG
  31. #define new DEBUG_NEW
  32. #undef THIS_FILE
  33. static char THIS_FILE[] = __FILE__;
  34. #endif
  35. //////////////////////////////////////////////////////////////////////////////
  36. //////////////////////////////////////////////////////////////////////////////
  37. #define ARRAYLEN(a) (sizeof(a) / sizeof((a)[0]))
  38. enum SED_PERM_TYPE{
  39. SED_AUDITS,
  40. SED_ACCESSES,
  41. SED_OWNER
  42. };
  43. enum MAP_DIRECTION
  44. {
  45. SPECIFIC_TO_GENERIC = 0,
  46. GENERIC_TO_SPECIFIC = 1
  47. };
  48. const DWORD LOCAL_ACCOUNTS_FILTERED = 2L;
  49. const BOOL bIsFile = 0;
  50. //#define MAPBITS
  51. BOOL MapBitsInSD(PSECURITY_DESCRIPTOR pSecDesc, MAP_DIRECTION direction);
  52. BOOL MapBitsInACL(PACL paclACL, MAP_DIRECTION direction);
  53. BOOL MapSpecificBitsInAce(PACCESS_ALLOWED_ACE pAce);
  54. BOOL MapGenericBitsInAce(PACCESS_ALLOWED_ACE pAce);
  55. typedef
  56. DWORD
  57. (*SedDiscretionaryAclEditorType)(
  58. HWND Owner,
  59. HANDLE Instance,
  60. LPWSTR Server,
  61. PSED_OBJECT_TYPE_DESCRIPTOR ObjectType,
  62. PSED_APPLICATION_ACCESSES ApplicationAccesses,
  63. LPWSTR ObjectName,
  64. PSED_FUNC_APPLY_SEC_CALLBACK ApplySecurityCallbackRoutine,
  65. ULONG CallbackContext,
  66. PSECURITY_DESCRIPTOR SecurityDescriptor,
  67. BOOLEAN CouldntReadDacl,
  68. BOOLEAN CantWriteDacl,
  69. LPDWORD SEDStatusReturn,
  70. DWORD Flags
  71. );
  72. // NOTE: the SedDiscretionaryAclEditor string is used in GetProcAddress to
  73. // get the correct entrypoint. Since GetProcAddress is not UNICODE, this string
  74. // must be ANSI.
  75. #define ACLEDIT_DLL_STRING TEXT("acledit.dll")
  76. #define ACLEDIT_HELPFILENAME TEXT("ntshrui.hlp")
  77. #define SEDDISCRETIONARYACLEDITOR_STRING ("SedDiscretionaryAclEditor")
  78. //
  79. // Declare the callback routine based on typedef in sedapi.h.
  80. //
  81. DWORD
  82. SedCallback(
  83. HWND hwndParent,
  84. HANDLE hInstance,
  85. ULONG ulCallbackContext,
  86. PSECURITY_DESCRIPTOR pSecDesc,
  87. PSECURITY_DESCRIPTOR pSecDescNewObjects,
  88. BOOLEAN fApplyToSubContainers,
  89. BOOLEAN fApplyToSubObjects,
  90. LPDWORD StatusReturn
  91. );
  92. //
  93. // Structure for callback function's usage. A pointer to this is passed as
  94. // ulCallbackContext. The callback functions sets bSecDescModified to TRUE
  95. // and makes a copy of the security descriptor. The caller of EditShareAcl
  96. // is responsible for deleting the memory in pSecDesc if bSecDescModified is
  97. // TRUE. This flag will be FALSE if the user hit CANCEL in the ACL editor.
  98. //
  99. struct SHARE_CALLBACK_INFO
  100. {
  101. BOOL bSecDescModified;
  102. PSECURITY_DESCRIPTOR pSecDesc;
  103. LPCTSTR pszClusterNameNode;
  104. };
  105. //
  106. // Local function prototypes
  107. //
  108. VOID
  109. InitializeShareGenericMapping(
  110. IN OUT PGENERIC_MAPPING pSHAREGenericMapping
  111. );
  112. PWSTR
  113. GetResourceString(
  114. IN DWORD dwId
  115. );
  116. PWSTR
  117. NewDup(
  118. IN const WCHAR* psz
  119. );
  120. //
  121. // The following two arrays define the permission names for NT Files. Note
  122. // that each index in one array corresponds to the index in the other array.
  123. // The second array will be modifed to contain a string pointer pointing to
  124. // a loaded string corresponding to the IDS_* in the first array.
  125. //
  126. DWORD g_dwSharePermNames[] =
  127. {
  128. IDS_ACLEDIT_PERM_GEN_NO_ACCESS,
  129. IDS_ACLEDIT_PERM_GEN_READ,
  130. IDS_ACLEDIT_PERM_GEN_MODIFY,
  131. IDS_ACLEDIT_PERM_GEN_ALL
  132. };
  133. SED_APPLICATION_ACCESS g_SedAppAccessSharePerms[] =
  134. {
  135. { SED_DESC_TYPE_RESOURCE, FILE_PERM_NO_ACCESS, 0, NULL },
  136. { SED_DESC_TYPE_RESOURCE, FILE_PERM_READ, 0, NULL },
  137. { SED_DESC_TYPE_RESOURCE, FILE_PERM_MODIFY, 0, NULL },
  138. { SED_DESC_TYPE_RESOURCE, FILE_PERM_ALL, 0, NULL }
  139. /*
  140. { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_NO_ACCESS, 0, NULL },
  141. { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_READ, 0, NULL },
  142. { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_MODIFY, 0, NULL },
  143. { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_ALL, 0, NULL }
  144. */
  145. };
  146. //////////////////////////////////////////////////////////////////////////////
  147. //////////////////////////////////////////////////////////////////////////////
  148. //+-------------------------------------------------------------------------
  149. //
  150. // Function: EditShareAcl
  151. //
  152. // Synopsis: Invokes the generic ACL editor, specifically for NT shares
  153. //
  154. // Arguments: [hwndParent] - Parent window handle
  155. // [pszServerName] - Name of server on which the object resides.
  156. // [pszShareName] - Fully qualified name of resource we will
  157. // edit, basically a share name.
  158. // [pSecDesc] - The initial security descriptor. If NULL, we will
  159. // create a default that is "World all" access.
  160. // [pbSecDescModified] - Set to TRUE if the security descriptor
  161. // was modified (i.e., the user hit "OK"), or FALSE if not
  162. // (i.e., the user hit "Cancel")
  163. // [ppSecDesc] - *ppSecDesc points to a new security descriptor
  164. // if *pbSecDescModified is TRUE. This memory must be freed
  165. // by the caller.
  166. //
  167. // History:
  168. // ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code.
  169. // Yi-HsinS 09-Oct-1992 Added ulHelpContextBase
  170. // BruceFo 4-Apr-95 Stole and used in ntshrui.dll
  171. // DavidP 10-Oct-1996 Modified for use with CLUADMIN
  172. //
  173. //--------------------------------------------------------------------------
  174. LONG
  175. EditShareAcl(
  176. IN HWND hwndParent,
  177. IN LPCTSTR pszServerName,
  178. IN LPCTSTR pszShareName,
  179. IN LPCTSTR pszClusterNameNode,
  180. IN PSECURITY_DESCRIPTOR pSecDesc,
  181. OUT BOOL * pbSecDescModified,
  182. OUT PSECURITY_DESCRIPTOR * ppSecDesc
  183. )
  184. {
  185. ASSERT(pszShareName != NULL);
  186. ASSERT(pszClusterNameNode != NULL);
  187. TRACE(_T("EditShareAcl, share %ws\n"), pszShareName);
  188. ASSERT((pSecDesc == NULL) || IsValidSecurityDescriptor(pSecDesc));
  189. ASSERT(pbSecDescModified != NULL);
  190. ASSERT(ppSecDesc != NULL);
  191. *pbSecDescModified = FALSE;
  192. LONG err = 0 ;
  193. PWSTR pszPermName;
  194. BOOL bCreatedDefaultSecDesc = FALSE;
  195. do // error breakout
  196. {
  197. /*
  198. * if pSecDesc is NULL, this is new file share or a file share with no
  199. * security descriptor.
  200. * we go and create a new (default) security descriptor.
  201. */
  202. if( NULL == pSecDesc )
  203. {
  204. TRACE(_T("Security Descriptor is NULL. Grant everyone Full Control\n") );
  205. LONG err = CreateDefaultSecDesc( &pSecDesc );
  206. if (err != NERR_Success)
  207. {
  208. err = GetLastError();
  209. TRACE(_T("CreateDefaultSecDesc failed, 0x%08lx\n"), err);
  210. break;
  211. }
  212. TRACE(_T("CreateDefaultSecDesc descriptor = 0x%08lx\n"), pSecDesc);
  213. bCreatedDefaultSecDesc = TRUE;
  214. }
  215. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  216. /* Retrieve the resource strings appropriate for the type of object we
  217. * are looking at
  218. */
  219. CString strTypeName;
  220. CString strDefaultPermName;
  221. try
  222. {
  223. strTypeName.LoadString(IDS_ACLEDIT_TITLE);
  224. strDefaultPermName.LoadString(IDS_ACLEDIT_PERM_GEN_ALL);
  225. } // try
  226. catch (CMemoryException * pme)
  227. {
  228. pme->Delete();
  229. }
  230. /*
  231. * other misc stuff we need pass to security editor
  232. */
  233. SED_OBJECT_TYPE_DESCRIPTOR sedObjDesc ;
  234. SED_HELP_INFO sedHelpInfo ;
  235. GENERIC_MAPPING SHAREGenericMapping ;
  236. // setup mappings
  237. InitializeShareGenericMapping( &SHAREGenericMapping ) ;
  238. WCHAR szHelpFile[50] = ACLEDIT_HELPFILENAME;
  239. sedHelpInfo.pszHelpFileName = szHelpFile;
  240. sedHelpInfo.aulHelpContext[HC_MAIN_DLG] = HC_UI_SHELL_BASE + HC_NTSHAREPERMS ;
  241. sedHelpInfo.aulHelpContext[HC_ADD_USER_DLG] = HC_UI_SHELL_BASE + HC_SHAREADDUSER ;
  242. sedHelpInfo.aulHelpContext[HC_ADD_USER_MEMBERS_GG_DLG] = HC_UI_SHELL_BASE + HC_SHAREADDUSER_GLOBALGROUP ;
  243. sedHelpInfo.aulHelpContext[HC_ADD_USER_SEARCH_DLG] = HC_UI_SHELL_BASE + HC_SHAREADDUSER_FINDUSER ;
  244. // These are not used, set to zero
  245. sedHelpInfo.aulHelpContext[HC_SPECIAL_ACCESS_DLG] = 0 ;
  246. sedHelpInfo.aulHelpContext[HC_NEW_ITEM_SPECIAL_ACCESS_DLG] = 0 ;
  247. // setup the object description
  248. sedObjDesc.Revision = SED_REVISION1 ;
  249. sedObjDesc.IsContainer = FALSE ;
  250. sedObjDesc.AllowNewObjectPerms = FALSE ;
  251. sedObjDesc.MapSpecificPermsToGeneric = TRUE ;
  252. sedObjDesc.GenericMapping = &SHAREGenericMapping ;
  253. sedObjDesc.GenericMappingNewObjects = &SHAREGenericMapping ;
  254. sedObjDesc.ObjectTypeName = (LPWSTR) (LPCWSTR) strTypeName ;
  255. sedObjDesc.HelpInfo = &sedHelpInfo ;
  256. sedObjDesc.SpecialObjectAccessTitle = NULL ;
  257. /* Now we need to load the global arrays with the permission names
  258. * from the resource file.
  259. */
  260. UINT cArrayItems = ARRAYLEN(g_SedAppAccessSharePerms);
  261. PSED_APPLICATION_ACCESS aSedAppAccess = g_SedAppAccessSharePerms ;
  262. /* Loop through each permission title retrieving the text from the
  263. * resource file and setting the pointer in the array.
  264. */
  265. for ( UINT i = 0 ; i < cArrayItems ; i++ )
  266. {
  267. pszPermName = GetResourceString(g_dwSharePermNames[i]) ;
  268. if (NULL == pszPermName)
  269. {
  270. TRACE(_T("GetResourceString failed\n"));
  271. break ;
  272. }
  273. aSedAppAccess[i].PermissionTitle = pszPermName;
  274. }
  275. if (i < cArrayItems)
  276. {
  277. TRACE(_T("failed to get all share permission names\n"));
  278. break ;
  279. }
  280. SED_APPLICATION_ACCESSES sedAppAccesses ;
  281. sedAppAccesses.Count = cArrayItems ;
  282. sedAppAccesses.AccessGroup = aSedAppAccess ;
  283. sedAppAccesses.DefaultPermName = (LPWSTR) (LPCWSTR) strDefaultPermName;
  284. /*
  285. * pass this along so when the call back function is called,
  286. * we can set it.
  287. */
  288. SHARE_CALLBACK_INFO callbackinfo ;
  289. callbackinfo.pSecDesc = NULL;
  290. callbackinfo.bSecDescModified = FALSE;
  291. callbackinfo.pszClusterNameNode = pszClusterNameNode;
  292. //
  293. // Now, load up the ACL editor and invoke it. We don't keep it around
  294. // because our DLL is loaded whenever the system is, so we don't want
  295. // the netui*.dll's hanging around as well...
  296. //
  297. HINSTANCE hInstanceAclEditor = NULL;
  298. SedDiscretionaryAclEditorType pAclEditor = NULL;
  299. hInstanceAclEditor = LoadLibrary(ACLEDIT_DLL_STRING);
  300. if (NULL == hInstanceAclEditor)
  301. {
  302. err = GetLastError();
  303. TRACE(_T("LoadLibrary of acledit.dll failed, 0x%08lx\n"), err);
  304. break;
  305. }
  306. pAclEditor = (SedDiscretionaryAclEditorType) GetProcAddress(
  307. hInstanceAclEditor,
  308. SEDDISCRETIONARYACLEDITOR_STRING
  309. );
  310. if ( pAclEditor == NULL )
  311. {
  312. err = GetLastError();
  313. TRACE(_T("GetProcAddress of SedDiscretionaryAclEditorType failed, 0x%08lx\n"), err);
  314. break;
  315. }
  316. #ifdef MAPBITS
  317. MapBitsInSD( pSecDesc, SPECIFIC_TO_GENERIC );
  318. #endif
  319. DWORD dwSedReturnStatus ;
  320. ASSERT(pAclEditor != NULL);
  321. err = (*pAclEditor)(
  322. hwndParent,
  323. AfxGetInstanceHandle(),
  324. (LPTSTR) pszServerName,
  325. &sedObjDesc,
  326. &sedAppAccesses,
  327. (LPTSTR) pszShareName,
  328. SedCallback,
  329. (ULONG) &callbackinfo,
  330. pSecDesc,
  331. FALSE, // always can read
  332. FALSE, // if we can read, we can write
  333. (LPDWORD) &dwSedReturnStatus,
  334. 0
  335. );
  336. if (pSecDesc != NULL)
  337. {
  338. #ifdef MAPBITS
  339. MapBitsInSD( pSecDesc, GENERIC_TO_SPECIFIC );
  340. #endif
  341. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  342. } // if: no security descriptor returned
  343. if (!FreeLibrary(hInstanceAclEditor))
  344. {
  345. LONG err2 = GetLastError();
  346. TRACE(_T("FreeLibrary of acledit.dll failed, 0x%08lx\n"), err2);
  347. // not fatal: continue...
  348. }
  349. if (0 != err)
  350. {
  351. TRACE(_T("SedDiscretionaryAclEditor failed, 0x%08lx\n"), err);
  352. break ;
  353. }
  354. *pbSecDescModified = callbackinfo.bSecDescModified ;
  355. if (*pbSecDescModified)
  356. {
  357. *ppSecDesc = callbackinfo.pSecDesc;
  358. #ifdef MAPBITS
  359. MapBitsInSD( *ppSecDesc, GENERIC_TO_SPECIFIC );
  360. #endif
  361. TRACE(_T("After calling acl editor, *ppSecDesc = 0x%08lx\n"), *ppSecDesc);
  362. ASSERT(IsValidSecurityDescriptor(*ppSecDesc));
  363. }
  364. } while (FALSE) ;
  365. //
  366. // Free memory...
  367. //
  368. UINT cArrayItems = ARRAYLEN(g_SedAppAccessSharePerms);
  369. PSED_APPLICATION_ACCESS aSedAppAccess = g_SedAppAccessSharePerms ;
  370. for ( UINT i = 0 ; i < cArrayItems ; i++ )
  371. {
  372. pszPermName = aSedAppAccess[i].PermissionTitle;
  373. if (NULL == pszPermName)
  374. {
  375. // if we hit a NULL, that's it!
  376. break ;
  377. }
  378. delete[] pszPermName;
  379. }
  380. if (bCreatedDefaultSecDesc)
  381. {
  382. DeleteDefaultSecDesc(pSecDesc);
  383. }
  384. ASSERT(!*pbSecDescModified || IsValidSecurityDescriptor(*ppSecDesc));
  385. if (0 != err)
  386. {
  387. CString strCaption;
  388. CString strMsg;
  389. try
  390. {
  391. strCaption.LoadString(IDS_MSGTITLE);
  392. strMsg.LoadString(IDS_NOACLEDITOR);
  393. MessageBox(hwndParent, strMsg, strCaption, MB_OK | MB_ICONSTOP);
  394. } // try
  395. catch (CException * pe)
  396. {
  397. pe->Delete();
  398. };
  399. }
  400. return err;
  401. } //*** EditShareAcl()
  402. BOOL BLocalAccountsInSD(PSECURITY_DESCRIPTOR pSD, LPCTSTR pszClusterNameNode)
  403. {
  404. /*++
  405. Routine Description:
  406. Determines if any ACEs for local accounts are in DACL stored in
  407. Security Descriptor (pSD) after the ACL editor has been called
  408. Added this function in order to prevent users from selecting local accounts in
  409. permissions dialog.
  410. Rod Sharper 04/29/97
  411. Arguments:
  412. pSD - Security Descriptor to be checked.
  413. Return Value:
  414. TRUE if at least one ACE was removed from the DACL, False otherwise.
  415. --*/
  416. PACL paclDACL = NULL;
  417. BOOL bHasDACL = FALSE;
  418. BOOL bDaclDefaulted = FALSE;
  419. BOOL bLocalAccountInACL = FALSE;
  420. BOOL bRtn = FALSE;
  421. ACL_SIZE_INFORMATION asiAclSize;
  422. DWORD dwBufLength;
  423. DWORD dwACL_Index = 0L;
  424. ACCESS_ALLOWED_ACE * paaAllowedAce;
  425. TCHAR szUserName[128];
  426. TCHAR szDomainName[128];
  427. DWORD cbUser = 128;
  428. DWORD cbDomain = 128;
  429. SID_NAME_USE SidType;
  430. PUCHAR pnSubAuthorityCount;
  431. PULONG pnSubAuthority0;
  432. PULONG pnSubAuthority1;
  433. bRtn = IsValidSecurityDescriptor(pSD);
  434. ASSERT(bRtn);
  435. if( !bRtn )
  436. return FALSE;
  437. bRtn = GetSecurityDescriptorDacl(
  438. pSD,
  439. (LPBOOL)&bHasDACL,
  440. (PACL *)&paclDACL,
  441. (LPBOOL)&bDaclDefaulted);
  442. ASSERT(bRtn);
  443. if( !bRtn )
  444. return FALSE;
  445. if (NULL == paclDACL)
  446. return FALSE;
  447. bRtn = IsValidAcl(paclDACL);
  448. ASSERT(bRtn);
  449. if( !bRtn )
  450. return FALSE;
  451. dwBufLength = sizeof(asiAclSize);
  452. bRtn = GetAclInformation(
  453. paclDACL,
  454. (LPVOID)&asiAclSize,
  455. (DWORD)dwBufLength,
  456. (ACL_INFORMATION_CLASS)AclSizeInformation);
  457. ASSERT(bRtn);
  458. if( !bRtn )
  459. return FALSE;
  460. // Search the ACL for local account ACEs
  461. //
  462. PSID pSID;
  463. while( dwACL_Index < asiAclSize.AceCount )
  464. {
  465. if (!GetAce(paclDACL, dwACL_Index, (LPVOID *)&paaAllowedAce))
  466. {
  467. ASSERT(FALSE);
  468. return FALSE;
  469. }
  470. if((((PACE_HEADER)paaAllowedAce)->AceType) == ACCESS_ALLOWED_ACE_TYPE)
  471. {
  472. //
  473. //Get SID from ACE
  474. //
  475. pSID=(PSID)&((PACCESS_ALLOWED_ACE)paaAllowedAce)->SidStart;
  476. cbUser = 128;
  477. cbDomain = 128;
  478. if (LookupAccountSid(NULL,
  479. pSID,
  480. szUserName,
  481. &cbUser,
  482. szDomainName,
  483. &cbDomain,
  484. &SidType))
  485. {
  486. if (lstrcmpi(szDomainName, _T("BUILTIN")) == 0)
  487. {
  488. pnSubAuthorityCount = GetSidSubAuthorityCount( pSID );
  489. if ( (pnSubAuthorityCount != NULL) && (*pnSubAuthorityCount == 2) )
  490. {
  491. // Check to see if this is the local Administrators group.
  492. pnSubAuthority0 = GetSidSubAuthority( pSID, 0 );
  493. pnSubAuthority1 = GetSidSubAuthority( pSID, 1 );
  494. if ( (pnSubAuthority0 == NULL)
  495. || (pnSubAuthority1 == NULL)
  496. || ( (*pnSubAuthority0 != SECURITY_BUILTIN_DOMAIN_RID)
  497. && (*pnSubAuthority1 != SECURITY_BUILTIN_DOMAIN_RID))
  498. || ( (*pnSubAuthority0 != DOMAIN_ALIAS_RID_ADMINS)
  499. && (*pnSubAuthority1 != DOMAIN_ALIAS_RID_ADMINS)))
  500. {
  501. bLocalAccountInACL = TRUE;
  502. break;
  503. } // if: not the local Administrators group
  504. } // if: exactly 2 sub-authorities
  505. else
  506. {
  507. bLocalAccountInACL = TRUE;
  508. break;
  509. } // else: unexpected # of sub-authorities
  510. } // if: built-in user or group
  511. else if ( (lstrcmpi(szDomainName, pszClusterNameNode) == 0)
  512. && (SidType != SidTypeDomain) )
  513. {
  514. // The domain name is the name of the node on which the
  515. // cluster name resource is online, so this is a local
  516. // user or group.
  517. bLocalAccountInACL = TRUE;
  518. break;
  519. } // else if: domain is cluster name resource node and not a Domain SID
  520. } // if: LookupAccountSid succeeded
  521. else
  522. {
  523. // If LookupAccountSid failed, assume that the SID is for
  524. // a user or group that is local to a machine to which we
  525. // don't have access.
  526. bLocalAccountInACL = TRUE;
  527. break;
  528. } // else: LookupAccountSid failed
  529. }
  530. dwACL_Index++;
  531. }
  532. return bLocalAccountInACL;
  533. } //*** BLocalAccountsInSD()
  534. //+-------------------------------------------------------------------------
  535. //
  536. // Function: SedCallback
  537. //
  538. // Synopsis: Security Editor callback for the SHARE ACL Editor
  539. //
  540. // Arguments: See sedapi.h
  541. //
  542. // History:
  543. // ChuckC 10-Aug-1992 Created
  544. // BruceFo 4-Apr-95 Stole and used in ntshrui.dll
  545. // DavidP 10-Oct-1996 Modified for use with CLUADMIN
  546. //
  547. //--------------------------------------------------------------------------
  548. DWORD
  549. SedCallback(
  550. HWND hwndParent,
  551. HANDLE hInstance,
  552. ULONG ulCallbackContext,
  553. PSECURITY_DESCRIPTOR pSecDesc,
  554. PSECURITY_DESCRIPTOR pSecDescNewObjects,
  555. BOOLEAN fApplyToSubContainers,
  556. BOOLEAN fApplyToSubObjects,
  557. LPDWORD StatusReturn
  558. )
  559. {
  560. SHARE_CALLBACK_INFO * pCallbackInfo = (SHARE_CALLBACK_INFO *)ulCallbackContext;
  561. TRACE(_T("SedCallback, got pSecDesc = 0x%08lx\n"), pSecDesc);
  562. ASSERT(pCallbackInfo != NULL);
  563. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  564. if ( BLocalAccountsInSD(pSecDesc, pCallbackInfo->pszClusterNameNode) )
  565. {
  566. CString strMsg;
  567. strMsg.LoadString(IDS_LOCAL_ACCOUNTS_SPECIFIED);
  568. AfxMessageBox(strMsg, MB_OK | MB_ICONSTOP);
  569. return LOCAL_ACCOUNTS_FILTERED;
  570. } // if: local users or groups were specified
  571. ASSERT(pCallbackInfo != NULL);
  572. delete[] (BYTE*)pCallbackInfo->pSecDesc;
  573. pCallbackInfo->pSecDesc = CopySecurityDescriptor(pSecDesc);
  574. pCallbackInfo->bSecDescModified = TRUE;
  575. ASSERT(IsValidSecurityDescriptor(pCallbackInfo->pSecDesc));
  576. TRACE(_T("SedCallback, return pSecDesc = 0x%08lx\n"), pCallbackInfo->pSecDesc);
  577. return NOERROR;
  578. } //*** SedCallback()
  579. //+-------------------------------------------------------------------------
  580. //
  581. // Function: InitializeShareGenericMapping
  582. //
  583. // Synopsis: Initializes the passed generic mapping structure for shares.
  584. //
  585. // Arguments: [pSHAREGenericMapping] - Pointer to GENERIC_MAPPING to be init.
  586. //
  587. // History:
  588. // ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code.
  589. // BruceFo 4-Apr-95 Stole and used in ntshrui.dll
  590. // DavidP 10-Oct-1996 Modified for use with CLUADMIN
  591. //
  592. //--------------------------------------------------------------------------
  593. VOID
  594. InitializeShareGenericMapping(
  595. IN OUT PGENERIC_MAPPING pSHAREGenericMapping
  596. )
  597. {
  598. TRACE(_T("InitializeShareGenericMapping\n"));
  599. pSHAREGenericMapping->GenericRead = GENERIC_READ;
  600. pSHAREGenericMapping->GenericWrite = GENERIC_WRITE;
  601. pSHAREGenericMapping->GenericExecute = GENERIC_EXECUTE;
  602. pSHAREGenericMapping->GenericAll = GENERIC_ALL;
  603. } //*** InitializeShareGenericMapping()
  604. //+-------------------------------------------------------------------------
  605. //
  606. // Function: CreateDefaultSecDesc
  607. //
  608. // Synopsis: Create a default ACL for either a new share or for
  609. // a share that doesn't exist.
  610. //
  611. // Arguments: [ppSecDesc] - *ppSecDesc points to a "world all" access
  612. // security descriptor on exit. Caller is responsible for
  613. // freeing it.
  614. //
  615. // Returns: NERR_Success if OK, api error otherwise.
  616. //
  617. // History:
  618. // ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code.
  619. // BruceFo 4-Apr-95 Stole and used in ntshrui.dll
  620. // DavidP 10-Oct-1996 Modified for use with CLUADMIN
  621. //
  622. //--------------------------------------------------------------------------
  623. LONG
  624. CreateDefaultSecDesc(
  625. OUT PSECURITY_DESCRIPTOR* ppSecDesc
  626. )
  627. {
  628. TRACE(_T("CreateDefaultSecDesc\n"));
  629. ASSERT(ppSecDesc != NULL) ;
  630. ASSERT(*ppSecDesc == NULL) ;
  631. LONG err = NERR_Success;
  632. PSECURITY_DESCRIPTOR pSecDesc = NULL;
  633. PACL pAcl = NULL;
  634. DWORD cbAcl;
  635. PSID pSid = NULL;
  636. *ppSecDesc = NULL;
  637. do // error breakout
  638. {
  639. // First, create a world SID. Next, create an access allowed
  640. // ACE with "Generic All" access with the world SID. Put the ACE in
  641. // the ACL and the ACL in the security descriptor.
  642. SID_IDENTIFIER_AUTHORITY IDAuthorityWorld = SECURITY_WORLD_SID_AUTHORITY;
  643. if (!AllocateAndInitializeSid(
  644. &IDAuthorityWorld,
  645. 1,
  646. SECURITY_WORLD_RID,
  647. 0, 0, 0, 0, 0, 0, 0,
  648. &pSid))
  649. {
  650. err = GetLastError();
  651. TRACE(_T("AllocateAndInitializeSid failed, 0x%08lx\n"), err);
  652. break;
  653. }
  654. ASSERT(IsValidSid(pSid));
  655. cbAcl = sizeof(ACL)
  656. + (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))
  657. + GetLengthSid(pSid)
  658. ;
  659. try
  660. {
  661. pAcl = (PACL) new BYTE[cbAcl];
  662. } // try
  663. catch (CMemoryException * pme)
  664. {
  665. err = ERROR_OUTOFMEMORY;
  666. TRACE(_T("new ACL failed\n"));
  667. pme->Delete();
  668. break;
  669. } // catch: CMemoryException
  670. if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION2))
  671. {
  672. err = GetLastError();
  673. TRACE(_T("InitializeAcl failed, 0x%08lx\n"), err);
  674. break;
  675. }
  676. if (!AddAccessAllowedAce(
  677. pAcl,
  678. ACL_REVISION2,
  679. FILE_PERM_ALL,
  680. pSid))
  681. {
  682. err = GetLastError();
  683. TRACE(_T("AddAccessAllowedAce failed, 0x%08lx\n"), err);
  684. break;
  685. }
  686. ASSERT(IsValidAcl(pAcl));
  687. try
  688. {
  689. pSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[SECURITY_DESCRIPTOR_MIN_LENGTH];
  690. } // try
  691. catch (CMemoryException * pme)
  692. {
  693. err = ERROR_OUTOFMEMORY;
  694. TRACE(_T("new SECURITY_DESCRIPTOR failed\n"));
  695. pme->Delete();
  696. break;
  697. } // catch: CMemoryException
  698. if (!InitializeSecurityDescriptor(
  699. pSecDesc,
  700. SECURITY_DESCRIPTOR_REVISION1))
  701. {
  702. err = GetLastError();
  703. TRACE(_T("InitializeSecurityDescriptor failed, 0x%08lx\n"), err);
  704. break;
  705. }
  706. if (!SetSecurityDescriptorDacl(
  707. pSecDesc,
  708. TRUE,
  709. pAcl,
  710. FALSE))
  711. {
  712. err = GetLastError();
  713. TRACE(_T("SetSecurityDescriptorDacl failed, 0x%08lx\n"), err);
  714. break;
  715. }
  716. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  717. // Make the security descriptor self-relative
  718. DWORD dwLen = GetSecurityDescriptorLength(pSecDesc);
  719. TRACE(_T("SECURITY_DESCRIPTOR length = %d\n"), dwLen);
  720. PSECURITY_DESCRIPTOR pSelfSecDesc = NULL;
  721. try
  722. {
  723. pSelfSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[dwLen];
  724. } // try
  725. catch (CMemoryException * pme)
  726. {
  727. err = ERROR_OUTOFMEMORY;
  728. TRACE(_T("new SECURITY_DESCRIPTOR (2) failed\n"));
  729. pme->Delete();
  730. break;
  731. } // catch: CMemoryException
  732. DWORD cbSelfSecDesc = dwLen;
  733. if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc))
  734. {
  735. err = GetLastError();
  736. TRACE(_T("MakeSelfRelativeSD failed, 0x%08lx\n"), err);
  737. break;
  738. }
  739. ASSERT(IsValidSecurityDescriptor(pSelfSecDesc));
  740. //
  741. // all done: set the security descriptor
  742. //
  743. *ppSecDesc = pSelfSecDesc;
  744. } while (FALSE) ;
  745. if (NULL != pSid)
  746. {
  747. FreeSid(pSid);
  748. }
  749. delete[] (BYTE*)pAcl;
  750. delete[] (BYTE*)pSecDesc;
  751. ASSERT(IsValidSecurityDescriptor(*ppSecDesc));
  752. return err;
  753. } //*** CreateDefaultSecDesc()
  754. //+-------------------------------------------------------------------------
  755. //
  756. // Function: DeleteDefaultSecDesc
  757. //
  758. // Synopsis: Delete a security descriptor that was created by
  759. // CreateDefaultSecDesc
  760. //
  761. // Arguments: [pSecDesc] - security descriptor to delete
  762. //
  763. // Returns: nothing
  764. //
  765. // History:
  766. // BruceFo 4-Apr-95 Created
  767. // DavidP 10-Oct-1996 Modified for use with CLUADMIN
  768. //
  769. //--------------------------------------------------------------------------
  770. VOID
  771. DeleteDefaultSecDesc(
  772. IN PSECURITY_DESCRIPTOR pSecDesc
  773. )
  774. {
  775. TRACE(_T("DeleteDefaultSecDesc\n"));
  776. delete[] (BYTE*)pSecDesc;
  777. } //*** DeleteDefaultSecDesc()
  778. //+-------------------------------------------------------------------------
  779. //
  780. // Member: CopySecurityDescriptor, public
  781. //
  782. // Synopsis: Copy an NT security descriptor. The security descriptor must
  783. // be in self-relative (not absolute) form. Delete the result
  784. // using "delete[] (BYTE*)pSecDesc".
  785. //
  786. // History: 19-Apr-95 BruceFo Created
  787. // 10-Oct-1996 DavidP Modified for use with CLUADMIN
  788. //
  789. //--------------------------------------------------------------------------
  790. PSECURITY_DESCRIPTOR
  791. CopySecurityDescriptor(
  792. IN PSECURITY_DESCRIPTOR pSecDesc
  793. )
  794. {
  795. TRACE(_T("CopySecurityDescriptor, pSecDesc = 0x%08lx\n"), pSecDesc);
  796. if (NULL == pSecDesc)
  797. {
  798. return NULL;
  799. }
  800. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  801. DWORD dwLen = GetSecurityDescriptorLength(pSecDesc);
  802. PSECURITY_DESCRIPTOR pSelfSecDesc = NULL;
  803. try
  804. {
  805. pSelfSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[dwLen];
  806. }
  807. catch (CMemoryException * pme)
  808. {
  809. TRACE(_T("new SECURITY_DESCRIPTOR (2) failed\n"));
  810. pme->Delete();
  811. return NULL; // actually, should probably return an error
  812. } // catch: CMemoryException
  813. DWORD cbSelfSecDesc = dwLen;
  814. if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc))
  815. {
  816. TRACE(_T("MakeSelfRelativeSD failed, 0x%08lx\n"), GetLastError());
  817. // assume it failed because it was already self-relative
  818. CopyMemory(pSelfSecDesc, pSecDesc, dwLen);
  819. }
  820. ASSERT(IsValidSecurityDescriptor(pSelfSecDesc));
  821. return pSelfSecDesc;
  822. } //*** CopySecurityDescriptor()
  823. //+---------------------------------------------------------------------------
  824. //
  825. // Function: GetResourceString
  826. //
  827. // Synopsis: Load a resource string, are return a "new"ed copy
  828. //
  829. // Arguments: [dwId] -- a resource string ID
  830. //
  831. // Returns: new memory copy of a string
  832. //
  833. // History: 5-Apr-95 BruceFo Created
  834. // 10-Oct-1996 DavidP Modified for CLUADMIN
  835. //
  836. //----------------------------------------------------------------------------
  837. PWSTR
  838. GetResourceString(
  839. IN DWORD dwId
  840. )
  841. {
  842. CString str;
  843. if (str.LoadString(dwId))
  844. return NewDup(str);
  845. else
  846. return NULL;
  847. } //*** GetResourceString()
  848. //+---------------------------------------------------------------------------
  849. //
  850. // Function: NewDup
  851. //
  852. // Synopsis: Duplicate a string using '::new'
  853. //
  854. // History: 28-Dec-94 BruceFo Created
  855. // 10-Oct-1996 DavidP Modified for CLUADMIN
  856. //
  857. //----------------------------------------------------------------------------
  858. PWSTR
  859. NewDup(
  860. IN const WCHAR* psz
  861. )
  862. {
  863. PWSTR pszRet = NULL;
  864. if (NULL == psz)
  865. {
  866. TRACE(_T("Illegal string to duplicate: NULL\n"));
  867. return NULL;
  868. }
  869. try
  870. {
  871. pszRet = new WCHAR[wcslen(psz) + 1];
  872. }
  873. catch (CMemoryException * pme)
  874. {
  875. TRACE(_T("OUT OF MEMORY\n"));
  876. pme->Delete();
  877. return NULL;
  878. } // catch: CMemoryException
  879. wcscpy(pszRet, psz);
  880. return pszRet;
  881. } //*** NewDup()
  882. //+-------------------------------------------------------------------------
  883. //
  884. // Function: MapBitsInSD
  885. //
  886. // Synopsis: Maps Specific bits to Generic bit when MAP_DIRECTION is SPECIFIC_TO_GENERIC
  887. // Maps Generic bits to Specific bit when MAP_DIRECTION is GENERIC_TO_SPECIFIC
  888. //
  889. // Arguments: [pSecDesc] - SECURITY_DESCIRPTOR to be modified
  890. // [direction] - indicates whether bits are mapped from specific to generic
  891. // or generic to specific.
  892. // Author:
  893. // Roderick Sharper (rodsh) April 12, 1997
  894. //
  895. // History:
  896. //
  897. //--------------------------------------------------------------------------
  898. BOOL MapBitsInSD(PSECURITY_DESCRIPTOR pSecDesc, MAP_DIRECTION direction)
  899. {
  900. PACL paclDACL = NULL;
  901. BOOL bHasDACL = FALSE;
  902. BOOL bDaclDefaulted = FALSE;
  903. BOOL bRtn = FALSE;
  904. if (!IsValidSecurityDescriptor(pSecDesc))
  905. return FALSE;
  906. if (!GetSecurityDescriptorDacl(pSecDesc,
  907. (LPBOOL)&bHasDACL,
  908. (PACL *)&paclDACL,
  909. (LPBOOL)&bDaclDefaulted))
  910. return FALSE;
  911. if (paclDACL)
  912. bRtn = MapBitsInACL(paclDACL, direction);
  913. return bRtn;
  914. }
  915. //+-------------------------------------------------------------------------
  916. //
  917. // Function: MapBitsInACL
  918. //
  919. // Synopsis: Maps Specific bits to Generic bit when MAP_DIRECTION is SPECIFIC_TO_GENERIC
  920. // Maps Generic bits to Specific bit when MAP_DIRECTION is GENERIC_TO_SPECIFIC
  921. //
  922. //
  923. // Arguments: [paclACL] - ACL (Access Control List) to be modified
  924. // [direction] - indicates whether bits are mapped from specific to generic
  925. // or generic to specific.
  926. // Author:
  927. // Roderick Sharper (rodsh) May 02, 1997
  928. //
  929. // History:
  930. //
  931. //--------------------------------------------------------------------------
  932. BOOL MapBitsInACL(PACL paclACL, MAP_DIRECTION direction)
  933. {
  934. ACL_SIZE_INFORMATION asiAclSize;
  935. BOOL bRtn = FALSE;
  936. DWORD dwBufLength;
  937. DWORD dwACL_Index;
  938. ACCESS_ALLOWED_ACE *paaAllowedAce;
  939. if (!IsValidAcl(paclACL))
  940. return FALSE;
  941. dwBufLength = sizeof(asiAclSize);
  942. if (!GetAclInformation(paclACL,
  943. (LPVOID)&asiAclSize,
  944. (DWORD)dwBufLength,
  945. (ACL_INFORMATION_CLASS)AclSizeInformation))
  946. return FALSE;
  947. for (dwACL_Index = 0; dwACL_Index < asiAclSize.AceCount; dwACL_Index++)
  948. {
  949. if (!GetAce(paclACL,
  950. dwACL_Index,
  951. (LPVOID *)&paaAllowedAce))
  952. return FALSE;
  953. if( direction == SPECIFIC_TO_GENERIC )
  954. bRtn = MapSpecificBitsInAce( paaAllowedAce );
  955. else if( direction == GENERIC_TO_SPECIFIC )
  956. bRtn = MapGenericBitsInAce( paaAllowedAce );
  957. else
  958. bRtn = FALSE;
  959. }
  960. return bRtn;
  961. }
  962. //+-------------------------------------------------------------------------
  963. //
  964. // Function: MapSpecificBitsInAce
  965. //
  966. // Synopsis: Maps specific bits in ACE to generic bits
  967. //
  968. // Arguments: [paaAllowedAce] - ACE (Access Control Entry) to be modified
  969. // [direction] - indicates whether bits are mapped from specific to generic
  970. // or generic to specific.
  971. // Author:
  972. // Roderick Sharper (rodsh) May 02, 1997
  973. //
  974. // History:
  975. //
  976. //--------------------------------------------------------------------------
  977. BOOL MapSpecificBitsInAce(PACCESS_ALLOWED_ACE paaAllowedAce)
  978. {
  979. ACCESS_MASK amMask = paaAllowedAce->Mask;
  980. BOOL bRtn = FALSE;
  981. DWORD dwGenericBits;
  982. DWORD dwSpecificBits;
  983. dwSpecificBits = (amMask & SPECIFIC_RIGHTS_ALL);
  984. dwGenericBits = 0;
  985. switch( dwSpecificBits )
  986. {
  987. case CLUSAPI_READ_ACCESS: dwGenericBits = GENERIC_READ; // GENERIC_READ == 0x80000000L
  988. bRtn = TRUE;
  989. break;
  990. case CLUSAPI_CHANGE_ACCESS: dwGenericBits = GENERIC_WRITE; // GENERIC_WRITE == 0x40000000L
  991. bRtn = TRUE;
  992. break;
  993. case CLUSAPI_NO_ACCESS: dwGenericBits = GENERIC_EXECUTE;// GENERIC_EXECUTE == 0x20000000L
  994. bRtn = TRUE;
  995. break;
  996. case CLUSAPI_ALL_ACCESS: dwGenericBits = GENERIC_ALL; // GENERIC_ALL == 0x10000000L
  997. bRtn = TRUE;
  998. break;
  999. default: dwGenericBits = 0x00000000L; // Invalid,assign no rights.
  1000. bRtn = FALSE;
  1001. break;
  1002. }
  1003. amMask = dwGenericBits;
  1004. paaAllowedAce->Mask = amMask;
  1005. return bRtn;
  1006. }
  1007. //+-------------------------------------------------------------------------
  1008. //
  1009. // Function: MapGenericBitsInAce
  1010. //
  1011. // Synopsis: Maps generic bits in ACE to specific bits
  1012. //
  1013. // Arguments: [paaAllowedAce] - ACE (Access Control Entry) to be modified
  1014. // [direction] - indicates whether bits are mapped from specific to generic
  1015. // or generic to specific.
  1016. // Author:
  1017. // Roderick Sharper (rodsh) May 02, 1997
  1018. //
  1019. // History:
  1020. //
  1021. //--------------------------------------------------------------------------
  1022. BOOL MapGenericBitsInAce (PACCESS_ALLOWED_ACE paaAllowedAce)
  1023. {
  1024. #define GENERIC_RIGHTS_ALL_THE_BITS 0xF0000000L
  1025. ACCESS_MASK amMask = paaAllowedAce->Mask;
  1026. BOOL bRtn = FALSE;
  1027. DWORD dwGenericBits;
  1028. DWORD dwSpecificBits;
  1029. dwSpecificBits = 0;
  1030. dwGenericBits = (amMask & GENERIC_RIGHTS_ALL_THE_BITS);
  1031. switch( dwGenericBits )
  1032. {
  1033. case GENERIC_ALL: dwSpecificBits = CLUSAPI_ALL_ACCESS; // CLUSAPI_ALL_ACCESS == 3
  1034. bRtn = TRUE;
  1035. break;
  1036. case GENERIC_EXECUTE: dwSpecificBits = CLUSAPI_NO_ACCESS; // CLUSAPI_NO_ACCESS == 4
  1037. bRtn = TRUE;
  1038. break;
  1039. case GENERIC_WRITE: dwSpecificBits = CLUSAPI_CHANGE_ACCESS; // CLUSAPI_CHANGE_ACCESS == 2
  1040. bRtn = TRUE;
  1041. break;
  1042. case GENERIC_READ: dwSpecificBits = CLUSAPI_READ_ACCESS; // CLUSAPI_READ_ACCESS == 1
  1043. bRtn = TRUE;
  1044. break;
  1045. default: dwSpecificBits = 0x00000000L; // Invalid, assign no rights.
  1046. bRtn = FALSE;
  1047. break;
  1048. }
  1049. amMask = dwSpecificBits;
  1050. paaAllowedAce->Mask = amMask;
  1051. return bRtn;
  1052. }