|
|
/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1996-2002 Microsoft Corporation
//
// Module Name:
// EditAcl.cpp
//
// Abstract:
// Implementation of ACL editor methods.
//
// Author:
// David Potter (davidp) October 9, 1996
// From \nt\private\window\shell\lmui\ntshrui\acl.cxx
// by BruceFo
//
// Revision History:
//
// Notes:
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <lmerr.h>
extern "C" { #include <sedapi.h>
}
#include "EditAcl.h"
#include "AclHelp.h"
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
#define ARRAYLEN(a) (sizeof(a) / sizeof((a)[0]))
enum SED_PERM_TYPE{ SED_AUDITS, SED_ACCESSES, SED_OWNER };
enum MAP_DIRECTION { SPECIFIC_TO_GENERIC = 0, GENERIC_TO_SPECIFIC = 1 };
const DWORD LOCAL_ACCOUNTS_FILTERED = 2L; const BOOL bIsFile = 0; //#define MAPBITS
BOOL MapBitsInSD(PSECURITY_DESCRIPTOR pSecDesc, MAP_DIRECTION direction); BOOL MapBitsInACL(PACL paclACL, MAP_DIRECTION direction); BOOL MapSpecificBitsInAce(PACCESS_ALLOWED_ACE pAce); BOOL MapGenericBitsInAce(PACCESS_ALLOWED_ACE pAce);
typedef DWORD (*SedDiscretionaryAclEditorType)( HWND Owner, HANDLE Instance, LPWSTR Server, PSED_OBJECT_TYPE_DESCRIPTOR ObjectType, PSED_APPLICATION_ACCESSES ApplicationAccesses, LPWSTR ObjectName, PSED_FUNC_APPLY_SEC_CALLBACK ApplySecurityCallbackRoutine, ULONG CallbackContext, PSECURITY_DESCRIPTOR SecurityDescriptor, BOOLEAN CouldntReadDacl, BOOLEAN CantWriteDacl, LPDWORD SEDStatusReturn, DWORD Flags );
// NOTE: the SedDiscretionaryAclEditor string is used in GetProcAddress to
// get the correct entrypoint. Since GetProcAddress is not UNICODE, this string
// must be ANSI.
#define ACLEDIT_DLL_STRING TEXT("acledit.dll")
#define ACLEDIT_HELPFILENAME TEXT("ntshrui.hlp")
#define SEDDISCRETIONARYACLEDITOR_STRING ("SedDiscretionaryAclEditor")
//
// Declare the callback routine based on typedef in sedapi.h.
//
DWORD SedCallback( HWND hwndParent, HANDLE hInstance, ULONG ulCallbackContext, PSECURITY_DESCRIPTOR pSecDesc, PSECURITY_DESCRIPTOR pSecDescNewObjects, BOOLEAN fApplyToSubContainers, BOOLEAN fApplyToSubObjects, LPDWORD StatusReturn );
//
// Structure for callback function's usage. A pointer to this is passed as
// ulCallbackContext. The callback functions sets bSecDescModified to TRUE
// and makes a copy of the security descriptor. The caller of EditShareAcl
// is responsible for deleting the memory in pSecDesc if bSecDescModified is
// TRUE. This flag will be FALSE if the user hit CANCEL in the ACL editor.
//
struct SHARE_CALLBACK_INFO { BOOL bSecDescModified; PSECURITY_DESCRIPTOR pSecDesc; LPCTSTR pszClusterNameNode; };
//
// Local function prototypes
//
VOID InitializeShareGenericMapping( IN OUT PGENERIC_MAPPING pSHAREGenericMapping );
PWSTR GetResourceString( IN DWORD dwId );
PWSTR NewDup( IN const WCHAR* psz );
//
// The following two arrays define the permission names for NT Files. Note
// that each index in one array corresponds to the index in the other array.
// The second array will be modifed to contain a string pointer pointing to
// a loaded string corresponding to the IDS_* in the first array.
//
DWORD g_dwSharePermNames[] = { IDS_ACLEDIT_PERM_GEN_NO_ACCESS, IDS_ACLEDIT_PERM_GEN_READ, IDS_ACLEDIT_PERM_GEN_MODIFY, IDS_ACLEDIT_PERM_GEN_ALL };
SED_APPLICATION_ACCESS g_SedAppAccessSharePerms[] = { { SED_DESC_TYPE_RESOURCE, FILE_PERM_NO_ACCESS, 0, NULL }, { SED_DESC_TYPE_RESOURCE, FILE_PERM_READ, 0, NULL }, { SED_DESC_TYPE_RESOURCE, FILE_PERM_MODIFY, 0, NULL }, { SED_DESC_TYPE_RESOURCE, FILE_PERM_ALL, 0, NULL } /*
{ SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_NO_ACCESS, 0, NULL }, { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_READ, 0, NULL }, { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_MODIFY, 0, NULL }, { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_ALL, 0, NULL } */ };
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//+-------------------------------------------------------------------------
//
// Function: EditShareAcl
//
// Synopsis: Invokes the generic ACL editor, specifically for NT shares
//
// Arguments: [hwndParent] - Parent window handle
// [pszServerName] - Name of server on which the object resides.
// [pszShareName] - Fully qualified name of resource we will
// edit, basically a share name.
// [pSecDesc] - The initial security descriptor. If NULL, we will
// create a default that is "World all" access.
// [pbSecDescModified] - Set to TRUE if the security descriptor
// was modified (i.e., the user hit "OK"), or FALSE if not
// (i.e., the user hit "Cancel")
// [ppSecDesc] - *ppSecDesc points to a new security descriptor
// if *pbSecDescModified is TRUE. This memory must be freed
// by the caller.
//
// History:
// ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code.
// Yi-HsinS 09-Oct-1992 Added ulHelpContextBase
// BruceFo 4-Apr-95 Stole and used in ntshrui.dll
// DavidP 10-Oct-1996 Modified for use with CLUADMIN
//
//--------------------------------------------------------------------------
LONG EditShareAcl( IN HWND hwndParent, IN LPCTSTR pszServerName, IN LPCTSTR pszShareName, IN LPCTSTR pszClusterNameNode, IN PSECURITY_DESCRIPTOR pSecDesc, OUT BOOL * pbSecDescModified, OUT PSECURITY_DESCRIPTOR * ppSecDesc ) { ASSERT(pszShareName != NULL); ASSERT(pszClusterNameNode != NULL); TRACE(_T("EditShareAcl, share %ws\n"), pszShareName);
ASSERT((pSecDesc == NULL) || IsValidSecurityDescriptor(pSecDesc)); ASSERT(pbSecDescModified != NULL); ASSERT(ppSecDesc != NULL);
*pbSecDescModified = FALSE;
LONG err = 0 ; PWSTR pszPermName; BOOL bCreatedDefaultSecDesc = FALSE; UINT idx;
do // error breakout
{ /*
* if pSecDesc is NULL, this is new file share or a file share with no * security descriptor. * we go and create a new (default) security descriptor. */ if ( pSecDesc == NULL ) { TRACE(_T("Security Descriptor is NULL. Grant everyone Full Control\n") ); LONG err = CreateDefaultSecDesc( &pSecDesc ); if (err != NERR_Success) { err = GetLastError(); TRACE(_T("CreateDefaultSecDesc failed, 0x%08lx\n"), err); break; } TRACE(_T("CreateDefaultSecDesc descriptor = 0x%08lx\n"), pSecDesc); bCreatedDefaultSecDesc = TRUE; } ASSERT(IsValidSecurityDescriptor(pSecDesc));
/* Retrieve the resource strings appropriate for the type of object we
* are looking at */
CString strTypeName; CString strDefaultPermName;
try { strTypeName.LoadString(IDS_ACLEDIT_TITLE); strDefaultPermName.LoadString(IDS_ACLEDIT_PERM_GEN_ALL); } // try
catch (CMemoryException * pme) { pme->Delete(); }
/*
* other misc stuff we need pass to security editor */ SED_OBJECT_TYPE_DESCRIPTOR sedObjDesc ; SED_HELP_INFO sedHelpInfo ; GENERIC_MAPPING SHAREGenericMapping ;
// setup mappings
InitializeShareGenericMapping( &SHAREGenericMapping ) ;
WCHAR szHelpFile[50] = ACLEDIT_HELPFILENAME; sedHelpInfo.pszHelpFileName = szHelpFile;
sedHelpInfo.aulHelpContext[HC_MAIN_DLG] = HC_UI_SHELL_BASE + HC_NTSHAREPERMS ; sedHelpInfo.aulHelpContext[HC_ADD_USER_DLG] = HC_UI_SHELL_BASE + HC_SHAREADDUSER ; sedHelpInfo.aulHelpContext[HC_ADD_USER_MEMBERS_GG_DLG] = HC_UI_SHELL_BASE + HC_SHAREADDUSER_GLOBALGROUP ; sedHelpInfo.aulHelpContext[HC_ADD_USER_SEARCH_DLG] = HC_UI_SHELL_BASE + HC_SHAREADDUSER_FINDUSER ;
// These are not used, set to zero
sedHelpInfo.aulHelpContext[HC_SPECIAL_ACCESS_DLG] = 0 ; sedHelpInfo.aulHelpContext[HC_NEW_ITEM_SPECIAL_ACCESS_DLG] = 0 ;
// setup the object description
sedObjDesc.Revision = SED_REVISION1 ; sedObjDesc.IsContainer = FALSE ; sedObjDesc.AllowNewObjectPerms = FALSE ; sedObjDesc.MapSpecificPermsToGeneric = TRUE ; sedObjDesc.GenericMapping = &SHAREGenericMapping ; sedObjDesc.GenericMappingNewObjects = &SHAREGenericMapping ; sedObjDesc.ObjectTypeName = (LPWSTR) (LPCWSTR) strTypeName ; sedObjDesc.HelpInfo = &sedHelpInfo ; sedObjDesc.SpecialObjectAccessTitle = NULL ;
/* Now we need to load the global arrays with the permission names
* from the resource file. */ UINT cArrayItems = ARRAYLEN(g_SedAppAccessSharePerms); PSED_APPLICATION_ACCESS aSedAppAccess = g_SedAppAccessSharePerms ;
/* Loop through each permission title retrieving the text from the
* resource file and setting the pointer in the array. */
for ( idx = 0 ; idx < cArrayItems ; idx++ ) { pszPermName = GetResourceString(g_dwSharePermNames[ idx ]) ; if ( pszPermName == NULL ) { TRACE(_T("GetResourceString failed\n")); break ; } aSedAppAccess[ idx ].PermissionTitle = pszPermName; } if ( idx < cArrayItems ) { TRACE(_T("failed to get all share permission names\n")); break ; }
SED_APPLICATION_ACCESSES sedAppAccesses ; sedAppAccesses.Count = cArrayItems ; sedAppAccesses.AccessGroup = aSedAppAccess ; sedAppAccesses.DefaultPermName = (LPWSTR) (LPCWSTR) strDefaultPermName;
/*
* pass this along so when the call back function is called, * we can set it. */ SHARE_CALLBACK_INFO callbackinfo ; callbackinfo.pSecDesc = NULL; callbackinfo.bSecDescModified = FALSE; callbackinfo.pszClusterNameNode = pszClusterNameNode;
//
// Now, load up the ACL editor and invoke it. We don't keep it around
// because our DLL is loaded whenever the system is, so we don't want
// the netui*.dll's hanging around as well...
//
HINSTANCE hInstanceAclEditor = NULL; SedDiscretionaryAclEditorType pAclEditor = NULL;
hInstanceAclEditor = LoadLibrary(ACLEDIT_DLL_STRING);
if ( hInstanceAclEditor == NULL ) { err = GetLastError(); TRACE(_T("LoadLibrary of acledit.dll failed, 0x%08lx\n"), err); break; }
pAclEditor = (SedDiscretionaryAclEditorType) GetProcAddress( hInstanceAclEditor, SEDDISCRETIONARYACLEDITOR_STRING ); if ( pAclEditor == NULL ) { err = GetLastError(); TRACE(_T("GetProcAddress of SedDiscretionaryAclEditorType failed, 0x%08lx\n"), err); break; }
#ifdef MAPBITS
MapBitsInSD( pSecDesc, SPECIFIC_TO_GENERIC ); #endif
DWORD dwSedReturnStatus ;
ASSERT(pAclEditor != NULL); err = (*pAclEditor)( hwndParent, AfxGetInstanceHandle(), (LPTSTR) pszServerName, &sedObjDesc, &sedAppAccesses, (LPTSTR) pszShareName, SedCallback, (ULONG) &callbackinfo, pSecDesc, FALSE, // always can read
FALSE, // if we can read, we can write
(LPDWORD) &dwSedReturnStatus, 0 );
if (pSecDesc != NULL) { #ifdef MAPBITS
MapBitsInSD( pSecDesc, GENERIC_TO_SPECIFIC ); #endif
ASSERT(IsValidSecurityDescriptor(pSecDesc)); } // if: no security descriptor returned
if (!FreeLibrary(hInstanceAclEditor)) { LONG err2 = GetLastError(); TRACE(_T("FreeLibrary of acledit.dll failed, 0x%08lx\n"), err2); // not fatal: continue...
}
if (0 != err) { TRACE(_T("SedDiscretionaryAclEditor failed, 0x%08lx\n"), err); break ; }
*pbSecDescModified = callbackinfo.bSecDescModified ;
if (*pbSecDescModified) { *ppSecDesc = callbackinfo.pSecDesc; #ifdef MAPBITS
MapBitsInSD( *ppSecDesc, GENERIC_TO_SPECIFIC ); #endif
TRACE(_T("After calling acl editor, *ppSecDesc = 0x%08lx\n"), *ppSecDesc); ASSERT(IsValidSecurityDescriptor(*ppSecDesc)); }
} while (FALSE) ;
//
// Free memory...
//
UINT cArrayItems = ARRAYLEN(g_SedAppAccessSharePerms); PSED_APPLICATION_ACCESS aSedAppAccess = g_SedAppAccessSharePerms ; for ( UINT i = 0 ; i < cArrayItems ; i++ ) { pszPermName = aSedAppAccess[i].PermissionTitle; if ( pszPermName == NULL ) { // if we hit a NULL, that's it!
break ; }
delete[] pszPermName; }
if (bCreatedDefaultSecDesc) { DeleteDefaultSecDesc(pSecDesc); }
ASSERT(!*pbSecDescModified || IsValidSecurityDescriptor(*ppSecDesc));
if (0 != err) { CString strCaption; CString strMsg;
try { strCaption.LoadString(IDS_MSGTITLE); strMsg.LoadString(IDS_NOACLEDITOR); MessageBox(hwndParent, strMsg, strCaption, MB_OK | MB_ICONSTOP); } // try
catch (CException * pe) { pe->Delete(); }; }
return err;
} //*** EditShareAcl
//////////////////////////////////////////////////////////////////////////////
//++
//
// BLocalAccountInSD
//
// Description:
// Determines if any ACEs for local accounts are in DACL stored in
// Security Descriptor (pSD) after the ACL editor has been called
//
// Added this function in order to prevent users from selecting local
// accounts in permissions dialog.
// Rod Sharper 04/29/97
//
// Arguments:
// pSD - Security Descriptor to be checked.
// pszClusterNameNode -
//
// Return Values:
// TRUE if at least one ACE was removed from the DACL, False otherwise.
//
//--
//////////////////////////////////////////////////////////////////////////////
BOOL BLocalAccountsInSD(PSECURITY_DESCRIPTOR pSD, LPCTSTR pszClusterNameNode) { PACL paclDACL = NULL; BOOL bHasDACL = FALSE; BOOL bDaclDefaulted = FALSE; BOOL bLocalAccountInACL = FALSE; BOOL bRtn = FALSE;
ACL_SIZE_INFORMATION asiAclSize; DWORD dwBufLength; DWORD dwACL_Index = 0L; ACCESS_ALLOWED_ACE * paaAllowedAce; TCHAR szUserName[128]; TCHAR szDomainName[128]; DWORD cbUser = 128; DWORD cbDomain = 128; SID_NAME_USE SidType; PUCHAR pnSubAuthorityCount; PULONG pnSubAuthority0; PULONG pnSubAuthority1;
bRtn = IsValidSecurityDescriptor(pSD); ASSERT(bRtn); if ( bRtn == FALSE ) { goto Cleanup; }
bRtn = GetSecurityDescriptorDacl( pSD, (LPBOOL)&bHasDACL, (PACL *)&paclDACL, (LPBOOL)&bDaclDefaulted); ASSERT(bRtn); if ( bRtn == FALSE ) { goto Cleanup; } if ( paclDACL == NULL ) { goto Cleanup; }
bRtn = IsValidAcl(paclDACL); ASSERT(bRtn); if ( bRtn == FALSE ) { goto Cleanup; }
dwBufLength = sizeof(asiAclSize);
bRtn = GetAclInformation( paclDACL, (LPVOID)&asiAclSize, (DWORD)dwBufLength, (ACL_INFORMATION_CLASS) AclSizeInformation ); ASSERT(bRtn); if ( bRtn == FALSE ) { goto Cleanup; }
// Search the ACL for local account ACEs
//
PSID pSID; while ( dwACL_Index < asiAclSize.AceCount ) { if (!GetAce(paclDACL, dwACL_Index, (LPVOID *)&paaAllowedAce)) { ASSERT(FALSE); goto Cleanup; } if((((PACE_HEADER)paaAllowedAce)->AceType) == ACCESS_ALLOWED_ACE_TYPE) { //
//Get SID from ACE
//
pSID=(PSID)&((PACCESS_ALLOWED_ACE)paaAllowedAce)->SidStart; cbUser = 128; cbDomain = 128; if (LookupAccountSid(NULL, pSID, szUserName, &cbUser, szDomainName, &cbDomain, &SidType )) { if ( ClRtlStrNICmp( szDomainName, _T("BUILTIN"), RTL_NUMBER_OF( szDomainName ) ) == 0 ) { pnSubAuthorityCount = GetSidSubAuthorityCount( pSID ); if ( (pnSubAuthorityCount != NULL) && (*pnSubAuthorityCount == 2) ) { // Check to see if this is the local Administrators group.
pnSubAuthority0 = GetSidSubAuthority( pSID, 0 ); pnSubAuthority1 = GetSidSubAuthority( pSID, 1 ); if ( (pnSubAuthority0 == NULL) || (pnSubAuthority1 == NULL) || ( (*pnSubAuthority0 != SECURITY_BUILTIN_DOMAIN_RID) && (*pnSubAuthority1 != SECURITY_BUILTIN_DOMAIN_RID)) || ( (*pnSubAuthority0 != DOMAIN_ALIAS_RID_ADMINS) && (*pnSubAuthority1 != DOMAIN_ALIAS_RID_ADMINS))) { bLocalAccountInACL = TRUE; break; } // if: not the local Administrators group
} // if: exactly 2 sub-authorities
else { bLocalAccountInACL = TRUE; break; } // else: unexpected # of sub-authorities
} // if: built-in user or group
else if ( ( ClRtlStrNICmp(szDomainName, pszClusterNameNode, RTL_NUMBER_OF( szDomainName ) ) == 0 ) && ( SidType != SidTypeDomain ) ) { // The domain name is the name of the node on which the
// cluster name resource is online, so this is a local
// user or group.
bLocalAccountInACL = TRUE; break; } // else if: domain is cluster name resource node and not a Domain SID
} // if: LookupAccountSid succeeded
else { // If LookupAccountSid failed, assume that the SID is for
// a user or group that is local to a machine to which we
// don't have access.
bLocalAccountInACL = TRUE; break; } // else: LookupAccountSid failed
} dwACL_Index++; }
Cleanup:
return bLocalAccountInACL;
} //*** BLocalAccountsInSD
//+-------------------------------------------------------------------------
//
// Function: SedCallback
//
// Synopsis: Security Editor callback for the SHARE ACL Editor
//
// Arguments: See sedapi.h
//
// History:
// ChuckC 10-Aug-1992 Created
// BruceFo 4-Apr-95 Stole and used in ntshrui.dll
// DavidP 10-Oct-1996 Modified for use with CLUADMIN
//
//--------------------------------------------------------------------------
DWORD SedCallback( HWND hwndParent, HANDLE hInstance, ULONG ulCallbackContext, PSECURITY_DESCRIPTOR pSecDesc, PSECURITY_DESCRIPTOR pSecDescNewObjects, BOOLEAN fApplyToSubContainers, BOOLEAN fApplyToSubObjects, LPDWORD StatusReturn ) { DWORD nStatus = NOERROR; SHARE_CALLBACK_INFO * pCallbackInfo = (SHARE_CALLBACK_INFO *)ulCallbackContext;
TRACE(_T("SedCallback, got pSecDesc = 0x%08lx\n"), pSecDesc);
ASSERT(pCallbackInfo != NULL); ASSERT(IsValidSecurityDescriptor(pSecDesc));
if ( BLocalAccountsInSD(pSecDesc, pCallbackInfo->pszClusterNameNode) ) { CString strMsg; strMsg.LoadString(IDS_LOCAL_ACCOUNTS_SPECIFIED); AfxMessageBox(strMsg, MB_OK | MB_ICONSTOP); nStatus = LOCAL_ACCOUNTS_FILTERED; goto Cleanup } // if: local users or groups were specified
ASSERT(pCallbackInfo != NULL);
delete[] (BYTE*)pCallbackInfo->pSecDesc; pCallbackInfo->pSecDesc = CopySecurityDescriptor(pSecDesc); pCallbackInfo->bSecDescModified = TRUE;
ASSERT(IsValidSecurityDescriptor(pCallbackInfo->pSecDesc)); TRACE(_T("SedCallback, return pSecDesc = 0x%08lx\n"), pCallbackInfo->pSecDesc);
Cleanup:
return nStatus;
} //*** SedCallback
//+-------------------------------------------------------------------------
//
// Function: InitializeShareGenericMapping
//
// Synopsis: Initializes the passed generic mapping structure for shares.
//
// Arguments: [pSHAREGenericMapping] - Pointer to GENERIC_MAPPING to be init.
//
// History:
// ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code.
// BruceFo 4-Apr-95 Stole and used in ntshrui.dll
// DavidP 10-Oct-1996 Modified for use with CLUADMIN
//
//--------------------------------------------------------------------------
VOID InitializeShareGenericMapping( IN OUT PGENERIC_MAPPING pSHAREGenericMapping ) { TRACE(_T("InitializeShareGenericMapping\n")); pSHAREGenericMapping->GenericRead = GENERIC_READ; pSHAREGenericMapping->GenericWrite = GENERIC_WRITE; pSHAREGenericMapping->GenericExecute = GENERIC_EXECUTE; pSHAREGenericMapping->GenericAll = GENERIC_ALL;
} //*** InitializeShareGenericMapping
//+-------------------------------------------------------------------------
//
// Function: CreateDefaultSecDesc
//
// Synopsis: Create a default ACL for either a new share or for
// a share that doesn't exist.
//
// Arguments: [ppSecDesc] - *ppSecDesc points to a "world all" access
// security descriptor on exit. Caller is responsible for
// freeing it.
//
// Returns: NERR_Success if OK, api error otherwise.
//
// History:
// ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code.
// BruceFo 4-Apr-95 Stole and used in ntshrui.dll
// DavidP 10-Oct-1996 Modified for use with CLUADMIN
//
//--------------------------------------------------------------------------
LONG CreateDefaultSecDesc( OUT PSECURITY_DESCRIPTOR* ppSecDesc ) { TRACE(_T("CreateDefaultSecDesc\n"));
ASSERT(ppSecDesc != NULL) ; ASSERT(*ppSecDesc == NULL) ;
LONG err = NERR_Success; PSECURITY_DESCRIPTOR pSecDesc = NULL; PACL pAcl = NULL; DWORD cbAcl; PSID pSid = NULL;
*ppSecDesc = NULL;
// First, create a world SID. Next, create an access allowed
// ACE with "Generic All" access with the world SID. Put the ACE in
// the ACL and the ACL in the security descriptor.
SID_IDENTIFIER_AUTHORITY IDAuthorityWorld = SECURITY_WORLD_SID_AUTHORITY;
if (!AllocateAndInitializeSid( &IDAuthorityWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSid)) { err = GetLastError(); TRACE(_T("AllocateAndInitializeSid failed, 0x%08lx\n"), err); goto Cleanup; }
ASSERT(IsValidSid(pSid));
cbAcl = sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetLengthSid(pSid) ;
try { pAcl = (PACL) new BYTE[cbAcl]; } // try
catch (CMemoryException * pme) { err = ERROR_OUTOFMEMORY; TRACE(_T("new ACL failed\n")); pme->Delete(); goto Cleanup; } // catch: CMemoryException
if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION2)) { err = GetLastError(); TRACE(_T("InitializeAcl failed, 0x%08lx\n"), err); goto Cleanup; }
if (!AddAccessAllowedAce( pAcl, ACL_REVISION2, FILE_PERM_ALL, pSid)) { err = GetLastError(); TRACE(_T("AddAccessAllowedAce failed, 0x%08lx\n"), err); goto Cleanup; }
ASSERT(IsValidAcl(pAcl));
try { pSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[SECURITY_DESCRIPTOR_MIN_LENGTH]; } // try
catch (CMemoryException * pme) { err = ERROR_OUTOFMEMORY; TRACE(_T("new SECURITY_DESCRIPTOR failed\n")); pme->Delete(); goto Cleanup; } // catch: CMemoryException
if (!InitializeSecurityDescriptor( pSecDesc, SECURITY_DESCRIPTOR_REVISION1)) { err = GetLastError(); TRACE(_T("InitializeSecurityDescriptor failed, 0x%08lx\n"), err); goto Cleanup; }
if (!SetSecurityDescriptorDacl( pSecDesc, TRUE, pAcl, FALSE)) { err = GetLastError(); TRACE(_T("SetSecurityDescriptorDacl failed, 0x%08lx\n"), err); goto Cleanup; }
ASSERT(IsValidSecurityDescriptor(pSecDesc));
// Make the security descriptor self-relative
DWORD dwLen = GetSecurityDescriptorLength(pSecDesc); TRACE(_T("SECURITY_DESCRIPTOR length = %d\n"), dwLen);
PSECURITY_DESCRIPTOR pSelfSecDesc = NULL; try { pSelfSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[dwLen]; } // try
catch (CMemoryException * pme) { err = ERROR_OUTOFMEMORY; TRACE(_T("new SECURITY_DESCRIPTOR (2) failed\n")); pme->Delete(); goto Cleanup; } // catch: CMemoryException
DWORD cbSelfSecDesc = dwLen; if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc)) { err = GetLastError(); TRACE(_T("MakeSelfRelativeSD failed, 0x%08lx\n"), err); goto Cleanup; }
ASSERT(IsValidSecurityDescriptor(pSelfSecDesc));
//
// all done: set the security descriptor
//
*ppSecDesc = pSelfSecDesc;
Cleanup:
if (NULL != pSid) { FreeSid(pSid); } delete[] (BYTE*)pAcl; delete[] (BYTE*)pSecDesc;
ASSERT(IsValidSecurityDescriptor(*ppSecDesc));
return err;
} //*** CreateDefaultSecDesc
//+-------------------------------------------------------------------------
//
// Function: DeleteDefaultSecDesc
//
// Synopsis: Delete a security descriptor that was created by
// CreateDefaultSecDesc
//
// Arguments: [pSecDesc] - security descriptor to delete
//
// Returns: nothing
//
// History:
// BruceFo 4-Apr-95 Created
// DavidP 10-Oct-1996 Modified for use with CLUADMIN
//
//--------------------------------------------------------------------------
VOID DeleteDefaultSecDesc( IN PSECURITY_DESCRIPTOR pSecDesc ) { TRACE(_T("DeleteDefaultSecDesc\n"));
delete[] (BYTE*)pSecDesc;
} //*** DeleteDefaultSecDesc
//+-------------------------------------------------------------------------
//
// Member: CopySecurityDescriptor, public
//
// Synopsis: Copy an NT security descriptor. The security descriptor must
// be in self-relative (not absolute) form. Delete the result
// using "delete[] (BYTE*)pSecDesc".
//
// History: 19-Apr-95 BruceFo Created
// 10-Oct-1996 DavidP Modified for use with CLUADMIN
//
//--------------------------------------------------------------------------
PSECURITY_DESCRIPTOR CopySecurityDescriptor( IN PSECURITY_DESCRIPTOR pSecDesc ) { TRACE(_T("CopySecurityDescriptor, pSecDesc = 0x%08lx\n"), pSecDesc);
ASSERT(IsValidSecurityDescriptor(pSecDesc));
size_t cbLen = GetSecurityDescriptorLength(pSecDesc); size_t cbSelfSecDesc = cbLen; PSECURITY_DESCRIPTOR pSelfSecDesc = NULL;
if ( pSecDesc == NULL ) { goto Cleanup; }
try { pSelfSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[ cbLen ]; } catch (CMemoryException * pme) { TRACE(_T("new SECURITY_DESCRIPTOR (2) failed\n")); pme->Delete(); return NULL; // actually, should probably return an error
} // catch: CMemoryException
if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc)) { TRACE(_T("MakeSelfRelativeSD failed, 0x%08lx\n"), GetLastError());
// assume it failed because it was already self-relative
CopyMemory( pSelfSecDesc, pSecDesc, cbLen ); }
ASSERT(IsValidSecurityDescriptor(pSelfSecDesc));
Cleanup:
return pSelfSecDesc;
} //*** CopySecurityDescriptor
//+---------------------------------------------------------------------------
//
// Function: GetResourceString
//
// Synopsis: Load a resource string, are return a "new"ed copy
//
// Arguments: [dwId] -- a resource string ID
//
// Returns: new memory copy of a string
//
// History: 5-Apr-95 BruceFo Created
// 10-Oct-1996 DavidP Modified for CLUADMIN
//
//----------------------------------------------------------------------------
PWSTR GetResourceString( IN DWORD dwId ) { CString str; PWSTR pwsz = NULL;
if (str.LoadString(dwId)) { pwsz = NewDup(str); }
return pwsz;
} //*** GetResourceString
//+---------------------------------------------------------------------------
//
// Function: NewDup
//
// Synopsis: Duplicate a string using '::new'
//
// History: 28-Dec-94 BruceFo Created
// 10-Oct-1996 DavidP Modified for CLUADMIN
//
//----------------------------------------------------------------------------
PWSTR NewDup( IN const WCHAR* psz ) { PWSTR pszRet = NULL; size_t cch; HRESULT hr;
if ( psz == NULL ) { TRACE(_T("Illegal string to duplicate: NULL\n")); goto Cleanup; }
cch = wcslen( psz ) + 1; try { pszRet = new WCHAR[ cch ]; if ( pszRet == NULL ) { TRACE( _T("OUT OF MEMORY\n") ); goto Cleanup; } } catch (CMemoryException * pme) { TRACE(_T("OUT OF MEMORY\n")); pme->Delete(); pszRet = NULL; goto Cleanup; } // catch: CMemoryException
hr = StringCchCopyW( pszRet, cch, psz ); ASSERT( SUCCEEDED( hr ) );
Cleanup:
return pszRet;
} //*** NewDup
//+-------------------------------------------------------------------------
//
// Function: MapBitsInSD
//
// Synopsis: Maps Specific bits to Generic bit when MAP_DIRECTION is SPECIFIC_TO_GENERIC
// Maps Generic bits to Specific bit when MAP_DIRECTION is GENERIC_TO_SPECIFIC
//
// Arguments: [pSecDesc] - SECURITY_DESCIRPTOR to be modified
// [direction] - indicates whether bits are mapped from specific to generic
// or generic to specific.
// Author:
// Roderick Sharper (rodsh) April 12, 1997
//
// History:
//
//--------------------------------------------------------------------------
BOOL MapBitsInSD(PSECURITY_DESCRIPTOR pSecDesc, MAP_DIRECTION direction) {
PACL paclDACL = NULL; BOOL bHasDACL = FALSE; BOOL bDaclDefaulted = FALSE; BOOL bRtn = FALSE;
if (!IsValidSecurityDescriptor(pSecDesc)) { goto Cleanup; }
if (!GetSecurityDescriptorDacl(pSecDesc, (LPBOOL)&bHasDACL, (PACL *)&paclDACL, (LPBOOL)&bDaclDefaulted )) { goto Cleanup; }
if (paclDACL) { bRtn = MapBitsInACL(paclDACL, direction); }
Cleanup:
return bRtn;
} //*** MapBitsInSD
//+-------------------------------------------------------------------------
//
// Function: MapBitsInACL
//
// Synopsis: Maps Specific bits to Generic bit when MAP_DIRECTION is SPECIFIC_TO_GENERIC
// Maps Generic bits to Specific bit when MAP_DIRECTION is GENERIC_TO_SPECIFIC
//
//
// Arguments: [paclACL] - ACL (Access Control List) to be modified
// [direction] - indicates whether bits are mapped from specific to generic
// or generic to specific.
// Author:
// Roderick Sharper (rodsh) May 02, 1997
//
// History:
//
//--------------------------------------------------------------------------
BOOL MapBitsInACL(PACL paclACL, MAP_DIRECTION direction) { ACL_SIZE_INFORMATION asiAclSize; BOOL bRtn = FALSE; DWORD dwBufLength; DWORD dwACL_Index; ACCESS_ALLOWED_ACE * paaAllowedAce;
if (!IsValidAcl(paclACL)) { goto Cleanup; }
dwBufLength = sizeof(asiAclSize);
if (!GetAclInformation(paclACL, (LPVOID)&asiAclSize, (DWORD)dwBufLength, (ACL_INFORMATION_CLASS)AclSizeInformation)) { goto Cleanup; }
for (dwACL_Index = 0; dwACL_Index < asiAclSize.AceCount; dwACL_Index++) { if (!GetAce(paclACL, dwACL_Index, (LPVOID *) &paaAllowedAce)) { goto Cleanup; }
if ( direction == SPECIFIC_TO_GENERIC ) { bRtn = MapSpecificBitsInAce( paaAllowedAce ); } else if ( direction == GENERIC_TO_SPECIFIC ) { bRtn = MapGenericBitsInAce( paaAllowedAce ); } else { bRtn = FALSE; } } // for: each ACE
Cleanup:
return bRtn;
} //*** MapBitsInACL
//+-------------------------------------------------------------------------
//
// Function: MapSpecificBitsInAce
//
// Synopsis: Maps specific bits in ACE to generic bits
//
// Arguments: [paaAllowedAce] - ACE (Access Control Entry) to be modified
// [direction] - indicates whether bits are mapped from specific to generic
// or generic to specific.
// Author:
// Roderick Sharper (rodsh) May 02, 1997
//
// History:
//
//--------------------------------------------------------------------------
BOOL MapSpecificBitsInAce(PACCESS_ALLOWED_ACE paaAllowedAce) { ACCESS_MASK amMask = paaAllowedAce->Mask; BOOL bRtn = FALSE;
DWORD dwGenericBits; DWORD dwSpecificBits;
dwSpecificBits = (amMask & SPECIFIC_RIGHTS_ALL); dwGenericBits = 0;
switch( dwSpecificBits ) { case CLUSAPI_READ_ACCESS: dwGenericBits = GENERIC_READ; // GENERIC_READ == 0x80000000L
bRtn = TRUE; break;
case CLUSAPI_CHANGE_ACCESS: dwGenericBits = GENERIC_WRITE; // GENERIC_WRITE == 0x40000000L
bRtn = TRUE; break; case CLUSAPI_NO_ACCESS: dwGenericBits = GENERIC_EXECUTE;// GENERIC_EXECUTE == 0x20000000L
bRtn = TRUE; break; case CLUSAPI_ALL_ACCESS: dwGenericBits = GENERIC_ALL; // GENERIC_ALL == 0x10000000L
bRtn = TRUE; break; default: dwGenericBits = 0x00000000L; // Invalid,assign no rights.
bRtn = FALSE; break; } // switch: on specific bits
amMask = dwGenericBits; paaAllowedAce->Mask = amMask;
return bRtn;
} //*** MapSpecificBitsInAce
//+-------------------------------------------------------------------------
//
// Function: MapGenericBitsInAce
//
// Synopsis: Maps generic bits in ACE to specific bits
//
// Arguments: [paaAllowedAce] - ACE (Access Control Entry) to be modified
// [direction] - indicates whether bits are mapped from specific to generic
// or generic to specific.
// Author:
// Roderick Sharper (rodsh) May 02, 1997
//
// History:
//
//--------------------------------------------------------------------------
BOOL MapGenericBitsInAce (PACCESS_ALLOWED_ACE paaAllowedAce) { #define GENERIC_RIGHTS_ALL_THE_BITS 0xF0000000L
ACCESS_MASK amMask = paaAllowedAce->Mask; BOOL bRtn = FALSE;
DWORD dwGenericBits; DWORD dwSpecificBits;
dwSpecificBits = 0; dwGenericBits = (amMask & GENERIC_RIGHTS_ALL_THE_BITS);
switch( dwGenericBits ) { case GENERIC_ALL: dwSpecificBits = CLUSAPI_ALL_ACCESS; // CLUSAPI_ALL_ACCESS == 3
bRtn = TRUE; break; case GENERIC_EXECUTE: dwSpecificBits = CLUSAPI_NO_ACCESS; // CLUSAPI_NO_ACCESS == 4
bRtn = TRUE; break;
case GENERIC_WRITE: dwSpecificBits = CLUSAPI_CHANGE_ACCESS; // CLUSAPI_CHANGE_ACCESS == 2
bRtn = TRUE; break; case GENERIC_READ: dwSpecificBits = CLUSAPI_READ_ACCESS; // CLUSAPI_READ_ACCESS == 1
bRtn = TRUE; break; default: dwSpecificBits = 0x00000000L; // Invalid, assign no rights.
bRtn = FALSE; break; } // switch: on generic bits
amMask = dwSpecificBits; paaAllowedAce->Mask = amMask;
return bRtn;
} //*** MapGenericBitsInAce
|