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.

1339 lines
40 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2002 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. UINT idx;
  196. do // error breakout
  197. {
  198. /*
  199. * if pSecDesc is NULL, this is new file share or a file share with no
  200. * security descriptor.
  201. * we go and create a new (default) security descriptor.
  202. */
  203. if ( pSecDesc == NULL )
  204. {
  205. TRACE(_T("Security Descriptor is NULL. Grant everyone Full Control\n") );
  206. LONG err = CreateDefaultSecDesc( &pSecDesc );
  207. if (err != NERR_Success)
  208. {
  209. err = GetLastError();
  210. TRACE(_T("CreateDefaultSecDesc failed, 0x%08lx\n"), err);
  211. break;
  212. }
  213. TRACE(_T("CreateDefaultSecDesc descriptor = 0x%08lx\n"), pSecDesc);
  214. bCreatedDefaultSecDesc = TRUE;
  215. }
  216. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  217. /* Retrieve the resource strings appropriate for the type of object we
  218. * are looking at
  219. */
  220. CString strTypeName;
  221. CString strDefaultPermName;
  222. try
  223. {
  224. strTypeName.LoadString(IDS_ACLEDIT_TITLE);
  225. strDefaultPermName.LoadString(IDS_ACLEDIT_PERM_GEN_ALL);
  226. } // try
  227. catch (CMemoryException * pme)
  228. {
  229. pme->Delete();
  230. }
  231. /*
  232. * other misc stuff we need pass to security editor
  233. */
  234. SED_OBJECT_TYPE_DESCRIPTOR sedObjDesc ;
  235. SED_HELP_INFO sedHelpInfo ;
  236. GENERIC_MAPPING SHAREGenericMapping ;
  237. // setup mappings
  238. InitializeShareGenericMapping( &SHAREGenericMapping ) ;
  239. WCHAR szHelpFile[50] = ACLEDIT_HELPFILENAME;
  240. sedHelpInfo.pszHelpFileName = szHelpFile;
  241. sedHelpInfo.aulHelpContext[HC_MAIN_DLG] = HC_UI_SHELL_BASE + HC_NTSHAREPERMS ;
  242. sedHelpInfo.aulHelpContext[HC_ADD_USER_DLG] = HC_UI_SHELL_BASE + HC_SHAREADDUSER ;
  243. sedHelpInfo.aulHelpContext[HC_ADD_USER_MEMBERS_GG_DLG] = HC_UI_SHELL_BASE + HC_SHAREADDUSER_GLOBALGROUP ;
  244. sedHelpInfo.aulHelpContext[HC_ADD_USER_SEARCH_DLG] = HC_UI_SHELL_BASE + HC_SHAREADDUSER_FINDUSER ;
  245. // These are not used, set to zero
  246. sedHelpInfo.aulHelpContext[HC_SPECIAL_ACCESS_DLG] = 0 ;
  247. sedHelpInfo.aulHelpContext[HC_NEW_ITEM_SPECIAL_ACCESS_DLG] = 0 ;
  248. // setup the object description
  249. sedObjDesc.Revision = SED_REVISION1 ;
  250. sedObjDesc.IsContainer = FALSE ;
  251. sedObjDesc.AllowNewObjectPerms = FALSE ;
  252. sedObjDesc.MapSpecificPermsToGeneric = TRUE ;
  253. sedObjDesc.GenericMapping = &SHAREGenericMapping ;
  254. sedObjDesc.GenericMappingNewObjects = &SHAREGenericMapping ;
  255. sedObjDesc.ObjectTypeName = (LPWSTR) (LPCWSTR) strTypeName ;
  256. sedObjDesc.HelpInfo = &sedHelpInfo ;
  257. sedObjDesc.SpecialObjectAccessTitle = NULL ;
  258. /* Now we need to load the global arrays with the permission names
  259. * from the resource file.
  260. */
  261. UINT cArrayItems = ARRAYLEN(g_SedAppAccessSharePerms);
  262. PSED_APPLICATION_ACCESS aSedAppAccess = g_SedAppAccessSharePerms ;
  263. /* Loop through each permission title retrieving the text from the
  264. * resource file and setting the pointer in the array.
  265. */
  266. for ( idx = 0 ; idx < cArrayItems ; idx++ )
  267. {
  268. pszPermName = GetResourceString(g_dwSharePermNames[ idx ]) ;
  269. if ( pszPermName == NULL )
  270. {
  271. TRACE(_T("GetResourceString failed\n"));
  272. break ;
  273. }
  274. aSedAppAccess[ idx ].PermissionTitle = pszPermName;
  275. }
  276. if ( idx < cArrayItems )
  277. {
  278. TRACE(_T("failed to get all share permission names\n"));
  279. break ;
  280. }
  281. SED_APPLICATION_ACCESSES sedAppAccesses ;
  282. sedAppAccesses.Count = cArrayItems ;
  283. sedAppAccesses.AccessGroup = aSedAppAccess ;
  284. sedAppAccesses.DefaultPermName = (LPWSTR) (LPCWSTR) strDefaultPermName;
  285. /*
  286. * pass this along so when the call back function is called,
  287. * we can set it.
  288. */
  289. SHARE_CALLBACK_INFO callbackinfo ;
  290. callbackinfo.pSecDesc = NULL;
  291. callbackinfo.bSecDescModified = FALSE;
  292. callbackinfo.pszClusterNameNode = pszClusterNameNode;
  293. //
  294. // Now, load up the ACL editor and invoke it. We don't keep it around
  295. // because our DLL is loaded whenever the system is, so we don't want
  296. // the netui*.dll's hanging around as well...
  297. //
  298. HINSTANCE hInstanceAclEditor = NULL;
  299. SedDiscretionaryAclEditorType pAclEditor = NULL;
  300. hInstanceAclEditor = LoadLibrary(ACLEDIT_DLL_STRING);
  301. if ( hInstanceAclEditor == NULL )
  302. {
  303. err = GetLastError();
  304. TRACE(_T("LoadLibrary of acledit.dll failed, 0x%08lx\n"), err);
  305. break;
  306. }
  307. pAclEditor = (SedDiscretionaryAclEditorType) GetProcAddress(
  308. hInstanceAclEditor,
  309. SEDDISCRETIONARYACLEDITOR_STRING
  310. );
  311. if ( pAclEditor == NULL )
  312. {
  313. err = GetLastError();
  314. TRACE(_T("GetProcAddress of SedDiscretionaryAclEditorType failed, 0x%08lx\n"), err);
  315. break;
  316. }
  317. #ifdef MAPBITS
  318. MapBitsInSD( pSecDesc, SPECIFIC_TO_GENERIC );
  319. #endif
  320. DWORD dwSedReturnStatus ;
  321. ASSERT(pAclEditor != NULL);
  322. err = (*pAclEditor)(
  323. hwndParent,
  324. AfxGetInstanceHandle(),
  325. (LPTSTR) pszServerName,
  326. &sedObjDesc,
  327. &sedAppAccesses,
  328. (LPTSTR) pszShareName,
  329. SedCallback,
  330. (ULONG) &callbackinfo,
  331. pSecDesc,
  332. FALSE, // always can read
  333. FALSE, // if we can read, we can write
  334. (LPDWORD) &dwSedReturnStatus,
  335. 0
  336. );
  337. if (pSecDesc != NULL)
  338. {
  339. #ifdef MAPBITS
  340. MapBitsInSD( pSecDesc, GENERIC_TO_SPECIFIC );
  341. #endif
  342. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  343. } // if: no security descriptor returned
  344. if (!FreeLibrary(hInstanceAclEditor))
  345. {
  346. LONG err2 = GetLastError();
  347. TRACE(_T("FreeLibrary of acledit.dll failed, 0x%08lx\n"), err2);
  348. // not fatal: continue...
  349. }
  350. if (0 != err)
  351. {
  352. TRACE(_T("SedDiscretionaryAclEditor failed, 0x%08lx\n"), err);
  353. break ;
  354. }
  355. *pbSecDescModified = callbackinfo.bSecDescModified ;
  356. if (*pbSecDescModified)
  357. {
  358. *ppSecDesc = callbackinfo.pSecDesc;
  359. #ifdef MAPBITS
  360. MapBitsInSD( *ppSecDesc, GENERIC_TO_SPECIFIC );
  361. #endif
  362. TRACE(_T("After calling acl editor, *ppSecDesc = 0x%08lx\n"), *ppSecDesc);
  363. ASSERT(IsValidSecurityDescriptor(*ppSecDesc));
  364. }
  365. } while (FALSE) ;
  366. //
  367. // Free memory...
  368. //
  369. UINT cArrayItems = ARRAYLEN(g_SedAppAccessSharePerms);
  370. PSED_APPLICATION_ACCESS aSedAppAccess = g_SedAppAccessSharePerms ;
  371. for ( UINT i = 0 ; i < cArrayItems ; i++ )
  372. {
  373. pszPermName = aSedAppAccess[i].PermissionTitle;
  374. if ( pszPermName == NULL )
  375. {
  376. // if we hit a NULL, that's it!
  377. break ;
  378. }
  379. delete[] pszPermName;
  380. }
  381. if (bCreatedDefaultSecDesc)
  382. {
  383. DeleteDefaultSecDesc(pSecDesc);
  384. }
  385. ASSERT(!*pbSecDescModified || IsValidSecurityDescriptor(*ppSecDesc));
  386. if (0 != err)
  387. {
  388. CString strCaption;
  389. CString strMsg;
  390. try
  391. {
  392. strCaption.LoadString(IDS_MSGTITLE);
  393. strMsg.LoadString(IDS_NOACLEDITOR);
  394. MessageBox(hwndParent, strMsg, strCaption, MB_OK | MB_ICONSTOP);
  395. } // try
  396. catch (CException * pe)
  397. {
  398. pe->Delete();
  399. };
  400. }
  401. return err;
  402. } //*** EditShareAcl
  403. //////////////////////////////////////////////////////////////////////////////
  404. //++
  405. //
  406. // BLocalAccountInSD
  407. //
  408. // Description:
  409. // Determines if any ACEs for local accounts are in DACL stored in
  410. // Security Descriptor (pSD) after the ACL editor has been called
  411. //
  412. // Added this function in order to prevent users from selecting local
  413. // accounts in permissions dialog.
  414. // Rod Sharper 04/29/97
  415. //
  416. // Arguments:
  417. // pSD - Security Descriptor to be checked.
  418. // pszClusterNameNode -
  419. //
  420. // Return Values:
  421. // TRUE if at least one ACE was removed from the DACL, False otherwise.
  422. //
  423. //--
  424. //////////////////////////////////////////////////////////////////////////////
  425. BOOL BLocalAccountsInSD(PSECURITY_DESCRIPTOR pSD, LPCTSTR pszClusterNameNode)
  426. {
  427. PACL paclDACL = NULL;
  428. BOOL bHasDACL = FALSE;
  429. BOOL bDaclDefaulted = FALSE;
  430. BOOL bLocalAccountInACL = FALSE;
  431. BOOL bRtn = FALSE;
  432. ACL_SIZE_INFORMATION asiAclSize;
  433. DWORD dwBufLength;
  434. DWORD dwACL_Index = 0L;
  435. ACCESS_ALLOWED_ACE * paaAllowedAce;
  436. TCHAR szUserName[128];
  437. TCHAR szDomainName[128];
  438. DWORD cbUser = 128;
  439. DWORD cbDomain = 128;
  440. SID_NAME_USE SidType;
  441. PUCHAR pnSubAuthorityCount;
  442. PULONG pnSubAuthority0;
  443. PULONG pnSubAuthority1;
  444. bRtn = IsValidSecurityDescriptor(pSD);
  445. ASSERT(bRtn);
  446. if ( bRtn == FALSE )
  447. {
  448. goto Cleanup;
  449. }
  450. bRtn = GetSecurityDescriptorDacl(
  451. pSD,
  452. (LPBOOL)&bHasDACL,
  453. (PACL *)&paclDACL,
  454. (LPBOOL)&bDaclDefaulted);
  455. ASSERT(bRtn);
  456. if ( bRtn == FALSE )
  457. {
  458. goto Cleanup;
  459. }
  460. if ( paclDACL == NULL )
  461. {
  462. goto Cleanup;
  463. }
  464. bRtn = IsValidAcl(paclDACL);
  465. ASSERT(bRtn);
  466. if ( bRtn == FALSE )
  467. {
  468. goto Cleanup;
  469. }
  470. dwBufLength = sizeof(asiAclSize);
  471. bRtn = GetAclInformation(
  472. paclDACL,
  473. (LPVOID)&asiAclSize,
  474. (DWORD)dwBufLength,
  475. (ACL_INFORMATION_CLASS) AclSizeInformation
  476. );
  477. ASSERT(bRtn);
  478. if ( bRtn == FALSE )
  479. {
  480. goto Cleanup;
  481. }
  482. // Search the ACL for local account ACEs
  483. //
  484. PSID pSID;
  485. while ( dwACL_Index < asiAclSize.AceCount )
  486. {
  487. if (!GetAce(paclDACL, dwACL_Index, (LPVOID *)&paaAllowedAce))
  488. {
  489. ASSERT(FALSE);
  490. goto Cleanup;
  491. }
  492. if((((PACE_HEADER)paaAllowedAce)->AceType) == ACCESS_ALLOWED_ACE_TYPE)
  493. {
  494. //
  495. //Get SID from ACE
  496. //
  497. pSID=(PSID)&((PACCESS_ALLOWED_ACE)paaAllowedAce)->SidStart;
  498. cbUser = 128;
  499. cbDomain = 128;
  500. if (LookupAccountSid(NULL,
  501. pSID,
  502. szUserName,
  503. &cbUser,
  504. szDomainName,
  505. &cbDomain,
  506. &SidType
  507. ))
  508. {
  509. if ( ClRtlStrNICmp( szDomainName, _T("BUILTIN"), RTL_NUMBER_OF( szDomainName ) ) == 0 )
  510. {
  511. pnSubAuthorityCount = GetSidSubAuthorityCount( pSID );
  512. if ( (pnSubAuthorityCount != NULL) && (*pnSubAuthorityCount == 2) )
  513. {
  514. // Check to see if this is the local Administrators group.
  515. pnSubAuthority0 = GetSidSubAuthority( pSID, 0 );
  516. pnSubAuthority1 = GetSidSubAuthority( pSID, 1 );
  517. if ( (pnSubAuthority0 == NULL)
  518. || (pnSubAuthority1 == NULL)
  519. || ( (*pnSubAuthority0 != SECURITY_BUILTIN_DOMAIN_RID)
  520. && (*pnSubAuthority1 != SECURITY_BUILTIN_DOMAIN_RID))
  521. || ( (*pnSubAuthority0 != DOMAIN_ALIAS_RID_ADMINS)
  522. && (*pnSubAuthority1 != DOMAIN_ALIAS_RID_ADMINS)))
  523. {
  524. bLocalAccountInACL = TRUE;
  525. break;
  526. } // if: not the local Administrators group
  527. } // if: exactly 2 sub-authorities
  528. else
  529. {
  530. bLocalAccountInACL = TRUE;
  531. break;
  532. } // else: unexpected # of sub-authorities
  533. } // if: built-in user or group
  534. else if ( ( ClRtlStrNICmp(szDomainName, pszClusterNameNode, RTL_NUMBER_OF( szDomainName ) ) == 0 )
  535. && ( SidType != SidTypeDomain ) )
  536. {
  537. // The domain name is the name of the node on which the
  538. // cluster name resource is online, so this is a local
  539. // user or group.
  540. bLocalAccountInACL = TRUE;
  541. break;
  542. } // else if: domain is cluster name resource node and not a Domain SID
  543. } // if: LookupAccountSid succeeded
  544. else
  545. {
  546. // If LookupAccountSid failed, assume that the SID is for
  547. // a user or group that is local to a machine to which we
  548. // don't have access.
  549. bLocalAccountInACL = TRUE;
  550. break;
  551. } // else: LookupAccountSid failed
  552. }
  553. dwACL_Index++;
  554. }
  555. Cleanup:
  556. return bLocalAccountInACL;
  557. } //*** BLocalAccountsInSD
  558. //+-------------------------------------------------------------------------
  559. //
  560. // Function: SedCallback
  561. //
  562. // Synopsis: Security Editor callback for the SHARE ACL Editor
  563. //
  564. // Arguments: See sedapi.h
  565. //
  566. // History:
  567. // ChuckC 10-Aug-1992 Created
  568. // BruceFo 4-Apr-95 Stole and used in ntshrui.dll
  569. // DavidP 10-Oct-1996 Modified for use with CLUADMIN
  570. //
  571. //--------------------------------------------------------------------------
  572. DWORD
  573. SedCallback(
  574. HWND hwndParent,
  575. HANDLE hInstance,
  576. ULONG ulCallbackContext,
  577. PSECURITY_DESCRIPTOR pSecDesc,
  578. PSECURITY_DESCRIPTOR pSecDescNewObjects,
  579. BOOLEAN fApplyToSubContainers,
  580. BOOLEAN fApplyToSubObjects,
  581. LPDWORD StatusReturn
  582. )
  583. {
  584. DWORD nStatus = NOERROR;
  585. SHARE_CALLBACK_INFO * pCallbackInfo = (SHARE_CALLBACK_INFO *)ulCallbackContext;
  586. TRACE(_T("SedCallback, got pSecDesc = 0x%08lx\n"), pSecDesc);
  587. ASSERT(pCallbackInfo != NULL);
  588. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  589. if ( BLocalAccountsInSD(pSecDesc, pCallbackInfo->pszClusterNameNode) )
  590. {
  591. CString strMsg;
  592. strMsg.LoadString(IDS_LOCAL_ACCOUNTS_SPECIFIED);
  593. AfxMessageBox(strMsg, MB_OK | MB_ICONSTOP);
  594. nStatus = LOCAL_ACCOUNTS_FILTERED;
  595. goto Cleanup
  596. } // if: local users or groups were specified
  597. ASSERT(pCallbackInfo != NULL);
  598. delete[] (BYTE*)pCallbackInfo->pSecDesc;
  599. pCallbackInfo->pSecDesc = CopySecurityDescriptor(pSecDesc);
  600. pCallbackInfo->bSecDescModified = TRUE;
  601. ASSERT(IsValidSecurityDescriptor(pCallbackInfo->pSecDesc));
  602. TRACE(_T("SedCallback, return pSecDesc = 0x%08lx\n"), pCallbackInfo->pSecDesc);
  603. Cleanup:
  604. return nStatus;
  605. } //*** SedCallback
  606. //+-------------------------------------------------------------------------
  607. //
  608. // Function: InitializeShareGenericMapping
  609. //
  610. // Synopsis: Initializes the passed generic mapping structure for shares.
  611. //
  612. // Arguments: [pSHAREGenericMapping] - Pointer to GENERIC_MAPPING to be init.
  613. //
  614. // History:
  615. // ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code.
  616. // BruceFo 4-Apr-95 Stole and used in ntshrui.dll
  617. // DavidP 10-Oct-1996 Modified for use with CLUADMIN
  618. //
  619. //--------------------------------------------------------------------------
  620. VOID
  621. InitializeShareGenericMapping(
  622. IN OUT PGENERIC_MAPPING pSHAREGenericMapping
  623. )
  624. {
  625. TRACE(_T("InitializeShareGenericMapping\n"));
  626. pSHAREGenericMapping->GenericRead = GENERIC_READ;
  627. pSHAREGenericMapping->GenericWrite = GENERIC_WRITE;
  628. pSHAREGenericMapping->GenericExecute = GENERIC_EXECUTE;
  629. pSHAREGenericMapping->GenericAll = GENERIC_ALL;
  630. } //*** InitializeShareGenericMapping
  631. //+-------------------------------------------------------------------------
  632. //
  633. // Function: CreateDefaultSecDesc
  634. //
  635. // Synopsis: Create a default ACL for either a new share or for
  636. // a share that doesn't exist.
  637. //
  638. // Arguments: [ppSecDesc] - *ppSecDesc points to a "world all" access
  639. // security descriptor on exit. Caller is responsible for
  640. // freeing it.
  641. //
  642. // Returns: NERR_Success if OK, api error otherwise.
  643. //
  644. // History:
  645. // ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code.
  646. // BruceFo 4-Apr-95 Stole and used in ntshrui.dll
  647. // DavidP 10-Oct-1996 Modified for use with CLUADMIN
  648. //
  649. //--------------------------------------------------------------------------
  650. LONG
  651. CreateDefaultSecDesc(
  652. OUT PSECURITY_DESCRIPTOR* ppSecDesc
  653. )
  654. {
  655. TRACE(_T("CreateDefaultSecDesc\n"));
  656. ASSERT(ppSecDesc != NULL) ;
  657. ASSERT(*ppSecDesc == NULL) ;
  658. LONG err = NERR_Success;
  659. PSECURITY_DESCRIPTOR pSecDesc = NULL;
  660. PACL pAcl = NULL;
  661. DWORD cbAcl;
  662. PSID pSid = NULL;
  663. *ppSecDesc = NULL;
  664. // First, create a world SID. Next, create an access allowed
  665. // ACE with "Generic All" access with the world SID. Put the ACE in
  666. // the ACL and the ACL in the security descriptor.
  667. SID_IDENTIFIER_AUTHORITY IDAuthorityWorld = SECURITY_WORLD_SID_AUTHORITY;
  668. if (!AllocateAndInitializeSid(
  669. &IDAuthorityWorld,
  670. 1,
  671. SECURITY_WORLD_RID,
  672. 0, 0, 0, 0, 0, 0, 0,
  673. &pSid))
  674. {
  675. err = GetLastError();
  676. TRACE(_T("AllocateAndInitializeSid failed, 0x%08lx\n"), err);
  677. goto Cleanup;
  678. }
  679. ASSERT(IsValidSid(pSid));
  680. cbAcl = sizeof(ACL)
  681. + (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))
  682. + GetLengthSid(pSid)
  683. ;
  684. try
  685. {
  686. pAcl = (PACL) new BYTE[cbAcl];
  687. } // try
  688. catch (CMemoryException * pme)
  689. {
  690. err = ERROR_OUTOFMEMORY;
  691. TRACE(_T("new ACL failed\n"));
  692. pme->Delete();
  693. goto Cleanup;
  694. } // catch: CMemoryException
  695. if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION2))
  696. {
  697. err = GetLastError();
  698. TRACE(_T("InitializeAcl failed, 0x%08lx\n"), err);
  699. goto Cleanup;
  700. }
  701. if (!AddAccessAllowedAce(
  702. pAcl,
  703. ACL_REVISION2,
  704. FILE_PERM_ALL,
  705. pSid))
  706. {
  707. err = GetLastError();
  708. TRACE(_T("AddAccessAllowedAce failed, 0x%08lx\n"), err);
  709. goto Cleanup;
  710. }
  711. ASSERT(IsValidAcl(pAcl));
  712. try
  713. {
  714. pSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[SECURITY_DESCRIPTOR_MIN_LENGTH];
  715. } // try
  716. catch (CMemoryException * pme)
  717. {
  718. err = ERROR_OUTOFMEMORY;
  719. TRACE(_T("new SECURITY_DESCRIPTOR failed\n"));
  720. pme->Delete();
  721. goto Cleanup;
  722. } // catch: CMemoryException
  723. if (!InitializeSecurityDescriptor(
  724. pSecDesc,
  725. SECURITY_DESCRIPTOR_REVISION1))
  726. {
  727. err = GetLastError();
  728. TRACE(_T("InitializeSecurityDescriptor failed, 0x%08lx\n"), err);
  729. goto Cleanup;
  730. }
  731. if (!SetSecurityDescriptorDacl(
  732. pSecDesc,
  733. TRUE,
  734. pAcl,
  735. FALSE))
  736. {
  737. err = GetLastError();
  738. TRACE(_T("SetSecurityDescriptorDacl failed, 0x%08lx\n"), err);
  739. goto Cleanup;
  740. }
  741. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  742. // Make the security descriptor self-relative
  743. DWORD dwLen = GetSecurityDescriptorLength(pSecDesc);
  744. TRACE(_T("SECURITY_DESCRIPTOR length = %d\n"), dwLen);
  745. PSECURITY_DESCRIPTOR pSelfSecDesc = NULL;
  746. try
  747. {
  748. pSelfSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[dwLen];
  749. } // try
  750. catch (CMemoryException * pme)
  751. {
  752. err = ERROR_OUTOFMEMORY;
  753. TRACE(_T("new SECURITY_DESCRIPTOR (2) failed\n"));
  754. pme->Delete();
  755. goto Cleanup;
  756. } // catch: CMemoryException
  757. DWORD cbSelfSecDesc = dwLen;
  758. if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc))
  759. {
  760. err = GetLastError();
  761. TRACE(_T("MakeSelfRelativeSD failed, 0x%08lx\n"), err);
  762. goto Cleanup;
  763. }
  764. ASSERT(IsValidSecurityDescriptor(pSelfSecDesc));
  765. //
  766. // all done: set the security descriptor
  767. //
  768. *ppSecDesc = pSelfSecDesc;
  769. Cleanup:
  770. if (NULL != pSid)
  771. {
  772. FreeSid(pSid);
  773. }
  774. delete[] (BYTE*)pAcl;
  775. delete[] (BYTE*)pSecDesc;
  776. ASSERT(IsValidSecurityDescriptor(*ppSecDesc));
  777. return err;
  778. } //*** CreateDefaultSecDesc
  779. //+-------------------------------------------------------------------------
  780. //
  781. // Function: DeleteDefaultSecDesc
  782. //
  783. // Synopsis: Delete a security descriptor that was created by
  784. // CreateDefaultSecDesc
  785. //
  786. // Arguments: [pSecDesc] - security descriptor to delete
  787. //
  788. // Returns: nothing
  789. //
  790. // History:
  791. // BruceFo 4-Apr-95 Created
  792. // DavidP 10-Oct-1996 Modified for use with CLUADMIN
  793. //
  794. //--------------------------------------------------------------------------
  795. VOID
  796. DeleteDefaultSecDesc(
  797. IN PSECURITY_DESCRIPTOR pSecDesc
  798. )
  799. {
  800. TRACE(_T("DeleteDefaultSecDesc\n"));
  801. delete[] (BYTE*)pSecDesc;
  802. } //*** DeleteDefaultSecDesc
  803. //+-------------------------------------------------------------------------
  804. //
  805. // Member: CopySecurityDescriptor, public
  806. //
  807. // Synopsis: Copy an NT security descriptor. The security descriptor must
  808. // be in self-relative (not absolute) form. Delete the result
  809. // using "delete[] (BYTE*)pSecDesc".
  810. //
  811. // History: 19-Apr-95 BruceFo Created
  812. // 10-Oct-1996 DavidP Modified for use with CLUADMIN
  813. //
  814. //--------------------------------------------------------------------------
  815. PSECURITY_DESCRIPTOR
  816. CopySecurityDescriptor(
  817. IN PSECURITY_DESCRIPTOR pSecDesc
  818. )
  819. {
  820. TRACE(_T("CopySecurityDescriptor, pSecDesc = 0x%08lx\n"), pSecDesc);
  821. ASSERT(IsValidSecurityDescriptor(pSecDesc));
  822. size_t cbLen = GetSecurityDescriptorLength(pSecDesc);
  823. size_t cbSelfSecDesc = cbLen;
  824. PSECURITY_DESCRIPTOR pSelfSecDesc = NULL;
  825. if ( pSecDesc == NULL )
  826. {
  827. goto Cleanup;
  828. }
  829. try
  830. {
  831. pSelfSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[ cbLen ];
  832. }
  833. catch (CMemoryException * pme)
  834. {
  835. TRACE(_T("new SECURITY_DESCRIPTOR (2) failed\n"));
  836. pme->Delete();
  837. return NULL; // actually, should probably return an error
  838. } // catch: CMemoryException
  839. if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc))
  840. {
  841. TRACE(_T("MakeSelfRelativeSD failed, 0x%08lx\n"), GetLastError());
  842. // assume it failed because it was already self-relative
  843. CopyMemory( pSelfSecDesc, pSecDesc, cbLen );
  844. }
  845. ASSERT(IsValidSecurityDescriptor(pSelfSecDesc));
  846. Cleanup:
  847. return pSelfSecDesc;
  848. } //*** CopySecurityDescriptor
  849. //+---------------------------------------------------------------------------
  850. //
  851. // Function: GetResourceString
  852. //
  853. // Synopsis: Load a resource string, are return a "new"ed copy
  854. //
  855. // Arguments: [dwId] -- a resource string ID
  856. //
  857. // Returns: new memory copy of a string
  858. //
  859. // History: 5-Apr-95 BruceFo Created
  860. // 10-Oct-1996 DavidP Modified for CLUADMIN
  861. //
  862. //----------------------------------------------------------------------------
  863. PWSTR
  864. GetResourceString(
  865. IN DWORD dwId
  866. )
  867. {
  868. CString str;
  869. PWSTR pwsz = NULL;
  870. if (str.LoadString(dwId))
  871. {
  872. pwsz = NewDup(str);
  873. }
  874. return pwsz;
  875. } //*** GetResourceString
  876. //+---------------------------------------------------------------------------
  877. //
  878. // Function: NewDup
  879. //
  880. // Synopsis: Duplicate a string using '::new'
  881. //
  882. // History: 28-Dec-94 BruceFo Created
  883. // 10-Oct-1996 DavidP Modified for CLUADMIN
  884. //
  885. //----------------------------------------------------------------------------
  886. PWSTR
  887. NewDup(
  888. IN const WCHAR* psz
  889. )
  890. {
  891. PWSTR pszRet = NULL;
  892. size_t cch;
  893. HRESULT hr;
  894. if ( psz == NULL )
  895. {
  896. TRACE(_T("Illegal string to duplicate: NULL\n"));
  897. goto Cleanup;
  898. }
  899. cch = wcslen( psz ) + 1;
  900. try
  901. {
  902. pszRet = new WCHAR[ cch ];
  903. if ( pszRet == NULL )
  904. {
  905. TRACE( _T("OUT OF MEMORY\n") );
  906. goto Cleanup;
  907. }
  908. }
  909. catch (CMemoryException * pme)
  910. {
  911. TRACE(_T("OUT OF MEMORY\n"));
  912. pme->Delete();
  913. pszRet = NULL;
  914. goto Cleanup;
  915. } // catch: CMemoryException
  916. hr = StringCchCopyW( pszRet, cch, psz );
  917. ASSERT( SUCCEEDED( hr ) );
  918. Cleanup:
  919. return pszRet;
  920. } //*** NewDup
  921. //+-------------------------------------------------------------------------
  922. //
  923. // Function: MapBitsInSD
  924. //
  925. // Synopsis: Maps Specific bits to Generic bit when MAP_DIRECTION is SPECIFIC_TO_GENERIC
  926. // Maps Generic bits to Specific bit when MAP_DIRECTION is GENERIC_TO_SPECIFIC
  927. //
  928. // Arguments: [pSecDesc] - SECURITY_DESCIRPTOR to be modified
  929. // [direction] - indicates whether bits are mapped from specific to generic
  930. // or generic to specific.
  931. // Author:
  932. // Roderick Sharper (rodsh) April 12, 1997
  933. //
  934. // History:
  935. //
  936. //--------------------------------------------------------------------------
  937. BOOL MapBitsInSD(PSECURITY_DESCRIPTOR pSecDesc, MAP_DIRECTION direction)
  938. {
  939. PACL paclDACL = NULL;
  940. BOOL bHasDACL = FALSE;
  941. BOOL bDaclDefaulted = FALSE;
  942. BOOL bRtn = FALSE;
  943. if (!IsValidSecurityDescriptor(pSecDesc))
  944. {
  945. goto Cleanup;
  946. }
  947. if (!GetSecurityDescriptorDacl(pSecDesc,
  948. (LPBOOL)&bHasDACL,
  949. (PACL *)&paclDACL,
  950. (LPBOOL)&bDaclDefaulted
  951. ))
  952. {
  953. goto Cleanup;
  954. }
  955. if (paclDACL)
  956. {
  957. bRtn = MapBitsInACL(paclDACL, direction);
  958. }
  959. Cleanup:
  960. return bRtn;
  961. } //*** MapBitsInSD
  962. //+-------------------------------------------------------------------------
  963. //
  964. // Function: MapBitsInACL
  965. //
  966. // Synopsis: Maps Specific bits to Generic bit when MAP_DIRECTION is SPECIFIC_TO_GENERIC
  967. // Maps Generic bits to Specific bit when MAP_DIRECTION is GENERIC_TO_SPECIFIC
  968. //
  969. //
  970. // Arguments: [paclACL] - ACL (Access Control List) to be modified
  971. // [direction] - indicates whether bits are mapped from specific to generic
  972. // or generic to specific.
  973. // Author:
  974. // Roderick Sharper (rodsh) May 02, 1997
  975. //
  976. // History:
  977. //
  978. //--------------------------------------------------------------------------
  979. BOOL MapBitsInACL(PACL paclACL, MAP_DIRECTION direction)
  980. {
  981. ACL_SIZE_INFORMATION asiAclSize;
  982. BOOL bRtn = FALSE;
  983. DWORD dwBufLength;
  984. DWORD dwACL_Index;
  985. ACCESS_ALLOWED_ACE * paaAllowedAce;
  986. if (!IsValidAcl(paclACL))
  987. {
  988. goto Cleanup;
  989. }
  990. dwBufLength = sizeof(asiAclSize);
  991. if (!GetAclInformation(paclACL,
  992. (LPVOID)&asiAclSize,
  993. (DWORD)dwBufLength,
  994. (ACL_INFORMATION_CLASS)AclSizeInformation))
  995. {
  996. goto Cleanup;
  997. }
  998. for (dwACL_Index = 0; dwACL_Index < asiAclSize.AceCount; dwACL_Index++)
  999. {
  1000. if (!GetAce(paclACL, dwACL_Index, (LPVOID *) &paaAllowedAce))
  1001. {
  1002. goto Cleanup;
  1003. }
  1004. if ( direction == SPECIFIC_TO_GENERIC )
  1005. {
  1006. bRtn = MapSpecificBitsInAce( paaAllowedAce );
  1007. }
  1008. else if ( direction == GENERIC_TO_SPECIFIC )
  1009. {
  1010. bRtn = MapGenericBitsInAce( paaAllowedAce );
  1011. }
  1012. else
  1013. {
  1014. bRtn = FALSE;
  1015. }
  1016. } // for: each ACE
  1017. Cleanup:
  1018. return bRtn;
  1019. } //*** MapBitsInACL
  1020. //+-------------------------------------------------------------------------
  1021. //
  1022. // Function: MapSpecificBitsInAce
  1023. //
  1024. // Synopsis: Maps specific bits in ACE to generic bits
  1025. //
  1026. // Arguments: [paaAllowedAce] - ACE (Access Control Entry) to be modified
  1027. // [direction] - indicates whether bits are mapped from specific to generic
  1028. // or generic to specific.
  1029. // Author:
  1030. // Roderick Sharper (rodsh) May 02, 1997
  1031. //
  1032. // History:
  1033. //
  1034. //--------------------------------------------------------------------------
  1035. BOOL MapSpecificBitsInAce(PACCESS_ALLOWED_ACE paaAllowedAce)
  1036. {
  1037. ACCESS_MASK amMask = paaAllowedAce->Mask;
  1038. BOOL bRtn = FALSE;
  1039. DWORD dwGenericBits;
  1040. DWORD dwSpecificBits;
  1041. dwSpecificBits = (amMask & SPECIFIC_RIGHTS_ALL);
  1042. dwGenericBits = 0;
  1043. switch( dwSpecificBits )
  1044. {
  1045. case CLUSAPI_READ_ACCESS:
  1046. dwGenericBits = GENERIC_READ; // GENERIC_READ == 0x80000000L
  1047. bRtn = TRUE;
  1048. break;
  1049. case CLUSAPI_CHANGE_ACCESS:
  1050. dwGenericBits = GENERIC_WRITE; // GENERIC_WRITE == 0x40000000L
  1051. bRtn = TRUE;
  1052. break;
  1053. case CLUSAPI_NO_ACCESS:
  1054. dwGenericBits = GENERIC_EXECUTE;// GENERIC_EXECUTE == 0x20000000L
  1055. bRtn = TRUE;
  1056. break;
  1057. case CLUSAPI_ALL_ACCESS:
  1058. dwGenericBits = GENERIC_ALL; // GENERIC_ALL == 0x10000000L
  1059. bRtn = TRUE;
  1060. break;
  1061. default:
  1062. dwGenericBits = 0x00000000L; // Invalid,assign no rights.
  1063. bRtn = FALSE;
  1064. break;
  1065. } // switch: on specific bits
  1066. amMask = dwGenericBits;
  1067. paaAllowedAce->Mask = amMask;
  1068. return bRtn;
  1069. } //*** MapSpecificBitsInAce
  1070. //+-------------------------------------------------------------------------
  1071. //
  1072. // Function: MapGenericBitsInAce
  1073. //
  1074. // Synopsis: Maps generic bits in ACE to specific bits
  1075. //
  1076. // Arguments: [paaAllowedAce] - ACE (Access Control Entry) to be modified
  1077. // [direction] - indicates whether bits are mapped from specific to generic
  1078. // or generic to specific.
  1079. // Author:
  1080. // Roderick Sharper (rodsh) May 02, 1997
  1081. //
  1082. // History:
  1083. //
  1084. //--------------------------------------------------------------------------
  1085. BOOL MapGenericBitsInAce (PACCESS_ALLOWED_ACE paaAllowedAce)
  1086. {
  1087. #define GENERIC_RIGHTS_ALL_THE_BITS 0xF0000000L
  1088. ACCESS_MASK amMask = paaAllowedAce->Mask;
  1089. BOOL bRtn = FALSE;
  1090. DWORD dwGenericBits;
  1091. DWORD dwSpecificBits;
  1092. dwSpecificBits = 0;
  1093. dwGenericBits = (amMask & GENERIC_RIGHTS_ALL_THE_BITS);
  1094. switch( dwGenericBits )
  1095. {
  1096. case GENERIC_ALL:
  1097. dwSpecificBits = CLUSAPI_ALL_ACCESS; // CLUSAPI_ALL_ACCESS == 3
  1098. bRtn = TRUE;
  1099. break;
  1100. case GENERIC_EXECUTE:
  1101. dwSpecificBits = CLUSAPI_NO_ACCESS; // CLUSAPI_NO_ACCESS == 4
  1102. bRtn = TRUE;
  1103. break;
  1104. case GENERIC_WRITE:
  1105. dwSpecificBits = CLUSAPI_CHANGE_ACCESS; // CLUSAPI_CHANGE_ACCESS == 2
  1106. bRtn = TRUE;
  1107. break;
  1108. case GENERIC_READ:
  1109. dwSpecificBits = CLUSAPI_READ_ACCESS; // CLUSAPI_READ_ACCESS == 1
  1110. bRtn = TRUE;
  1111. break;
  1112. default:
  1113. dwSpecificBits = 0x00000000L; // Invalid, assign no rights.
  1114. bRtn = FALSE;
  1115. break;
  1116. } // switch: on generic bits
  1117. amMask = dwSpecificBits;
  1118. paaAllowedAce->Mask = amMask;
  1119. return bRtn;
  1120. } //*** MapGenericBitsInAce