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.
4506 lines
150 KiB
4506 lines
150 KiB
//+-------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1996.
|
|
//
|
|
// File: acclist.cxx
|
|
//
|
|
// Contents: Class implementation of the CAccessList class
|
|
//
|
|
// Classes: CAccessList
|
|
//
|
|
// History: 28-Jul-96 MacM Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
#include <aclpch.hxx>
|
|
#pragma hdrstop
|
|
|
|
#include <alsup.hxx>
|
|
|
|
#include <seopaque.h>
|
|
#include <sertlp.h>
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAcccessList::CAccessList, public
|
|
//
|
|
// Synopsis: Constructor for the class
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Void
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CAccessList::CAccessList() :
|
|
_AccList(DelAcclistNode),
|
|
_TrusteeList (DelTrusteeNode),
|
|
_pGroup (NULL),
|
|
_pOwner (NULL),
|
|
_fSDValid (FALSE),
|
|
_fFreeSD (FALSE),
|
|
_pSD (NULL),
|
|
_cSDSize (0),
|
|
_fDAclFlags (0),
|
|
_fSAclFlags (0),
|
|
_ObjType (SE_UNKNOWN_OBJECT_TYPE),
|
|
_pLDAP (NULL),
|
|
_pwszDsPathReference (NULL),
|
|
_pwszLookupServer (NULL)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC, "In - out CAccessList::CAccessList\n"));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::~CAccessList, public
|
|
//
|
|
// Synopsis: Destructor for the class
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Void
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CAccessList::~CAccessList()
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC, "In - out CAccessList::~CAccessList\n"));
|
|
|
|
AccFree(_pGroup);
|
|
AccFree(_pOwner);
|
|
|
|
if(_fFreeSD == TRUE)
|
|
{
|
|
AccFree(_pSD);
|
|
}
|
|
|
|
AccFree(_pwszLookupServer);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::AddSD, public
|
|
//
|
|
// Synopsis: Adds a new security descriptor to the list. It converts the
|
|
// acls into an access list
|
|
//
|
|
// Arguments: [IN pSD] -- The information about the security
|
|
// descriptor
|
|
// [IN SeInfo] -- SecurityInfo
|
|
// [IN pwszProperty] Property name
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::AddSD(IN PSECURITY_DESCRIPTOR pSD,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
IN PWSTR pwszProperty,
|
|
IN BOOL fAddAll)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC, "In CAccessList::AddSD\n"));
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
|
|
PISECURITY_DESCRIPTOR pISD = (PISECURITY_DESCRIPTOR)pSD;
|
|
|
|
dwErr = AddAcl(RtlpDaclAddrSecurityDescriptor(pISD),
|
|
RtlpSaclAddrSecurityDescriptor(pISD),
|
|
RtlpOwnerAddrSecurityDescriptor(pISD),
|
|
RtlpGroupAddrSecurityDescriptor(pISD),
|
|
SeInfo,
|
|
pwszProperty,
|
|
fAddAll,
|
|
pISD->Control);
|
|
|
|
acDebugOut((DEB_TRACE_ACC, "Out CAccessList::AddSD: 0x%lx\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::AddAcl, public
|
|
//
|
|
// Synopsis: Adds a new acl to the list. It converts the acls into an
|
|
// access list
|
|
//
|
|
// Arguments: [IN pDAcl] -- The DAcl to add
|
|
// [IN pSAcl] -- The SAcl to add
|
|
// [IN SeInfo] -- SecurityInfo
|
|
// [IN pwszProperty] Property name
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::AddAcl(IN PACL pDAcl,
|
|
IN PACL pSAcl,
|
|
IN PSID pOwner,
|
|
IN PSID pGroup,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
IN PWSTR pwszProperty,
|
|
IN BOOL fAddAll,
|
|
IN ULONG fControl)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC, "In CAccessList::AddAcl: 0x%lx\n", pDAcl));
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
_fSDValid = FALSE;
|
|
|
|
//
|
|
// If no parameters are given, just return success
|
|
//
|
|
if(SeInfo == 0)
|
|
{
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Ok, save off the group and owner if they exist
|
|
//
|
|
if(FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION))
|
|
{
|
|
if(pOwner == NULL || RtlValidSid((PSID)pOwner) == FALSE)
|
|
{
|
|
dwErr = ERROR_INVALID_OWNER;
|
|
}
|
|
else
|
|
{
|
|
ACC_ALLOC_AND_COPY_SID(pOwner, _pOwner, dwErr);
|
|
}
|
|
}
|
|
|
|
if(FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
|
|
{
|
|
if(pGroup == NULL || RtlValidSid((PSID)pGroup) == FALSE)
|
|
{
|
|
dwErr = ERROR_INVALID_PRIMARY_GROUP;
|
|
}
|
|
else
|
|
{
|
|
ACC_ALLOC_AND_COPY_SID(pGroup, _pGroup, dwErr);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Otherwise, we'll start processing them...
|
|
//
|
|
if(dwErr == ERROR_SUCCESS &&
|
|
FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION))
|
|
{
|
|
dwErr = ConvertAclToAccess(DACL_SECURITY_INFORMATION,
|
|
pDAcl,
|
|
pwszProperty,
|
|
fAddAll,
|
|
(BOOL)FLAG_ON(fControl, SE_DACL_PROTECTED));
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS &&
|
|
FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION))
|
|
{
|
|
dwErr = ConvertAclToAccess(SACL_SECURITY_INFORMATION,
|
|
pSAcl,
|
|
pwszProperty,
|
|
fAddAll,
|
|
(BOOL)FLAG_ON(fControl, SE_SACL_PROTECTED));
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC, "Out CAccessList::AddAcl: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::RemoveTrusteeFromAccess, public
|
|
//
|
|
// Synopsis: This method goes through and removes any explicit entries from
|
|
// an access list for the given trustee.
|
|
//
|
|
// Arguments: [IN SeInfo] -- Type of access list to operate on
|
|
// [IN pTrustee] -- Trustee to remove
|
|
// [IN pwszProperty] -- If present, this is the property to
|
|
// revoke the access on
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::RemoveTrusteeFromAccess(IN SECURITY_INFORMATION SeInfo,
|
|
IN PTRUSTEE pTrustee,
|
|
IN PWSTR pwszProperty OPTIONAL)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::RemoveTrusteeFromAccess\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOL PropertiesMatch = FALSE;
|
|
GUID Guid;
|
|
PWSTR pwszNewPropertyName, pwszSourceName;
|
|
|
|
//
|
|
// Now, we'll simply process all of the lists, and remove any of the
|
|
// specified entries
|
|
//
|
|
|
|
_fSDValid = FALSE;
|
|
|
|
//
|
|
// Enumerate through the list
|
|
//
|
|
_AccList.Reset();
|
|
PACCLIST_NODE pAccNode = (PACCLIST_NODE)_AccList.NextData();
|
|
|
|
while(pAccNode != NULL && dwErr == ERROR_SUCCESS)
|
|
{
|
|
PropertiesMatch = DoPropertiesMatch(pAccNode->pwszProperty, pwszProperty);
|
|
|
|
if(PropertiesMatch == FALSE && pwszProperty != NULL && pAccNode->pwszProperty != NULL)
|
|
{
|
|
//
|
|
// See if we should convert one to/from a guid and then
|
|
// compare it again
|
|
//
|
|
dwErr = UuidFromString(pwszProperty, &Guid);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pwszSourceName = pAccNode->pwszProperty;
|
|
}
|
|
else
|
|
{
|
|
dwErr = UuidFromString(pAccNode->pwszProperty, &Guid);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pwszSourceName = pwszProperty;
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccctrlLookupIdName(_pLDAP,
|
|
_pwszDsPathReference,
|
|
&Guid,
|
|
FALSE,
|
|
FALSE,
|
|
&pwszNewPropertyName);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
PropertiesMatch = DoPropertiesMatch(pwszSourceName,
|
|
pwszNewPropertyName);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if(PropertiesMatch)
|
|
{
|
|
//
|
|
// Get the list we need
|
|
//
|
|
PACTRL_ACCESS_ENTRY_LIST pList = SeInfo == DACL_SECURITY_INFORMATION ?
|
|
pAccNode->pAccessList :
|
|
pAccNode->pAuditList;
|
|
if(pList != NULL)
|
|
{
|
|
//
|
|
// Now, process it...
|
|
//
|
|
ULONG cRemoved = 0;
|
|
for(ULONG iIndex = 0;
|
|
iIndex < pList->cEntries && dwErr == ERROR_SUCCESS;
|
|
iIndex++)
|
|
{
|
|
BOOL fMatch = FALSE;
|
|
dwErr = DoTrusteesMatch(_pwszLookupServer,
|
|
pTrustee,
|
|
&(pList->pAccessList[iIndex].Trustee),
|
|
&fMatch);
|
|
if(dwErr == ERROR_SUCCESS && fMatch == TRUE)
|
|
{
|
|
cRemoved++;
|
|
|
|
//
|
|
// Indicate that this node is to be removed by setting the
|
|
// access flags to 0xFFFFFFFF
|
|
//
|
|
pList->pAccessList[iIndex].Access = 0xFFFFFFFF;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, see if we need to do anything...
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && cRemoved != 0)
|
|
{
|
|
PACTRL_ACCESS_ENTRY_LIST pNew;
|
|
dwErr = ShrinkList(pList,
|
|
cRemoved,
|
|
&pNew);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Finally, replace what is there with our new one
|
|
//
|
|
if(SeInfo == DACL_SECURITY_INFORMATION)
|
|
{
|
|
CHECK_HEAP
|
|
AccFree(pAccNode->pAccessList);
|
|
pAccNode->pAccessList = pNew;
|
|
if(pNew == NULL)
|
|
{
|
|
pAccNode->SeInfo &= ~DACL_SECURITY_INFORMATION;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AccFree(pAccNode->pAuditList);
|
|
pAccNode->pAuditList = pNew;
|
|
if(pNew == NULL)
|
|
{
|
|
pAccNode->SeInfo &= ~SACL_SECURITY_INFORMATION;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
pAccNode = (PACCLIST_NODE)_AccList.NextData();
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::RemoveTrusteeFromAccess: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::ConvertAclToAccess, private
|
|
//
|
|
// Synopsis: Converts the given dacl/sacl to an ACCLIST_NODE format
|
|
//
|
|
// Arguments: [IN SeInfo] -- What type of ACL this is
|
|
// [IN pAcl] -- The Acl to convert
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
|
|
// ERROR_INVALID_ACL -- ACL came in as downlevel
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::ConvertAclToAccess(IN SECURITY_INFORMATION SeInfo,
|
|
IN PACL pAcl,
|
|
IN PWSTR pwszProperty,
|
|
IN BOOL fAddAll,
|
|
IN BOOL fProtected)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC, "In CAccessList::ConvertAclToAccess\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
CSList AceList((FreeFunc)AccFree);
|
|
ACL EmptyAcl;
|
|
// CSList AceList((FreeFunc)DebugFree);
|
|
|
|
//
|
|
// Check for the case where we're setting a NULL acl. If it's a NULL SACL, turn
|
|
// it into an empty one.
|
|
//
|
|
if(pAcl == NULL && FLAG_ON(SeInfo,SACL_SECURITY_INFORMATION))
|
|
{
|
|
EmptyAcl.AclRevision = ACL_REVISION;
|
|
EmptyAcl.Sbz1 = 0;
|
|
EmptyAcl.AclSize = sizeof( ACL );
|
|
EmptyAcl.AceCount = 0;
|
|
EmptyAcl.Sbz2 = 0;
|
|
|
|
pAcl = &EmptyAcl;
|
|
}
|
|
|
|
if(pAcl == NULL)
|
|
{
|
|
//
|
|
// Ok, find the node for this property
|
|
//
|
|
PACCLIST_NODE pAccNode;
|
|
|
|
dwErr = GetNodeForProperty(_AccList,
|
|
pwszProperty,
|
|
&pAccNode);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// We'll fill in the information now
|
|
//
|
|
pAccNode->SeInfo |= SeInfo;
|
|
if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION))
|
|
{
|
|
pAccNode->pAccessList = NULL;
|
|
if(fProtected)
|
|
{
|
|
pAccNode->fState |= ACCLIST_DACL_PROTECTED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pAccNode->pAuditList = NULL;
|
|
if(fProtected)
|
|
{
|
|
pAccNode->fState |= ACCLIST_SACL_PROTECTED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Ok, we've got a valid acl list, so we'll process it...
|
|
//
|
|
|
|
//
|
|
// Basically, we'll save off our flags...
|
|
//
|
|
SeInfo == DACL_SECURITY_INFORMATION ?
|
|
_fDAclFlags = pAcl->Sbz1 :
|
|
_fSAclFlags = pAcl->Sbz1;
|
|
|
|
ULONG rgInheritFlags[] = {0,
|
|
INHERITED_PARENT,
|
|
INHERITED_GRANDPARENT};
|
|
//
|
|
// We need to keep track of the changes in denied/allowed pairs,
|
|
// so that we can determine between the inherited and parent
|
|
// inherited aces are, so that we can mark our new entries
|
|
//
|
|
ULONG iIFIndex = 0;
|
|
ULONG PrevIn = 0;
|
|
BOOL fPrevAllowed = FALSE;
|
|
|
|
|
|
//
|
|
// Ok, now we'll simply process each of the entries in the list
|
|
//
|
|
PACE_HEADER pAceHeader = (PACE_HEADER)FirstAce(pAcl);
|
|
for(ULONG iAce = 0;
|
|
iAce < pAcl->AceCount && dwErr == ERROR_SUCCESS;
|
|
iAce++, pAceHeader = (PACE_HEADER)NextAce(pAceHeader))
|
|
{
|
|
BOOL fThisAllowed = FALSE;
|
|
BOOL fIsExtendedAce = FALSE;
|
|
GUID PropID;
|
|
GUID *pPropID = NULL;
|
|
|
|
//
|
|
// Ok, now lets try to figure out what type of ACE this is, so we can
|
|
// do the neccessary mapping into the provider rights
|
|
//
|
|
switch(pAceHeader->AceType)
|
|
{
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
fThisAllowed = TRUE;
|
|
break;
|
|
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
fThisAllowed = TRUE;
|
|
fIsExtendedAce = TRUE;
|
|
break;
|
|
|
|
//
|
|
// Currently unsupported
|
|
//
|
|
case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
|
|
dwErr = ERROR_INVALID_ACL;
|
|
break;
|
|
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
break;
|
|
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
fIsExtendedAce = TRUE;
|
|
break;
|
|
|
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|
fIsExtendedAce = TRUE;
|
|
fThisAllowed = TRUE;
|
|
break;
|
|
|
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|
fThisAllowed = TRUE;
|
|
break;
|
|
|
|
default:
|
|
dwErr = ERROR_INVALID_ACL;
|
|
break;
|
|
|
|
}
|
|
|
|
LPGUID pProp = NULL;
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(fIsExtendedAce == TRUE)
|
|
{
|
|
PACCESS_ALLOWED_OBJECT_ACE pExAce =
|
|
(PACCESS_ALLOWED_OBJECT_ACE)pAceHeader;
|
|
if(FLAG_ON(pExAce->Flags,ACE_OBJECT_TYPE_PRESENT))
|
|
{
|
|
pProp = RtlObjectAceObjectType(pAceHeader);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pull what we can from the ace header
|
|
//
|
|
if((fThisAllowed == FALSE && fPrevAllowed == TRUE) ||
|
|
(FLAG_ON(pAceHeader->AceFlags,INHERITED_ACE) &&
|
|
PrevIn == 0))
|
|
{
|
|
iIFIndex++;
|
|
ASSERT(iIFIndex < sizeof(rgInheritFlags) / sizeof(ULONG));
|
|
if(iIFIndex >= sizeof(rgInheritFlags) / sizeof(ULONG))
|
|
{
|
|
dwErr = ERROR_INVALID_ACL;
|
|
}
|
|
|
|
PrevIn = pAceHeader->AceFlags;
|
|
}
|
|
else
|
|
{
|
|
PrevIn = pAceHeader->AceFlags;
|
|
}
|
|
|
|
dwErr = InsertAtoANode(AceList,
|
|
pProp,
|
|
pAceHeader,
|
|
rgInheritFlags[iIFIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ok, now we'll turn it into PACTRL_ACCESS structure, and call our
|
|
// add access routine
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ACTRL_ACCESS Access;
|
|
|
|
Access.cEntries = 0;
|
|
|
|
PACTRL_PROPERTY_ENTRY pAPE = (PACTRL_PROPERTY_ENTRY)
|
|
AccAlloc(max( AceList.QueryCount(), 1 ) * sizeof(ACTRL_PROPERTY_ENTRY));
|
|
if(pAPE == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
Access.cEntries = AceList.QueryCount();
|
|
Access.pPropertyAccessList = pAPE;
|
|
|
|
//
|
|
// Now, start filling them in...
|
|
//
|
|
AceList.Reset();
|
|
for(ULONG i = 0; i < Access.cEntries; i++)
|
|
{
|
|
if(fProtected)
|
|
{
|
|
pAPE[i].fListFlags = ACTRL_ACCESS_PROTECTED;
|
|
}
|
|
|
|
|
|
PACCLIST_ATOACCESS pAToA = (PACCLIST_ATOACCESS)AceList.NextData();
|
|
if(pAToA->pGuid != NULL)
|
|
{
|
|
dwErr = AccctrlLookupIdName(_pLDAP,
|
|
_pwszDsPathReference,
|
|
pAToA->pGuid,
|
|
TRUE,
|
|
FALSE, // avoid object GUIDs
|
|
(PWSTR *)&pAPE[i].lpProperty);
|
|
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pAPE[i].pAccessEntryList = (PACTRL_ACCESS_ENTRY_LIST)
|
|
AccAlloc(sizeof(ACTRL_ACCESS_ENTRY_LIST));
|
|
if(pAPE[i].pAccessEntryList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pAPE[i].pAccessEntryList->cEntries =
|
|
pAToA->AceList.QueryCount();
|
|
|
|
pAPE[i].pAccessEntryList->pAccessList =
|
|
(PACTRL_ACCESS_ENTRY)AccAlloc(
|
|
pAPE[i].pAccessEntryList->cEntries *
|
|
sizeof(ACTRL_ACCESS_ENTRY));
|
|
if(pAPE[i].pAccessEntryList->pAccessList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
PACTRL_ACCESS_ENTRY pAEL =
|
|
pAPE[i].pAccessEntryList->pAccessList;
|
|
pAToA->AceList.Reset();
|
|
for(ULONG j = 0;
|
|
j < pAPE[i].pAccessEntryList->cEntries &&
|
|
dwErr == ERROR_SUCCESS;
|
|
j++)
|
|
{
|
|
|
|
PACCLIST_ATOANODE pNode = (PACCLIST_ATOANODE)
|
|
pAToA->AceList.NextData();
|
|
|
|
dwErr = AceToAccessEntry(pNode->pAce,
|
|
pNode->fInherit,
|
|
_ObjType,
|
|
_KernelObjectType,
|
|
&(pAEL[j]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle the empty case...
|
|
//
|
|
if ( Access.cEntries == 0 && pAcl != NULL ) {
|
|
|
|
Access.cEntries = 1;
|
|
pAPE->pAccessEntryList = (PACTRL_ACCESS_ENTRY_LIST)
|
|
AccAlloc(sizeof(ACTRL_ACCESS_ENTRY_LIST));
|
|
if(pAPE->pAccessEntryList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
pAPE->pAccessEntryList->cEntries = 0;
|
|
pAPE->pAccessEntryList->pAccessList = NULL;
|
|
if(fProtected)
|
|
{
|
|
pAPE->fListFlags = ACTRL_ACCESS_PROTECTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If all of that worked, add it...
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AddAccessLists(SeInfo,
|
|
&Access,
|
|
TRUE);
|
|
}
|
|
|
|
//
|
|
// Regardless of success or failure, delete all memory
|
|
//
|
|
for(i = 0; i < Access.cEntries; i++)
|
|
{
|
|
AccFree((PWSTR *)Access.pPropertyAccessList[i].lpProperty);
|
|
if(Access.pPropertyAccessList[i].pAccessEntryList != NULL)
|
|
{
|
|
for(ULONG j = 0;
|
|
j < Access.pPropertyAccessList[i].
|
|
pAccessEntryList->cEntries;
|
|
j++)
|
|
{
|
|
if(Access.pPropertyAccessList[i].pAccessEntryList->pAccessList != NULL )
|
|
{
|
|
AccFree(Access.pPropertyAccessList[i].
|
|
pAccessEntryList->pAccessList[j].lpInheritProperty);
|
|
}
|
|
}
|
|
|
|
AccFree(Access.pPropertyAccessList[i].
|
|
pAccessEntryList->pAccessList);
|
|
AccFree(Access.pPropertyAccessList[i].pAccessEntryList);
|
|
}
|
|
}
|
|
|
|
AccFree(Access.pPropertyAccessList);
|
|
}
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::ConvertAclToAccess: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::MarshalAccessList, private
|
|
//
|
|
// Synopsis: Marshals the information specified by SeInfo into a single
|
|
// buffer
|
|
//
|
|
// Arguments: [IN SeInfo] -- Type of info to marshal
|
|
// [OUT ppAList] -- Where the information is
|
|
// returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERRROR_NOT_ENOUGH_MEMORY-- A memory allocation failed
|
|
//
|
|
// Notes: Memory is allocated as a block via a AccAlloc call and
|
|
// should be freed with a AccFree call
|
|
//
|
|
// SeInfo can only contain a SINGLE information value
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::MarshalAccessList(IN SECURITY_INFORMATION SeInfo,
|
|
OUT PACTRL_ACCESSW *ppAList)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In qCAccessList::MarshalAccessList\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
PACCLIST_CNODE pCNode = NULL;
|
|
ULONG cItems = 0;
|
|
|
|
ASSERT( SeInfo == DACL_SECURITY_INFORMATION || SeInfo == SACL_SECURITY_INFORMATION );
|
|
|
|
//
|
|
// First, compress the list...
|
|
//
|
|
dwErr = CompressList(SeInfo,
|
|
&pCNode,
|
|
&cItems);
|
|
//
|
|
// Then, we need to get the size of the memory block we need to allocate
|
|
//
|
|
DWORD cSize = 0;
|
|
DWORD cAEs = 0;
|
|
PBYTE pbEndOBuff = NULL;
|
|
ULONG cUsed = 0;
|
|
ULONG i = 0;
|
|
|
|
CSList TrusteesToMarshal(NULL);
|
|
CSList InheritPropsToMarshal((FreeFunc)LocalFree);
|
|
// CSList InheritPropsToMarshal((FreeFunc)DebugFree);
|
|
|
|
|
|
for(i = 0; i < cItems && dwErr == ERROR_SUCCESS; i++)
|
|
{
|
|
//
|
|
// Get the list we need
|
|
//
|
|
ULONG cEnts = pCNode[i].cExp + pCNode[i].cL1Inherit +
|
|
pCNode[i].cL2Inherit;
|
|
|
|
if(pCNode[i].pList != NULL)
|
|
{
|
|
|
|
cUsed++;
|
|
cSize += sizeof(ACTRL_ACCESS_ENTRY) * cEnts;
|
|
|
|
if ((SeInfo == DACL_SECURITY_INFORMATION ?
|
|
pCNode[ i ].pONode->pAccessList->pAccessList : pCNode[ i ].pONode->pAuditList->pAccessList) == NULL )
|
|
{
|
|
pCNode[i].Empty = TRUE;
|
|
}
|
|
|
|
//
|
|
// Finally, go through and figure out what trustees we'll need to
|
|
// marshal
|
|
//
|
|
for(ULONG iIndex = 0;
|
|
iIndex < cEnts && dwErr == ERROR_SUCCESS && pCNode[i].Empty == FALSE;
|
|
iIndex++)
|
|
{
|
|
dwErr = TrusteesToMarshal.InsertIfUnique(
|
|
&(pCNode[i].pList[iIndex].Trustee),
|
|
CompTrustees);
|
|
if(dwErr == ERROR_SUCCESS &&
|
|
pCNode[i].pList[iIndex].Trustee.MultipleTrusteeOperation ==
|
|
TRUSTEE_IS_IMPERSONATE)
|
|
{
|
|
dwErr = TrusteesToMarshal.InsertIfUnique(
|
|
pCNode[i].pList[iIndex].Trustee.pMultipleTrustee,
|
|
CompTrustees);
|
|
|
|
}
|
|
|
|
//
|
|
// Now, see if we have any inheritable properties to add
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(pCNode[i].pList[iIndex].lpInheritProperty != NULL &&
|
|
InheritPropsToMarshal.Find(
|
|
(PVOID)pCNode[i].pList[iIndex].lpInheritProperty,
|
|
CompInheritProps) == NULL)
|
|
{
|
|
PIPROP_IN_BUFF pPIB =
|
|
(PIPROP_IN_BUFF)AccAlloc(sizeof(IPROP_IN_BUFF));
|
|
if(pPIB == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
pPIB->pwszIProp = (LPWSTR)
|
|
pCNode[i].pList[iIndex].lpInheritProperty;
|
|
dwErr = InheritPropsToMarshal.Insert((PVOID)pPIB);
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
AccFree(pPIB);
|
|
}
|
|
else
|
|
{
|
|
cSize +=
|
|
SIZE_PWSTR(pCNode[i].pList[iIndex].
|
|
lpInheritProperty);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cUsed++;
|
|
}
|
|
|
|
//
|
|
// Also, add in the property size
|
|
//
|
|
cSize += SIZE_PWSTR(pCNode[i].pONode->pwszProperty);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
TrusteesToMarshal.Reset();
|
|
PTRUSTEE pTrustee = (PTRUSTEE)TrusteesToMarshal.NextData();
|
|
while(pTrustee != NULL)
|
|
{
|
|
if(pTrustee->TrusteeForm == TRUSTEE_IS_NAME)
|
|
{
|
|
cSize += SIZE_PWSTR(pTrustee->ptstrName);
|
|
}
|
|
else
|
|
{
|
|
PTRUSTEE_NODE pTN = NULL;
|
|
dwErr = GetTrusteeNode(pTrustee,
|
|
TRUSTEE_OPT_NOTHING,
|
|
&pTN);
|
|
cSize += SIZE_PWSTR(pTN->pwszTrusteeName);
|
|
}
|
|
|
|
if(pTrustee->MultipleTrusteeOperation == TRUSTEE_IS_IMPERSONATE)
|
|
{
|
|
cSize += sizeof(TRUSTEE);
|
|
}
|
|
|
|
pTrustee = (PTRUSTEE)TrusteesToMarshal.NextData();
|
|
}
|
|
}
|
|
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Now, all that we have is the size of the entries and the strings.
|
|
// We now need to add the size of our structures...
|
|
//
|
|
cSize += sizeof(PACTRL_ACCESSW) +
|
|
(cUsed * sizeof(ACTRL_PROPERTY_ENTRY)) +
|
|
(cUsed * sizeof(ACTRL_ACCESS_ENTRY)) +
|
|
sizeof(ACTRL_ACCESS_ENTRY_LIST);
|
|
|
|
acDebugOut((DEB_TRACE_ACC, "Total size needed: %lu\n", cSize));
|
|
|
|
//
|
|
// Now, we'll allocate it, and start filling it in
|
|
//
|
|
*ppAList = (PACTRL_ACCESSW)AccAlloc(cSize);
|
|
if(*ppAList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Now, we'll have to through first and add the property and
|
|
// names to the end of the block. We need to do this before
|
|
// adding the individual entries, so that as we go through and
|
|
// add each access entry, we can point the trustee to the
|
|
// proper place
|
|
//
|
|
pbEndOBuff = (PBYTE)*ppAList + cSize;
|
|
|
|
//
|
|
// First, process all of the property names
|
|
//
|
|
for(i = 0; i < cItems; i++)
|
|
{
|
|
//
|
|
// If we don't have a property name, set it to NULL
|
|
//
|
|
if(pCNode[i].pONode->pwszProperty == NULL)
|
|
{
|
|
pCNode[i].pONode->pwszPropInBuff = NULL;
|
|
}
|
|
else
|
|
{
|
|
ULONG cLen = SIZE_PWSTR(pCNode[i].pONode->pwszProperty);
|
|
pbEndOBuff -= cLen;
|
|
|
|
memcpy(pbEndOBuff,
|
|
pCNode[i].pONode->pwszProperty,
|
|
cLen);
|
|
pCNode[i].pONode->pwszPropInBuff = (PWSTR)pbEndOBuff;
|
|
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
TrusteesToMarshal.Reset();
|
|
PTRUSTEE pTrustee = (PTRUSTEE)TrusteesToMarshal.NextData();
|
|
while(pTrustee != NULL)
|
|
{
|
|
PTRUSTEE_NODE pTN = NULL;
|
|
dwErr = GetTrusteeNode(pTrustee,
|
|
TRUSTEE_OPT_NOTHING,
|
|
&pTN);
|
|
ULONG cLen = SIZE_PWSTR(pTN->pwszTrusteeName);
|
|
pbEndOBuff -= cLen;
|
|
|
|
memcpy(pbEndOBuff,
|
|
pTN->pwszTrusteeName,
|
|
cLen);
|
|
pTN->pwszTrusteeInBuff = (PWSTR)pbEndOBuff;
|
|
|
|
pTrustee = (PTRUSTEE)TrusteesToMarshal.NextData();
|
|
}
|
|
}
|
|
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
InheritPropsToMarshal.Reset();
|
|
PIPROP_IN_BUFF pPIB =
|
|
(PIPROP_IN_BUFF)InheritPropsToMarshal.NextData();
|
|
while(pPIB != NULL)
|
|
{
|
|
ULONG cLen = SIZE_PWSTR(pPIB->pwszIProp);
|
|
pbEndOBuff -= cLen;
|
|
|
|
memcpy(pbEndOBuff,
|
|
pPIB->pwszIProp,
|
|
cLen);
|
|
pPIB->pwszIPropInBuff = (PWSTR)pbEndOBuff;
|
|
|
|
pPIB = (PIPROP_IN_BUFF)InheritPropsToMarshal.NextData();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ok, now we'll start processing everything else... This
|
|
// begins by setting our count
|
|
//
|
|
|
|
(*ppAList)->cEntries = cUsed;
|
|
|
|
PBYTE pCurrBuff = (PBYTE)*ppAList + sizeof(ACTRL_PROPERTY_ENTRY);;
|
|
|
|
if((*ppAList)->cEntries != 0)
|
|
{
|
|
(*ppAList)->pPropertyAccessList =
|
|
(PACTRL_PROPERTY_ENTRYW)pCurrBuff;
|
|
|
|
pCurrBuff += (*ppAList)->cEntries * sizeof(ACTRL_PROPERTY_ENTRY);
|
|
}
|
|
else
|
|
{
|
|
(*ppAList)->pPropertyAccessList = NULL;
|
|
}
|
|
|
|
//
|
|
// Go through and set our property entry list correctly
|
|
//
|
|
ULONG iProp = 0; // Property list index
|
|
for(i = 0; i < cItems && cUsed != 0; i++)
|
|
{
|
|
BOOL fNullAcl = FALSE;
|
|
|
|
if(FLAG_ON(SeInfo,DACL_SECURITY_INFORMATION))
|
|
{
|
|
if(FLAG_ON(pCNode[i].pONode->fState, ACCLIST_DACL_PROTECTED) ||
|
|
FLAG_ON(_fDAclFlags, ACCLIST_DACL_PROTECTED) )
|
|
{
|
|
(*ppAList)->pPropertyAccessList[iProp].fListFlags =
|
|
ACTRL_ACCESS_PROTECTED;
|
|
}
|
|
|
|
}
|
|
|
|
if(FLAG_ON(SeInfo,SACL_SECURITY_INFORMATION))
|
|
{
|
|
if(FLAG_ON(pCNode[i].pONode->fState, ACCLIST_SACL_PROTECTED) ||
|
|
FLAG_ON(_fSAclFlags, ACCLIST_SACL_PROTECTED) )
|
|
{
|
|
(*ppAList)->pPropertyAccessList[iProp].fListFlags =
|
|
ACTRL_ACCESS_PROTECTED;
|
|
}
|
|
|
|
}
|
|
|
|
if(pCNode[i].pList == NULL)
|
|
{
|
|
fNullAcl = TRUE;
|
|
}
|
|
|
|
//
|
|
// Set our prop pointer
|
|
//
|
|
(*ppAList)->pPropertyAccessList[iProp].lpProperty =
|
|
pCNode[i].pONode->pwszPropInBuff;
|
|
|
|
if(fNullAcl == TRUE)
|
|
{
|
|
(*ppAList)->pPropertyAccessList[iProp].pAccessEntryList = NULL;
|
|
}
|
|
else
|
|
{
|
|
(*ppAList)->pPropertyAccessList[iProp].pAccessEntryList =
|
|
(PACTRL_ACCESS_ENTRY_LIST)pCurrBuff;
|
|
|
|
if(pCNode[i].pList != NULL)
|
|
{
|
|
pCurrBuff +=
|
|
(sizeof(ACTRL_ACCESS_ENTRY_LIST));
|
|
}
|
|
}
|
|
|
|
|
|
iProp++;
|
|
}
|
|
|
|
//
|
|
// Ok, now we'll actually go through and build the individual
|
|
// lists
|
|
//
|
|
iProp = 0;
|
|
if((*ppAList)->pPropertyAccessList != NULL)
|
|
{
|
|
pCurrBuff =
|
|
(PBYTE)(*ppAList)->pPropertyAccessList[iProp].pAccessEntryList;
|
|
pCurrBuff +=
|
|
(cUsed * sizeof(ACTRL_ACCESS_ENTRY_LIST));
|
|
}
|
|
for(i = 0; i < cItems && dwErr == ERROR_SUCCESS; i++)
|
|
{
|
|
//
|
|
// Get the list we need
|
|
//
|
|
if(pCNode[i].pList != NULL &&
|
|
(*ppAList)->pPropertyAccessList[iProp].pAccessEntryList != NULL)
|
|
{
|
|
PACTRL_ACCESS_ENTRY_LIST pAEL =
|
|
(*ppAList)->pPropertyAccessList[iProp].pAccessEntryList;
|
|
|
|
pAEL->cEntries = pCNode[i].cExp + pCNode[i].cL1Inherit +
|
|
pCNode[i].cL2Inherit;
|
|
|
|
if( !pCNode[i].Empty )
|
|
{
|
|
pAEL->pAccessList = (PACTRL_ACCESS_ENTRY)pCurrBuff;
|
|
pCurrBuff += (sizeof(ACTRL_ACCESS_ENTRY) * pAEL->cEntries);
|
|
|
|
}
|
|
else
|
|
{
|
|
pAEL->pAccessList = NULL;
|
|
pAEL->cEntries = 0;
|
|
}
|
|
|
|
//
|
|
// Copy the node and adjust our trustee
|
|
//
|
|
for(ULONG iIndex = 0; iIndex < pAEL->cEntries && !pCNode[i].Empty; iIndex++)
|
|
{
|
|
//
|
|
// Make sure we strip any of our internal flags info
|
|
//
|
|
|
|
pAEL->pAccessList[iIndex].fAccessFlags =
|
|
pCNode[i].pList[iIndex].fAccessFlags &
|
|
~ACCLIST_VALID_TYPE_FLAGS;
|
|
pAEL->pAccessList[iIndex].Access =
|
|
pCNode[i].pList[iIndex].Access;
|
|
pAEL->pAccessList[iIndex].ProvSpecificAccess =
|
|
pCNode[i].pList[iIndex].ProvSpecificAccess;
|
|
pAEL->pAccessList[iIndex].Inheritance =
|
|
pCNode[i].pList[iIndex].Inheritance;
|
|
if(pCNode[i].pList[iIndex].lpInheritProperty != NULL)
|
|
{
|
|
PIPROP_IN_BUFF pPIB =
|
|
(PIPROP_IN_BUFF)InheritPropsToMarshal.Find(
|
|
(PVOID)pCNode[i].pList[iIndex].
|
|
lpInheritProperty,
|
|
CompInheritProps);
|
|
ASSERT(pPIB != NULL);
|
|
pAEL->pAccessList[iIndex].lpInheritProperty =
|
|
pPIB->pwszIPropInBuff;
|
|
}
|
|
|
|
//
|
|
// Now, we only have to adjust our trustee
|
|
//
|
|
PTRUSTEE pTrustee = &(pCNode[i].pList[iIndex].Trustee);
|
|
PTRUSTEE_NODE pTN = NULL;
|
|
dwErr = GetTrusteeNode(pTrustee,
|
|
TRUSTEE_OPT_NOTHING,
|
|
&pTN);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// We'll add the trustee now...
|
|
//
|
|
pAEL->pAccessList[iIndex].Trustee.pMultipleTrustee =
|
|
NULL;
|
|
pAEL->pAccessList[iIndex].Trustee.MultipleTrusteeOperation =
|
|
NO_MULTIPLE_TRUSTEE;
|
|
pAEL->pAccessList[iIndex].Trustee.TrusteeForm =
|
|
TRUSTEE_IS_NAME;
|
|
pAEL->pAccessList[iIndex].Trustee.TrusteeType =
|
|
pTN->Trustee.TrusteeType;
|
|
pAEL->pAccessList[iIndex].Trustee.ptstrName =
|
|
pTN->pwszTrusteeInBuff;
|
|
|
|
if(pTN->pImpersonate != NULL)
|
|
{
|
|
//
|
|
// Ok, 2 things to do: adjust our current trustee
|
|
// state and add the new one
|
|
//
|
|
pAEL->pAccessList[iIndex].Trustee.
|
|
MultipleTrusteeOperation =
|
|
TRUSTEE_IS_IMPERSONATE;
|
|
pTrustee = pAEL->pAccessList[iIndex].Trustee.
|
|
pMultipleTrustee;
|
|
pbEndOBuff -= sizeof(TRUSTEE);
|
|
pTrustee = (PTRUSTEE)pbEndOBuff;
|
|
pTrustee->MultipleTrusteeOperation =
|
|
NO_MULTIPLE_TRUSTEE;
|
|
pTrustee->TrusteeForm = TRUSTEE_IS_NAME;
|
|
pTrustee->TrusteeType = TRUSTEE_IS_USER;
|
|
pTrustee->ptstrName =
|
|
pTN->pImpersonate->pwszTrusteeInBuff;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
iProp++;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free our memory if something failed
|
|
//
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
AccFree(*ppAList);
|
|
*ppAList = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
FreeCompressedList(pCNode,
|
|
cItems);
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::MarshalAccessList: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::MarshalAccessLists, public
|
|
//
|
|
// Synopsis: Returns the requested lists in single buffer form. Each
|
|
// access or audit list is returned seperately.
|
|
//
|
|
// Arguments: [IN SeInfo] -- Type of info requested
|
|
// [OUT ppAccess] -- Where the ACCESS list is
|
|
// returned if requested
|
|
// [OUT ppAudit] -- Where the AUDIT list is
|
|
// returned if requested
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::MarshalAccessLists(IN SECURITY_INFORMATION SeInfo,
|
|
OUT PACTRL_ACCESS *ppAccess,
|
|
OUT PACTRL_AUDIT *ppAudit)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::MarshalAccessLists\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
if(FLAG_ON(SeInfo,DACL_SECURITY_INFORMATION))
|
|
{
|
|
dwErr = MarshalAccessList(DACL_SECURITY_INFORMATION,
|
|
ppAccess);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS &&
|
|
FLAG_ON(SeInfo,SACL_SECURITY_INFORMATION))
|
|
{
|
|
dwErr = MarshalAccessList(SACL_SECURITY_INFORMATION,
|
|
ppAudit);
|
|
|
|
//
|
|
// If it failed and we allocated our Access list, make sure to free it
|
|
//
|
|
if(dwErr != ERROR_SUCCESS &&
|
|
FLAG_ON(SeInfo,DACL_SECURITY_INFORMATION))
|
|
{
|
|
AccFree(*ppAccess);
|
|
}
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::MarshalAccessLists: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::GetTrusteeNode, private
|
|
//
|
|
// Synopsis: Returns a pointer to a TRUSTEE_NODE for the given
|
|
// trustee. The flags indicate what information about the
|
|
// trustee needs to be present in the node. If the trustee
|
|
// does not already exist in the list, it will be added
|
|
//
|
|
// Arguments: [IN pTrustee] -- Trustee to find
|
|
// [IN fNodeOptions] -- Information that needs to be
|
|
// present in the node
|
|
// [OUT ppTrusteeNode] -- Where the node pointer is returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::GetTrusteeNode(IN PTRUSTEE pTrustee,
|
|
IN ULONG fNodeOptions,
|
|
OUT PTRUSTEE_NODE *ppTrusteeNode)
|
|
{
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::GetTrusteeNode\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// If we're doing an insert, we'll always want to create the name
|
|
//
|
|
if(FLAG_ON(fNodeOptions, TRUSTEE_OPT_INSERT_ONLY))
|
|
{
|
|
fNodeOptions |= TRUSTEE_OPT_NAME;
|
|
}
|
|
|
|
//
|
|
// First, see if it exists in our list...
|
|
//
|
|
PTRUSTEE_NODE pTrusteeNode =
|
|
(PTRUSTEE_NODE)_TrusteeList.Find((PVOID)pTrustee,
|
|
CompTrusteeToTrusteeNode);
|
|
if(pTrusteeNode == NULL)
|
|
{
|
|
//
|
|
// Ok, we'll have to create one...
|
|
//
|
|
pTrusteeNode = (PTRUSTEE_NODE)AccAlloc(sizeof(TRUSTEE_NODE));
|
|
if(pTrusteeNode == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(&(pTrusteeNode->Trustee),
|
|
pTrustee,
|
|
sizeof(TRUSTEE));
|
|
pTrusteeNode->SidType = SidTypeUnknown;
|
|
|
|
|
|
//
|
|
// Copy off whatever information we need
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(pTrustee->TrusteeForm == TRUSTEE_IS_SID)
|
|
{
|
|
if(RtlValidSid((PSID)pTrustee->ptstrName))
|
|
{
|
|
DWORD cSidSize =
|
|
RtlLengthSid((PSID)pTrustee->ptstrName);
|
|
pTrusteeNode->pSid = (PSID)AccAlloc(cSidSize);
|
|
if(pTrusteeNode->pSid == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(pTrusteeNode->pSid,
|
|
(PSID)pTrustee->ptstrName,
|
|
cSidSize);
|
|
pTrusteeNode->Trustee.ptstrName =
|
|
(PWSTR)pTrusteeNode->pSid;
|
|
pTrusteeNode->fFlags |= TRUSTEE_DELETE_SID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_INVALID_SID;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pTrusteeNode->pwszTrusteeName =
|
|
(PWSTR)AccAlloc(SIZE_PWSTR(pTrustee->ptstrName));
|
|
if(pTrusteeNode->pwszTrusteeName == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pTrusteeNode->pwszTrusteeName,
|
|
pTrustee->ptstrName);
|
|
pTrusteeNode->Trustee.ptstrName =
|
|
pTrusteeNode->pwszTrusteeName;
|
|
pTrusteeNode->fFlags |= TRUSTEE_DELETE_NAME;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// See if we need to insert an impersonate node as well
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(pTrustee->MultipleTrusteeOperation ==
|
|
TRUSTEE_IS_IMPERSONATE)
|
|
{
|
|
if(pTrustee->pMultipleTrustee == NULL)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
PTRUSTEE_NODE pImpersonate;
|
|
dwErr = GetTrusteeNode(pTrustee->pMultipleTrustee,
|
|
fNodeOptions,
|
|
&pImpersonate);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pTrusteeNode->pImpersonate = pImpersonate;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally, insert it in the list
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = _TrusteeList.Insert((PVOID)pTrusteeNode);
|
|
}
|
|
|
|
//
|
|
// If something went wrong, cleanup
|
|
//
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
DelTrusteeNode(pTrusteeNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Increment our use count if we were inserting
|
|
//
|
|
if(dwErr == ERROR_SUCCESS &&
|
|
FLAG_ON(fNodeOptions, TRUSTEE_OPT_INSERT_ONLY))
|
|
{
|
|
pTrusteeNode->cUseCount++;
|
|
}
|
|
|
|
//
|
|
// Now, if that worked, we'll need to make sure we have all the info
|
|
// we need...
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Now, if we don't have our sid type, we'll go ahead and determine it
|
|
//
|
|
if(pTrusteeNode->SidType == SidTypeUnknown)
|
|
{
|
|
//
|
|
// We'll do this by turning on the appropriate flag
|
|
//
|
|
if(pTrusteeNode->Trustee.TrusteeForm == TRUSTEE_IS_SID)
|
|
{
|
|
fNodeOptions |= TRUSTEE_OPT_NAME;
|
|
}
|
|
else
|
|
{
|
|
fNodeOptions |= TRUSTEE_OPT_SID;
|
|
}
|
|
}
|
|
|
|
dwErr = LookupTrusteeNodeInformation(_pwszLookupServer,
|
|
pTrusteeNode,
|
|
fNodeOptions);
|
|
|
|
//
|
|
// Finally, if that worked, and we have a compound trustee, do the
|
|
// child
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && pTrusteeNode->pImpersonate != NULL)
|
|
{
|
|
dwErr = GetTrusteeNode(&(pTrusteeNode->pImpersonate->Trustee),
|
|
fNodeOptions,
|
|
&(pTrusteeNode->pImpersonate));
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it all worked, return the new information
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ASSERT(pTrusteeNode->Trustee.ptstrName == pTrusteeNode->pSid ||
|
|
pTrusteeNode->Trustee.ptstrName == pTrusteeNode->pwszTrusteeName);
|
|
|
|
if(ppTrusteeNode != NULL)
|
|
{
|
|
*ppTrusteeNode = pTrusteeNode;
|
|
}
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::GetTrusteeNode: %lu\n", dwErr));
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::AddAccessLists, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [IN pTrustee] -- Trustee to find
|
|
// [IN fNodeOptions] -- Information that needs to be
|
|
// present in the node
|
|
// [OUT ppTrusteeNode] -- Where the node pointer is returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::AddAccessLists(IN SECURITY_INFORMATION SeInfo,
|
|
IN PACTRL_ACCESSW pAdd,
|
|
IN BOOL fMerge,
|
|
IN BOOL fOldStyleMerge)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"In CAccessList::AddAccessLists (%ws)\n",
|
|
fMerge == TRUE ? L"Merge" : L"NoMerge"));
|
|
|
|
//
|
|
// If NULL parameters are given, just return success
|
|
//
|
|
if(SeInfo == 0)
|
|
{
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Handle the empty list case
|
|
//
|
|
ACTRL_ACCESSW NullAccess;
|
|
ACTRL_PROPERTY_ENTRY EmptyPropList;
|
|
ACTRL_ACCESS_ENTRY_LIST EmptyAccessList;
|
|
if(pAdd == NULL)
|
|
{
|
|
//
|
|
// We don't allow NULL sacls, only empty ones
|
|
//
|
|
if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION))
|
|
{
|
|
NullAccess.cEntries = 1;
|
|
NullAccess.pPropertyAccessList = &EmptyPropList;
|
|
memset(&EmptyPropList,0,sizeof(EmptyPropList));
|
|
EmptyPropList.pAccessEntryList = &EmptyAccessList;
|
|
memset(&EmptyAccessList,0,sizeof(EmptyAccessList));
|
|
}
|
|
else
|
|
{
|
|
NullAccess.cEntries = 0;
|
|
NullAccess.pPropertyAccessList = NULL;
|
|
}
|
|
pAdd = &NullAccess;
|
|
}
|
|
|
|
|
|
if(pAdd->cEntries != 0 && pAdd->pPropertyAccessList == NULL)
|
|
{
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
else
|
|
{
|
|
_fSDValid = FALSE;
|
|
}
|
|
|
|
//
|
|
// If we're doing an old style merge, make sure we remove all of the
|
|
// existing entries for these trustees
|
|
//
|
|
if(fOldStyleMerge == TRUE)
|
|
{
|
|
dwErr = RevokeTrusteeAccess(SeInfo,
|
|
pAdd,
|
|
NULL);
|
|
}
|
|
|
|
//
|
|
// If we're doing a set, we'll have to go through and remove any entries
|
|
// that would be replaced before we go through and add the new entries
|
|
// This is because our input list can have multiple lists that deal
|
|
// with the same property, so a set applied then has disasterous results
|
|
//
|
|
ULONG iIndex = 0;
|
|
while(fMerge == FALSE && iIndex < pAdd->cEntries)
|
|
{
|
|
PACCLIST_NODE pAccNode = (PACCLIST_NODE)_AccList.Find((PVOID)
|
|
(pAdd->cEntries == 0 ?
|
|
NULL :
|
|
pAdd->pPropertyAccessList
|
|
[iIndex].lpProperty),
|
|
CompProps);
|
|
if(pAccNode != NULL)
|
|
{
|
|
if(SeInfo == DACL_SECURITY_INFORMATION)
|
|
{
|
|
FreeAEList(pAccNode->pAccessList);
|
|
pAccNode->pAccessList = NULL;
|
|
pAccNode->fState &= ~ACCLIST_DACL_PROTECTED;
|
|
|
|
}
|
|
else
|
|
{
|
|
FreeAEList(pAccNode->pAuditList);
|
|
pAccNode->fState &= ~ACCLIST_SACL_PROTECTED;
|
|
pAccNode->pAuditList = NULL;
|
|
}
|
|
}
|
|
iIndex++;
|
|
}
|
|
|
|
|
|
//
|
|
// We have to do this in a while loop, so we handle the empty access list
|
|
// properly without having to duplicate a bunch o' code
|
|
//
|
|
iIndex = 0;
|
|
while(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Ok, first, we need to find the matching property...
|
|
//
|
|
PACCLIST_NODE pAccNode;
|
|
dwErr = GetNodeForProperty(_AccList,
|
|
(PWSTR)(pAdd->cEntries == 0 ?
|
|
NULL :
|
|
pAdd->pPropertyAccessList
|
|
[iIndex].lpProperty),
|
|
&pAccNode);
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Otherwise, we'll figure out what we're doing...
|
|
//
|
|
PACTRL_ACCESS_ENTRY_LIST pList =
|
|
SeInfo == DACL_SECURITY_INFORMATION ?
|
|
pAccNode->pAccessList :
|
|
pAccNode->pAuditList;
|
|
|
|
pAccNode->SeInfo |= SeInfo;
|
|
|
|
if(pAdd->cEntries && FLAG_ON(pAdd->pPropertyAccessList[iIndex].fListFlags, ACTRL_ACCESS_PROTECTED))
|
|
{
|
|
SeInfo == DACL_SECURITY_INFORMATION ?
|
|
_fDAclFlags |= ACCLIST_DACL_PROTECTED :
|
|
_fSAclFlags |= ACCLIST_SACL_PROTECTED;
|
|
}
|
|
|
|
//
|
|
// Ok, we can quit now if we have an empty list
|
|
//
|
|
if( pAdd->cEntries == 0 ||
|
|
pAdd->pPropertyAccessList[iIndex].pAccessEntryList == NULL )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Validate that the list is correct
|
|
//
|
|
if(pAdd->cEntries &&
|
|
pAdd->pPropertyAccessList[iIndex].pAccessEntryList->cEntries != 0 &&
|
|
pAdd->pPropertyAccessList[iIndex].pAccessEntryList->pAccessList == NULL)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Save our flags
|
|
//
|
|
SeInfo == DACL_SECURITY_INFORMATION ?
|
|
_fDAclFlags |= pAdd->pPropertyAccessList[iIndex].fListFlags :
|
|
_fSAclFlags |= pAdd->pPropertyAccessList[iIndex].fListFlags;
|
|
|
|
//
|
|
// Now, we'll have to generate a new list
|
|
//
|
|
ULONG cSize = 0;
|
|
|
|
if(pAdd->pPropertyAccessList[iIndex].pAccessEntryList != NULL)
|
|
{
|
|
cSize += pAdd->pPropertyAccessList[iIndex].pAccessEntryList->cEntries;
|
|
}
|
|
|
|
if(pList != NULL)
|
|
{
|
|
cSize += pList->cEntries;
|
|
}
|
|
|
|
PACTRL_ACCESS_ENTRY_LIST pNew = (PACTRL_ACCESS_ENTRY_LIST)AccAlloc(
|
|
sizeof(ACTRL_ACCESS_ENTRY_LIST) +
|
|
(cSize * sizeof(ACTRL_ACCESS_ENTRY)));
|
|
if(pNew == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Otherwise, we'll add all the new denieds, followed by the old
|
|
// denieds, then the new accesses, followed by the old accesses
|
|
//
|
|
ULONG iNewIndex = 0;
|
|
|
|
ULONG cNewCopy = 0;
|
|
ULONG cOldCopy = 0;
|
|
|
|
pNew->pAccessList = (PACTRL_ACCESS_ENTRY)((PBYTE)pNew +
|
|
sizeof(ACTRL_ACCESS_ENTRY_LIST));
|
|
|
|
if ( pAdd->pPropertyAccessList[iIndex].pAccessEntryList->pAccessList == NULL ) {
|
|
|
|
pNew->cEntries = 0;
|
|
pNew->pAccessList = NULL;
|
|
SeInfo == DACL_SECURITY_INFORMATION ?
|
|
pAccNode->pAccessList = pNew :
|
|
pAccNode->pAuditList = pNew;
|
|
break;
|
|
}
|
|
//
|
|
// Count the new denieds
|
|
//
|
|
for(ULONG iCnt = 0;
|
|
pAdd->pPropertyAccessList[iIndex].pAccessEntryList != NULL &&
|
|
iCnt < pAdd->pPropertyAccessList[iIndex].pAccessEntryList->cEntries;
|
|
iCnt++)
|
|
{
|
|
if(FLAG_ON(pAdd->pPropertyAccessList[iIndex].pAccessEntryList->
|
|
pAccessList[iCnt].fAccessFlags,
|
|
ACTRL_ACCESS_DENIED))
|
|
{
|
|
cNewCopy++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, the old denieds
|
|
//
|
|
if(pList != NULL)
|
|
{
|
|
for(iCnt = 0;
|
|
iCnt < pList->cEntries;
|
|
iCnt++)
|
|
{
|
|
if(FLAG_ON(pList->pAccessList[iCnt].fAccessFlags,
|
|
ACTRL_ACCESS_DENIED))
|
|
{
|
|
cOldCopy++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Excellent.. Now, a series of copies
|
|
//
|
|
if(cNewCopy != 0)
|
|
{
|
|
for(iCnt = 0; iCnt < cNewCopy && dwErr == ERROR_SUCCESS; iCnt++)
|
|
{
|
|
if(SeInfo == DACL_SECURITY_INFORMATION)
|
|
{
|
|
if(!(FLAG_ON(pAdd->pPropertyAccessList[iIndex].pAccessEntryList->
|
|
pAccessList[iCnt].fAccessFlags,ACTRL_ACCESS_DENIED) ||
|
|
FLAG_ON(pAdd->pPropertyAccessList[iIndex].pAccessEntryList->
|
|
pAccessList[iCnt].fAccessFlags,ACTRL_ACCESS_ALLOWED)))
|
|
{
|
|
dwErr = ERROR_INVALID_ACL;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!(FLAG_ON(pAdd->pPropertyAccessList[iIndex].pAccessEntryList->
|
|
pAccessList[iCnt].fAccessFlags,ACTRL_AUDIT_SUCCESS) ||
|
|
FLAG_ON(pAdd->pPropertyAccessList[iIndex].pAccessEntryList->
|
|
pAccessList[iCnt].fAccessFlags,ACTRL_AUDIT_FAILURE)))
|
|
{
|
|
dwErr = ERROR_INVALID_ACL;
|
|
break;
|
|
}
|
|
|
|
}
|
|
dwErr = CopyAccessEntry(&(pNew->pAccessList[iNewIndex]),
|
|
&(pAdd->pPropertyAccessList[iIndex].
|
|
pAccessEntryList->pAccessList[iCnt]));
|
|
iNewIndex++;
|
|
}
|
|
pNew->cEntries += cNewCopy;
|
|
}
|
|
|
|
if(cOldCopy != 0)
|
|
{
|
|
memcpy(&(pNew->pAccessList[iNewIndex]),
|
|
pList->pAccessList,
|
|
cOldCopy * sizeof(ACTRL_ACCESS_ENTRY));
|
|
iNewIndex += cOldCopy;
|
|
pNew->cEntries += cOldCopy;
|
|
|
|
}
|
|
|
|
//
|
|
// Then, copy the alloweds...
|
|
//
|
|
for(iCnt = cNewCopy;
|
|
dwErr == ERROR_SUCCESS &&
|
|
pAdd->pPropertyAccessList[iIndex].pAccessEntryList != NULL &&
|
|
iCnt < pAdd->pPropertyAccessList[iIndex].pAccessEntryList->cEntries;
|
|
iCnt++)
|
|
{
|
|
ULONG fAccessFlag = pAdd->pPropertyAccessList[iIndex].pAccessEntryList->
|
|
pAccessList[iCnt].fAccessFlags;
|
|
|
|
if(fAccessFlag != ACTRL_ACCESS_ALLOWED &&
|
|
fAccessFlag != ACTRL_ACCESS_DENIED &&
|
|
(fAccessFlag & ~(ACTRL_AUDIT_SUCCESS | ACTRL_AUDIT_FAILURE)))
|
|
{
|
|
dwErr = ERROR_INVALID_FLAGS;
|
|
break;
|
|
}
|
|
|
|
if(SeInfo == DACL_SECURITY_INFORMATION)
|
|
{
|
|
if(!(FLAG_ON(fAccessFlag,ACTRL_ACCESS_DENIED) ||
|
|
FLAG_ON(fAccessFlag,ACTRL_ACCESS_ALLOWED)))
|
|
{
|
|
dwErr = ERROR_INVALID_ACL;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!(FLAG_ON(fAccessFlag,ACTRL_AUDIT_SUCCESS) ||
|
|
FLAG_ON(fAccessFlag,ACTRL_AUDIT_FAILURE)))
|
|
{
|
|
dwErr = ERROR_INVALID_ACL;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if(fAccessFlag == ACTRL_ACCESS_DENIED)
|
|
{
|
|
dwErr = ERROR_INVALID_ACL;
|
|
break;
|
|
}
|
|
|
|
dwErr = CopyAccessEntry(&(pNew->pAccessList[iNewIndex]),
|
|
&(pAdd->pPropertyAccessList[iIndex].
|
|
pAccessEntryList->pAccessList[iCnt]));
|
|
iNewIndex++;
|
|
pNew->cEntries++;
|
|
}
|
|
|
|
|
|
if(dwErr == ERROR_SUCCESS &&
|
|
pList != NULL && pList->cEntries - cOldCopy > 0)
|
|
{
|
|
memcpy(&(pNew->pAccessList[iNewIndex]),
|
|
&pList->pAccessList[cOldCopy],
|
|
(pList->cEntries - cOldCopy) * sizeof(ACTRL_ACCESS_ENTRY));
|
|
iNewIndex += cOldCopy;
|
|
pNew->cEntries += (pList->cEntries - cOldCopy);
|
|
|
|
}
|
|
|
|
//
|
|
// Now, if we got this far, we'll set it back in our list
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
SeInfo == DACL_SECURITY_INFORMATION ?
|
|
pAccNode->pAccessList = pNew :
|
|
pAccNode->pAuditList = pNew;
|
|
if(FLAG_ON(pAdd->pPropertyAccessList[iIndex].fListFlags, ACTRL_ACCESS_PROTECTED))
|
|
{
|
|
pAccNode->fState |= (SeInfo == DACL_SECURITY_INFORMATION ?
|
|
ACCLIST_DACL_PROTECTED :
|
|
ACCLIST_SACL_PROTECTED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AccFree(pNew);
|
|
}
|
|
|
|
iIndex++;
|
|
|
|
if(iIndex >= pAdd->cEntries)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::AddAccessLists: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::GetExplicitAccess, public
|
|
//
|
|
// Synopsis: Determines the explicit access for a given trustee. This
|
|
// includes group membership lookup
|
|
//
|
|
// Arguments: [IN pTrustee] -- Trustee to check the access for
|
|
// [IN pwszProperty] -- Property to get access for
|
|
// [OUT pDeniedMask] -- Where the denied mask is returned
|
|
// [OUT pAllowedMask] -- Where the allowed mask is returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::GetExplicitAccess(IN PTRUSTEE pTrustee,
|
|
IN PWSTR pwszProperty,
|
|
OUT PULONG pDeniedMask,
|
|
OUT PULONG pAllowedMask)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::GetExplicitAccess\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOL PropertiesMatch = FALSE;
|
|
GUID Guid;
|
|
PWSTR pwszNewPropertyName, pwszSourceName;
|
|
|
|
//
|
|
// Ok, first, get the specified access list for our property
|
|
//
|
|
PACCLIST_NODE pAccNode = (PACCLIST_NODE)_AccList.Find((PVOID)pwszProperty,
|
|
CompProps);
|
|
if(pAccNode == NULL)
|
|
{
|
|
//
|
|
// If that failed, lets see if we can translate it from a guid to a string
|
|
//
|
|
|
|
//
|
|
// See if we should convert one to/from a guid and then
|
|
// compare it again
|
|
//
|
|
dwErr = UuidFromString(pwszProperty, &Guid);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccctrlLookupIdName(_pLDAP,
|
|
_pwszDsPathReference,
|
|
&Guid,
|
|
FALSE,
|
|
FALSE,
|
|
&pwszNewPropertyName);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pAccNode = (PACCLIST_NODE)_AccList.Find((PVOID)pwszNewPropertyName,
|
|
CompProps);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Whoops... No such property...
|
|
//
|
|
if(pAccNode == NULL)
|
|
{
|
|
dwErr = ERROR_UNKNOWN_PROPERTY;
|
|
}
|
|
}
|
|
|
|
if(pAccNode != NULL)
|
|
{
|
|
PACTRL_ACCESS_ENTRY_LIST pList = pAccNode->pAccessList;
|
|
|
|
if(pList == NULL)
|
|
{
|
|
*pDeniedMask = 0;
|
|
*pAllowedMask = 0xFFFFFFFF;
|
|
}
|
|
else if(pList->cEntries == 0)
|
|
{
|
|
*pDeniedMask = 0xFFFFFFFF;
|
|
*pAllowedMask = 0;
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Now, we'll process each one of the entries, and build our masks
|
|
//
|
|
*pDeniedMask = 0;
|
|
*pAllowedMask = 0;
|
|
|
|
//
|
|
// Add our trustee, so we get our information
|
|
//
|
|
PTRUSTEE_NODE pTNode;
|
|
dwErr = GetTrusteeNode(pTrustee,
|
|
TRUSTEE_OPT_SID,
|
|
&pTNode);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
CMemberCheck MemberCheck(pTNode);
|
|
dwErr = MemberCheck.Init();
|
|
|
|
//
|
|
// Now, we'll just go
|
|
//
|
|
for(ULONG iIndex = 0;
|
|
iIndex < pList->cEntries && dwErr == ERROR_SUCCESS;
|
|
iIndex++)
|
|
{
|
|
if(!(pList->pAccessList[iIndex].Inheritance & INHERIT_ONLY_ACE))
|
|
{
|
|
PTRUSTEE_NODE pATNode;
|
|
dwErr = GetTrusteeNode(&(pList->pAccessList[iIndex].Trustee),
|
|
TRUSTEE_OPT_SID,
|
|
&pATNode);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
BOOL fAddMask;
|
|
dwErr = MemberCheck.IsMemberOf(pATNode,
|
|
&fAddMask);
|
|
if(dwErr == ERROR_SUCCESS && fAddMask == TRUE)
|
|
{
|
|
//
|
|
// Great, then we'll simply or in the bits
|
|
//
|
|
if(pList->pAccessList[iIndex].fAccessFlags ==
|
|
ACTRL_ACCESS_ALLOWED)
|
|
{
|
|
*pAllowedMask |= pList->pAccessList[iIndex].Access;
|
|
}
|
|
else
|
|
{
|
|
*pDeniedMask |= pList->pAccessList[iIndex].Access;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::GetExplicitAccess: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::GetExplicitAudits, public
|
|
//
|
|
// Synopsis: Determines the explicit audits for a given trustee. This
|
|
// includes group membership lookup
|
|
//
|
|
// Arguments: [IN pTrustee] -- Trustee to check the access for
|
|
// [IN pwszProperty] -- Property to get access for
|
|
// [OUT pSuccessMask] -- Where the successful audit mask
|
|
// is returned
|
|
// [OUT pFailureMask] -- Where the failed audit mask is
|
|
// returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::GetExplicitAudits(IN PTRUSTEE pTrustee,
|
|
IN PWSTR pwszProperty,
|
|
OUT PULONG pSuccessMask,
|
|
OUT PULONG pFailureMask)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::GetExplicitAudits\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
|
|
//
|
|
// Ok, first, get the specified access list for our property
|
|
//
|
|
//
|
|
// Ok, first, get the specified access list for our property
|
|
//
|
|
PACCLIST_NODE pAccNode = (PACCLIST_NODE)_AccList.Find((PVOID)pwszProperty,
|
|
CompProps);
|
|
if(pAccNode == NULL)
|
|
{
|
|
//
|
|
// Whoops... No such property...
|
|
//
|
|
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
PACTRL_ACCESS_ENTRY_LIST pList = pAccNode->pAuditList;
|
|
|
|
if(pList == NULL)
|
|
{
|
|
*pSuccessMask = 0;
|
|
*pFailureMask = 0;
|
|
}
|
|
else if(pList->cEntries == 0)
|
|
{
|
|
*pSuccessMask = 0;
|
|
*pFailureMask = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Now, we'll process each one of the entries, and build our masks
|
|
//
|
|
*pSuccessMask = 0;
|
|
*pFailureMask = 0;
|
|
|
|
//
|
|
// Add our trustee, so we get our information
|
|
//
|
|
PTRUSTEE_NODE pTNode;
|
|
dwErr = GetTrusteeNode(pTrustee,
|
|
TRUSTEE_OPT_SID,
|
|
&pTNode);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
CMemberCheck MemberCheck(pTNode);
|
|
dwErr = MemberCheck.Init();
|
|
|
|
//
|
|
// Now, we'll just go
|
|
//
|
|
for(ULONG iIndex = 0;
|
|
iIndex < pList->cEntries && dwErr == ERROR_SUCCESS;
|
|
iIndex++)
|
|
{
|
|
PTRUSTEE_NODE pATNode;
|
|
dwErr = GetTrusteeNode(&(pList->pAccessList[iIndex].Trustee),
|
|
TRUSTEE_OPT_SID,
|
|
&pATNode);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
BOOL fAddMask;
|
|
dwErr = MemberCheck.IsMemberOf(pATNode,
|
|
&fAddMask);
|
|
if(dwErr == ERROR_SUCCESS && fAddMask == TRUE)
|
|
{
|
|
//
|
|
// Great, then we'll simply or in the bits
|
|
//
|
|
if(pList->pAccessList[iIndex].fAccessFlags ==
|
|
ACTRL_AUDIT_SUCCESS)
|
|
{
|
|
*pSuccessMask |= AccessMaskForAccessEntry(
|
|
&(pList->pAccessList[iIndex]),
|
|
_ObjType);
|
|
}
|
|
|
|
if(pList->pAccessList[iIndex].fAccessFlags ==
|
|
ACTRL_AUDIT_FAILURE)
|
|
{
|
|
*pFailureMask |= AccessMaskForAccessEntry(
|
|
&(pList->pAccessList[iIndex]),
|
|
_ObjType);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::GetExplicitAudits: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::CopyAccessEntry, private
|
|
//
|
|
// Synopsis: Copies one access entry to another
|
|
//
|
|
// Arguments: [IN pNewEntry] -- Entry to be copied to
|
|
// [IN pOldEntry] -- Entry to copy from
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes: pNewEntry must already exist
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::CopyAccessEntry(IN PACTRL_ACCESS_ENTRY pNewEntry,
|
|
IN PACTRL_ACCESS_ENTRY pOldEntry)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::CopyAccessEntry\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// First, copy the members
|
|
//
|
|
memcpy(pNewEntry,
|
|
pOldEntry,
|
|
sizeof(ACTRL_ACCESS_ENTRY));
|
|
|
|
//
|
|
// We'll have to NULL out the inherit property on the given entry,
|
|
// since we only share it, and we don't want to prematurely delete it
|
|
//
|
|
pOldEntry->lpInheritProperty = NULL;
|
|
|
|
//
|
|
// Then, adjust the trustee
|
|
//
|
|
PTRUSTEE_NODE pTNode;
|
|
dwErr = GetTrusteeNode(&(pOldEntry->Trustee),
|
|
TRUSTEE_OPT_NOTHING,
|
|
&pTNode);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
PWSTR pwszNewTrustee;
|
|
if(pOldEntry->Trustee.TrusteeForm == TRUSTEE_IS_SID)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Transfered %p\n",
|
|
pTNode->pSid));
|
|
pwszNewTrustee = (PWSTR)pTNode->pSid;
|
|
}
|
|
else
|
|
{
|
|
pwszNewTrustee = pTNode->pwszTrusteeName;
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Transfered %ws\n",
|
|
pwszNewTrustee));
|
|
}
|
|
|
|
pNewEntry->Trustee.ptstrName = pwszNewTrustee;
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::CopyAccessEntry: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::GrowInheritedAces, private
|
|
//
|
|
// Synopsis: Expands inherited aces of a DS Object. This will actually
|
|
// add the appropriate access entries
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_INVALID_DATA -- The root access list was not
|
|
// loaded
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::GrowInheritedAces()
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::GrowInheritedAces\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
if(_ObjType != SE_DS_OBJECT && _ObjType != SE_DS_OBJECT_ALL)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::GrowInheritedAces: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
//
|
|
// Ok, find the node whose property is NULL
|
|
//
|
|
PACCLIST_NODE pNode = (PACCLIST_NODE)_AccList.Find(NULL,
|
|
CompProps);
|
|
if(pNode == NULL)
|
|
{
|
|
//
|
|
// If we haven't loaded the root, so we're screwed
|
|
//
|
|
|
|
dwErr = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
|
|
if(dwErr == ERROR_SUCCESS && _AccList.QueryCount() > 1)
|
|
{
|
|
PACTRL_ACCESS_ENTRYW *ppAccInherit = NULL;
|
|
PACTRL_ACCESS_ENTRYW *ppAudInherit = NULL;
|
|
ULONG cAud = 0;
|
|
ULONG cAcc = 0;
|
|
|
|
PACTRL_ACCESS_ENTRY_LIST pILists[2];
|
|
PACTRL_ACCESS_ENTRY **ppInheritList[2];
|
|
PULONG pulCounts[2];
|
|
|
|
pILists[0] = pNode->pAccessList;
|
|
ppInheritList[0] = &ppAccInherit;
|
|
pulCounts[0] = &cAcc;
|
|
|
|
pILists[1] = pNode->pAuditList;
|
|
ppInheritList[1] = &ppAudInherit;
|
|
pulCounts[1] = &cAud;
|
|
|
|
//
|
|
// Now, build the lists
|
|
//
|
|
for(ULONG iIndex = 0;
|
|
iIndex < 2 && dwErr == ERROR_SUCCESS;
|
|
iIndex++)
|
|
{
|
|
//
|
|
// Skip empty lists
|
|
//
|
|
if(pILists[iIndex] == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for(ULONG iItems = 0; iItems < pILists[iIndex]->cEntries; iItems++)
|
|
{
|
|
if(FLAG_ON(pILists[iIndex]->pAccessList[iItems].Inheritance,
|
|
VALID_INHERIT_FLAGS))
|
|
{
|
|
(*pulCounts[iIndex])++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, we'll do an allocation, and repeat the operation, doing
|
|
// the assignment
|
|
//
|
|
*ppInheritList[iIndex] = (PACTRL_ACCESS_ENTRY *)
|
|
AccAlloc(sizeof(PACTRL_ACCESS_ENTRY) * *pulCounts[iIndex]);
|
|
|
|
if(*ppInheritList[iIndex] == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
ULONG iInherit = 0;
|
|
for(iItems = 0; iItems < pILists[iIndex]->cEntries; iItems++)
|
|
{
|
|
if(FLAG_ON(pILists[iIndex]->pAccessList[iItems].Inheritance,
|
|
VALID_INHERIT_FLAGS))
|
|
{
|
|
(*ppInheritList)[iIndex][iInherit] =
|
|
&(pILists[iIndex]->pAccessList[iItems]);
|
|
}
|
|
}
|
|
}
|
|
|
|
_AccList.Reset();
|
|
PACCLIST_NODE pAccNode = (PACCLIST_NODE)_AccList.NextData();
|
|
|
|
//
|
|
// We'll do this for both the access and audit lists
|
|
//
|
|
|
|
while(pAccNode != NULL && dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(pAccNode->pwszProperty == NULL)
|
|
{
|
|
PACTRL_ACCESS_ENTRY_LIST *ppLists[2];
|
|
|
|
ppLists[0] = &(pAccNode->pAccessList);
|
|
ppLists[1] = &(pAccNode->pAuditList);
|
|
|
|
for(ULONG iList = 0;
|
|
iList < 2 && dwErr == ERROR_SUCCESS;
|
|
iList++)
|
|
{
|
|
//
|
|
// Skip empty lists
|
|
//
|
|
if(ppLists[iList] == NULL ||
|
|
(*ppInheritList)[iList] == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We'll build an AList and then do a merge
|
|
//
|
|
ACTRL_ACCESS_ENTRY_LIST AEL;
|
|
AEL.cEntries = *pulCounts[iList];
|
|
AEL.pAccessList = **ppInheritList[iList];
|
|
|
|
ACTRL_PROPERTY_ENTRY PEntry;
|
|
PEntry.lpProperty = pAccNode->pwszProperty;
|
|
PEntry.pAccessEntryList = &AEL;
|
|
|
|
ACTRL_ACCESSW AList;
|
|
AList.cEntries = 1;
|
|
AList.pPropertyAccessList = &PEntry;
|
|
|
|
dwErr = AddAccessLists(iList == 0 ?
|
|
DACL_SECURITY_INFORMATION :
|
|
SACL_SECURITY_INFORMATION,
|
|
&AList,
|
|
TRUE);
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pAccNode = (PACCLIST_NODE)_AccList.NextData();
|
|
}
|
|
|
|
//
|
|
// Finally, free our memory
|
|
//
|
|
for(iIndex = 0; iIndex < 2; iIndex++)
|
|
{
|
|
AccFree(*ppInheritList[iIndex]);;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::GrowInheritedAces: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::CollapseInheritedAces, private
|
|
//
|
|
// Synopsis: The inverse of the above function. Goes through the lists
|
|
// and collapses the inherited access entries for a DS object
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::CollapseInheritedAces()
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::CollapseInheritedAces\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
if(_ObjType != SE_DS_OBJECT && _ObjType != SE_DS_OBJECT_ALL)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::CollapseInheritedAces: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
//
|
|
// Now, we'll process all the items EXCEPT the root. (We only collapse
|
|
// on properties)
|
|
//
|
|
_AccList.Reset();
|
|
PACCLIST_NODE pAccNode = (PACCLIST_NODE)_AccList.NextData();
|
|
|
|
//
|
|
// We'll do this for both the access and audit lists
|
|
//
|
|
|
|
while(pAccNode != NULL && dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(pAccNode->pwszProperty == NULL)
|
|
{
|
|
PACTRL_ACCESS_ENTRY_LIST *ppLists[2];
|
|
ULONG cLists = 0;
|
|
|
|
if(pAccNode->pAccessList != NULL)
|
|
{
|
|
ppLists[cLists++] = &(pAccNode->pAccessList);
|
|
}
|
|
|
|
if(pAccNode->pAuditList != NULL)
|
|
{
|
|
ppLists[cLists++] = &(pAccNode->pAuditList);
|
|
}
|
|
|
|
for(ULONG iList = 0;
|
|
iList < cLists && dwErr == ERROR_SUCCESS;
|
|
iList++)
|
|
{
|
|
ULONG cRemoved = 0;
|
|
for(ULONG iIndex = 0;
|
|
iIndex < (*ppLists)[iList]->cEntries;
|
|
iIndex++)
|
|
{
|
|
if(FLAG_ON((*ppLists)[iList]->pAccessList[iIndex].
|
|
Inheritance,
|
|
INHERITED_ACE))
|
|
{
|
|
(*ppLists)[iList]->pAccessList[iIndex].Access =
|
|
0xFFFFFFFF;
|
|
cRemoved++;
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS && cRemoved != 0)
|
|
{
|
|
PACTRL_ACCESS_ENTRY_LIST pNew;
|
|
dwErr = ShrinkList((*ppLists)[iList],
|
|
cRemoved,
|
|
&pNew);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
AccFree((*ppLists)[iList]);
|
|
(*ppLists)[iList] = pNew;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pAccNode = (PACCLIST_NODE)_AccList.NextData();
|
|
}
|
|
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::CollapseInheritedAces: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::ShrinkList, private
|
|
//
|
|
// Synopsis: Shrinks the given list. This goes through and removes any
|
|
// nodes that have been marked as "deleted", as indicated by the
|
|
// access mask.
|
|
//
|
|
// Arguments: [IN pOldList] -- List to shrink
|
|
// [IN cRemoved] -- Number of items to be removed
|
|
// [OUT ppNewList] -- Where the "shrunk" list is
|
|
// returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::ShrinkList(IN PACTRL_ACCESS_ENTRY_LIST pOldList,
|
|
IN ULONG cRemoved,
|
|
IN PACTRL_ACCESS_ENTRY_LIST *ppNewList)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::ShrinkList\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Ok, we'll process the list, and repackage it...
|
|
//
|
|
PACTRL_ACCESS_ENTRY_LIST pNew = (PACTRL_ACCESS_ENTRY_LIST)
|
|
AccAlloc(sizeof(ACTRL_ACCESS_ENTRY_LIST) +
|
|
((pOldList->cEntries - cRemoved) *
|
|
sizeof(ACTRL_ACCESS_ENTRY)));
|
|
if(pNew == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
pNew->pAccessList = (PACTRL_ACCESS_ENTRY)((PBYTE)pNew +
|
|
sizeof(ACTRL_ACCESS_ENTRY_LIST));
|
|
//
|
|
// Now, copy the ones that we still want to keep over
|
|
//
|
|
ULONG iNew = 0;
|
|
ULONG Removed = 0;
|
|
for(ULONG iIndex = 0; iIndex < pOldList->cEntries; iIndex++)
|
|
{
|
|
if(pOldList->pAccessList[iIndex].Access != 0xFFFFFFFF)
|
|
{
|
|
memcpy(&(pNew->pAccessList[iNew]),
|
|
&(pOldList->pAccessList[iIndex]),
|
|
sizeof(ACTRL_ACCESS_ENTRY));
|
|
iNew++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Remove the trustee from the list
|
|
//
|
|
dwErr = RemoveTrustee(&(pOldList->pAccessList[iIndex].Trustee));
|
|
|
|
Removed++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we've removed all of the entries, remove the item as well...
|
|
//
|
|
if(iNew == 0 && Removed > 0 )
|
|
{
|
|
AccFree( pNew );
|
|
*ppNewList = NULL;
|
|
}
|
|
else
|
|
{
|
|
pNew->cEntries = iNew;
|
|
*ppNewList = pNew;
|
|
}
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::ShrinkList: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::BuildSDForAccessList, public
|
|
//
|
|
// Synopsis: Builds a security descriptor for the loaded access lists
|
|
//
|
|
// Arguments: [OUT ppSD] -- Where the built security
|
|
// descriptor is returned
|
|
// [OUT pSeInfo] -- Where the SeInfo corresponding
|
|
// to the Security Descriptor is
|
|
// returned
|
|
// [IN fFlags] -- Flags that govern the lifetime
|
|
// of the SD. It controls whether
|
|
// the class deletes the SD or not
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::BuildSDForAccessList(OUT PSECURITY_DESCRIPTOR *ppSD,
|
|
OUT PSECURITY_INFORMATION pSeInfo,
|
|
IN ULONG fFlags)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::BuildSDForAccessList\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// If our current SD is valid, simply return it...
|
|
//
|
|
if(_fSDValid == TRUE)
|
|
{
|
|
*ppSD = _pSD;
|
|
*pSeInfo = _SeInfo;
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::BuildSDForAccessList: 0\n"));
|
|
return(dwErr);
|
|
}
|
|
else
|
|
{
|
|
AccFree(_pSD);
|
|
_pSD = NULL;
|
|
_fFreeSD = FALSE;
|
|
_cSDSize = 0;
|
|
}
|
|
|
|
|
|
if(FLAG_ON(fFlags,ACCLIST_SD_NOFREE))
|
|
{
|
|
_fFreeSD = FALSE;
|
|
}
|
|
else
|
|
{
|
|
_fFreeSD = TRUE;
|
|
}
|
|
|
|
UCHAR AclRevision = ACL_REVISION2;
|
|
if(_ObjType == SE_DS_OBJECT || _ObjType == SE_DS_OBJECT_ALL)
|
|
{
|
|
AclRevision = ACL_REVISION_DS;
|
|
}
|
|
|
|
PACCLIST_CNODE pCDAcl = NULL;
|
|
PACCLIST_CNODE pCSAcl = NULL;
|
|
ULONG cDAcls = 0;
|
|
ULONG cSAcls = 0;
|
|
ULONG cDAclSize = 0;
|
|
ULONG cSAclSize = 0;
|
|
|
|
dwErr = CompressList(DACL_SECURITY_INFORMATION,
|
|
&pCDAcl,
|
|
&cDAcls);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(cDAcls != 0)
|
|
{
|
|
*pSeInfo = DACL_SECURITY_INFORMATION;
|
|
}
|
|
else
|
|
{
|
|
*pSeInfo = 0;
|
|
}
|
|
|
|
dwErr = CompressList(SACL_SECURITY_INFORMATION,
|
|
&pCSAcl,
|
|
&cSAcls);
|
|
if(dwErr == ERROR_SUCCESS && cSAcls != 0)
|
|
{
|
|
*pSeInfo |= SACL_SECURITY_INFORMATION;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, go through and size the DACL and SACL
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = SizeCompressedListAsAcl(pCDAcl,
|
|
cDAcls,
|
|
&cDAclSize,
|
|
FALSE);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = SizeCompressedListAsAcl(pCSAcl,
|
|
cSAcls,
|
|
&cSAclSize,
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If all that worked, add in our security descriptor size and owner/group
|
|
//
|
|
ULONG cSize = 0;
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
cSize = cDAclSize + cSAclSize;
|
|
cSize += sizeof(SECURITY_DESCRIPTOR);
|
|
|
|
//
|
|
// Owner and group
|
|
//
|
|
if(_pOwner != NULL)
|
|
{
|
|
cSize += RtlLengthSid(_pOwner);
|
|
*pSeInfo |= OWNER_SECURITY_INFORMATION;
|
|
}
|
|
|
|
if(_pGroup != NULL)
|
|
{
|
|
cSize += RtlLengthSid(_pGroup);
|
|
*pSeInfo |= GROUP_SECURITY_INFORMATION;
|
|
}
|
|
|
|
if(FLAG_ON(fFlags, ACCLIST_SD_DS_STYLE))
|
|
{
|
|
cSize += sizeof(ULONG);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If that worked, then we'll allocate for the security descriptor.
|
|
// We allocate in a block, so we can free it in another routine later
|
|
//
|
|
BOOL fProtected=FALSE;
|
|
PSECURITY_DESCRIPTOR pSD;
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pSD = (PSECURITY_DESCRIPTOR)AccAlloc(cSize);
|
|
if(pSD == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
PBYTE pbEndOBuff = (PBYTE)pSD + cSize;
|
|
|
|
if(FLAG_ON(fFlags, ACCLIST_SD_DS_STYLE))
|
|
{
|
|
pSD = (PSECURITY_DESCRIPTOR)((PBYTE)pSD + sizeof(ULONG));
|
|
}
|
|
|
|
_cSDSize = cSize;
|
|
|
|
//
|
|
// First, build an absolute SD
|
|
//
|
|
if(InitializeSecurityDescriptor(pSD,
|
|
SECURITY_DESCRIPTOR_REVISION) ==
|
|
FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
//
|
|
// First, set the owner
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && _pOwner != NULL)
|
|
{
|
|
PSID pOwner = (PSID)(pbEndOBuff - RtlLengthSid(_pOwner));
|
|
RtlCopySid((ULONG)(pbEndOBuff - (PBYTE)pOwner),
|
|
pOwner,
|
|
_pOwner);
|
|
pbEndOBuff = (PBYTE)pOwner;
|
|
if(SetSecurityDescriptorOwner(pSD,
|
|
pOwner,
|
|
FALSE) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Next, try our hand with the group
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && _pGroup != NULL)
|
|
{
|
|
PSID pGroup = (PSID)(pbEndOBuff - RtlLengthSid(_pGroup));
|
|
RtlCopySid((ULONG)(pbEndOBuff - (PBYTE)pGroup),
|
|
pGroup,
|
|
_pGroup);
|
|
pbEndOBuff = (PBYTE)pGroup;
|
|
if(SetSecurityDescriptorGroup(pSD,
|
|
pGroup,
|
|
FALSE) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ok, then the DACL
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && cDAclSize != 0)
|
|
{
|
|
PACL pAcl = (PACL)(pbEndOBuff - cDAclSize);
|
|
|
|
pAcl->AclRevision = AclRevision;
|
|
pAcl->Sbz1 = (BYTE)_fDAclFlags;
|
|
pAcl->AclSize = (USHORT)cDAclSize;
|
|
pAcl->AceCount = 0;
|
|
|
|
if(cDAclSize > sizeof(ACL))
|
|
{
|
|
dwErr = BuildAcl(pCDAcl,
|
|
cDAcls,
|
|
pAcl,
|
|
DACL_SECURITY_INFORMATION,
|
|
&fProtected);
|
|
|
|
#if DBG
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
DWORD cChk = 0;
|
|
|
|
PKNOWN_ACE pAce = (PKNOWN_ACE)FirstAce(pAcl);
|
|
for(ULONG z = 0; z < pAcl->AceCount; z++)
|
|
{
|
|
cChk += (DWORD)pAce->Header.AceSize;
|
|
|
|
pAce = (PKNOWN_ACE)NextAce(pAce);
|
|
}
|
|
|
|
cChk += sizeof(ACL);
|
|
|
|
ASSERT(cChk == cDAclSize);
|
|
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if( FLAG_ON(_fDAclFlags, ACCLIST_DACL_PROTECTED ))
|
|
{
|
|
((SECURITY_DESCRIPTOR *)pSD)->Control |= SE_DACL_PROTECTED;
|
|
}
|
|
|
|
}
|
|
|
|
pbEndOBuff = (PBYTE)pAcl;
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(SetSecurityDescriptorDacl(pSD,
|
|
TRUE,
|
|
pAcl,
|
|
FALSE) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS && fProtected == TRUE)
|
|
{
|
|
((SECURITY_DESCRIPTOR *)pSD)->Control |= SE_DACL_PROTECTED;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if( cDAclSize == 0 && FLAG_ON(_fDAclFlags,ACCLIST_DACL_PROTECTED ))
|
|
{
|
|
((SECURITY_DESCRIPTOR *)pSD)->Control |= SE_DACL_PROTECTED;
|
|
}
|
|
|
|
if ( FLAG_ON( *pSeInfo, DACL_SECURITY_INFORMATION ) )
|
|
{
|
|
((SECURITY_DESCRIPTOR *) pSD)->Dacl = NULL;
|
|
((SECURITY_DESCRIPTOR *) pSD)->Control |= SE_DACL_PRESENT;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Finally, the SACL
|
|
//
|
|
fProtected=FALSE;
|
|
|
|
if(dwErr == ERROR_SUCCESS && cSAclSize != 0)
|
|
{
|
|
PACL pAcl = (PACL)(pbEndOBuff - cSAclSize);
|
|
|
|
pAcl->AclRevision = AclRevision;
|
|
pAcl->Sbz1 = (BYTE)_fSAclFlags;
|
|
pAcl->AclSize = (USHORT)cSAclSize;
|
|
pAcl->AceCount = 0;
|
|
|
|
if(cSAclSize > sizeof(ACL))
|
|
{
|
|
dwErr = BuildAcl(pCSAcl,
|
|
cSAcls,
|
|
pAcl,
|
|
SACL_SECURITY_INFORMATION,
|
|
&fProtected);
|
|
}
|
|
else
|
|
{
|
|
|
|
if( FLAG_ON(_fSAclFlags,ACCLIST_SACL_PROTECTED ))
|
|
{
|
|
((SECURITY_DESCRIPTOR *)pSD)->Control |= SE_SACL_PROTECTED;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
pbEndOBuff = (PBYTE)pAcl;
|
|
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(SetSecurityDescriptorSacl(pSD,
|
|
TRUE,
|
|
pAcl,
|
|
FALSE) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS && fProtected == TRUE)
|
|
{
|
|
((SECURITY_DESCRIPTOR *)pSD)->Control |= SE_SACL_PROTECTED;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if( cSAclSize == 0 && FLAG_ON(_fSAclFlags, ACCLIST_SACL_PROTECTED ))
|
|
{
|
|
((SECURITY_DESCRIPTOR *)pSD)->Control |= SE_SACL_PROTECTED;
|
|
}
|
|
|
|
if ( FLAG_ON( *pSeInfo, SACL_SECURITY_INFORMATION ) )
|
|
{
|
|
if(SetSecurityDescriptorSacl(pSD,
|
|
TRUE,
|
|
NULL,
|
|
FALSE) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#if DBG
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ASSERT(pbEndOBuff == (PBYTE)pSD + sizeof(SECURITY_DESCRIPTOR));
|
|
acDebugOut((DEB_TRACE_ACC,"pbEndOBuff: 0x%lx\n", pbEndOBuff));
|
|
acDebugOut((DEB_TRACE_ACC,"pSD: 0x%lx\n",
|
|
(PBYTE)pSD + sizeof(SECURITY_DESCRIPTOR)));
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Great.. Now if all of that worked, we'll convert it to
|
|
// an absolute format if necessary, or
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(FLAG_ON(fFlags,ACCLIST_SD_ABSOK))
|
|
{
|
|
*ppSD = pSD;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We'll need to make this self relative
|
|
//
|
|
ULONG cNewSDSize = 0;
|
|
MakeSelfRelativeSD(pSD,
|
|
NULL,
|
|
&cNewSDSize);
|
|
ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
if(FLAG_ON(fFlags,ACCLIST_SD_DS_STYLE))
|
|
{
|
|
cNewSDSize += sizeof(ULONG);
|
|
}
|
|
|
|
*ppSD = (PSECURITY_DESCRIPTOR)AccAlloc(cNewSDSize);
|
|
if(*ppSD == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
if(FLAG_ON(fFlags,ACCLIST_SD_DS_STYLE))
|
|
{
|
|
*ppSD = (PSECURITY_DESCRIPTOR)
|
|
((PBYTE)*ppSD + sizeof(ULONG));
|
|
}
|
|
_cSDSize = cNewSDSize;
|
|
if(MakeSelfRelativeSD(pSD,
|
|
*ppSD,
|
|
&cNewSDSize) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
if(FLAG_ON(fFlags, ACCLIST_SD_DS_STYLE))
|
|
{
|
|
pSD = (PSECURITY_DESCRIPTOR)((PBYTE)pSD - sizeof(ULONG));
|
|
}
|
|
//
|
|
// It all worked, so free our initial sd
|
|
//
|
|
AccFree(pSD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
if(FLAG_ON(fFlags, ACCLIST_SD_DS_STYLE))
|
|
{
|
|
pSD = (PSECURITY_DESCRIPTOR)((PBYTE)pSD - sizeof(ULONG));
|
|
}
|
|
AccFree(pSD);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save and return our security information
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
_pSD = *ppSD;
|
|
_SeInfo = *pSeInfo;
|
|
}
|
|
|
|
//
|
|
// Set our flags properly
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(FLAG_ON(*pSeInfo, DACL_SECURITY_INFORMATION))
|
|
{
|
|
((PISECURITY_DESCRIPTOR)_pSD)->Control |=
|
|
SE_DACL_AUTO_INHERIT_REQ;
|
|
}
|
|
|
|
if(FLAG_ON(*pSeInfo, SACL_SECURITY_INFORMATION))
|
|
{
|
|
((PISECURITY_DESCRIPTOR)_pSD)->Control |=
|
|
SE_SACL_AUTO_INHERIT_REQ;
|
|
}
|
|
|
|
if(FLAG_ON(fFlags,ACCLIST_SD_DS_STYLE))
|
|
{
|
|
PULONG pSE = (PULONG)((PBYTE)*ppSD - sizeof(ULONG));
|
|
*pSE = *pSeInfo;
|
|
|
|
*ppSD = (PSECURITY_DESCRIPTOR)pSE;
|
|
}
|
|
}
|
|
|
|
|
|
FreeCompressedList(pCDAcl, cDAcls);
|
|
FreeCompressedList(pCSAcl, cSAcls);
|
|
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
|
|
_fFreeSD = FALSE;
|
|
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::BuildSDForAccessList: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::AddOwnerGroup, public
|
|
//
|
|
// Synopsis: Adds an owner and or group to the class
|
|
//
|
|
// Arguments: [IN SeInfo] -- Add owner or group?
|
|
// [IN pOwner] -- Owner to add
|
|
// [IN pGroup] -- Group to add
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::AddOwnerGroup(IN SECURITY_INFORMATION SeInfo,
|
|
IN PTRUSTEE pOwner,
|
|
IN PTRUSTEE pGroup)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::AddOwnerGroup\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
SID_NAME_USE SidType;
|
|
//
|
|
// Basically, we'll simply add them in..
|
|
//
|
|
if(FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION))
|
|
{
|
|
if(pOwner->TrusteeForm == TRUSTEE_IS_SID)
|
|
{
|
|
if(RtlValidSid((PSID)pOwner->ptstrName) == FALSE)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
ACC_ALLOC_AND_COPY_SID((PSID)pOwner->ptstrName,_pOwner, dwErr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwErr = AccctrlLookupSid(_pwszLookupServer,
|
|
pOwner->ptstrName,
|
|
TRUE,
|
|
&_pOwner,
|
|
&SidType);
|
|
}
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS && FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
|
|
{
|
|
if(pGroup->TrusteeForm == TRUSTEE_IS_SID)
|
|
{
|
|
if(RtlValidSid((PSID)pGroup->ptstrName) == FALSE)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
ACC_ALLOC_AND_COPY_SID((PSID)pGroup->ptstrName,_pGroup, dwErr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwErr = AccctrlLookupSid(_pwszLookupServer,
|
|
pGroup->ptstrName,
|
|
TRUE,
|
|
&_pGroup,
|
|
&SidType);
|
|
}
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::AddOwnerGroup: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::GetSDSidAsTrustee, public
|
|
//
|
|
// Synopsis: Returns the specified owner/group as a trustee...
|
|
//
|
|
// Arguments: [IN SeInfo] -- Get owner or group?
|
|
// [OUT ppTrustee] -- Where the trustee is returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::GetSDSidAsTrustee(IN SECURITY_INFORMATION SeInfo,
|
|
OUT PTRUSTEE *ppTrustee)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::GetSDSidAsTrustee\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
|
|
PSID pSid;
|
|
if(FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
|
|
{
|
|
pSid = _pGroup;
|
|
}
|
|
else
|
|
{
|
|
pSid = _pOwner;
|
|
}
|
|
|
|
dwErr = AccLookupAccountTrustee(_pwszLookupServer,
|
|
pSid,
|
|
ppTrustee);
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::GetSDSidAsTrustee: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::GetExplicitEntries, public
|
|
//
|
|
// Synopsis: Returns a list of explicit entries for the given trustee.
|
|
// This will lookup group membership
|
|
//
|
|
// Arguments: [IN pTrustee] -- Trustee to lookup
|
|
// [IN pwszProperty] -- Property to worry about
|
|
// [IN SeInfo] -- Look for access or audit list
|
|
// [OUT pcEntries] -- Where the count of items is
|
|
// returned.
|
|
// [OUT ppAEList] -- Where the explicit entry list is
|
|
// returned
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::GetExplicitEntries(IN PTRUSTEE pTrustee,
|
|
IN PWSTR pwszProperty,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
OUT PULONG pcEntries,
|
|
OUT PACTRL_ACCESS_ENTRYW *ppAEList)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::GetExplicitEntries\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Ok, first, get the specified access list for our property
|
|
//
|
|
PACCLIST_NODE pAccNode = (PACCLIST_NODE)_AccList.Find((PVOID)pwszProperty,
|
|
CompProps);
|
|
if(pAccNode == NULL)
|
|
{
|
|
//
|
|
// Whoops... No such property...
|
|
//
|
|
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
PACTRL_ACCESS_ENTRY_LIST pList = pAccNode->pAccessList;
|
|
|
|
if(pList != NULL)
|
|
{
|
|
//
|
|
// Now, we'll process each one of the entries, and build our masks
|
|
//
|
|
|
|
CSList MemberList(NULL);
|
|
|
|
//
|
|
// Add our trustee, so we get our information
|
|
//
|
|
PTRUSTEE_NODE pTNode;
|
|
dwErr = GetTrusteeNode(pTrustee,
|
|
TRUSTEE_OPT_SID,
|
|
&pTNode);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
CMemberCheck MemberCheck(pTNode);
|
|
dwErr = MemberCheck.Init();
|
|
|
|
//
|
|
// Now, we'll just go
|
|
//
|
|
for(ULONG iIndex = 0;
|
|
iIndex < pList->cEntries && dwErr == ERROR_SUCCESS;
|
|
iIndex++)
|
|
{
|
|
PTRUSTEE_NODE pATNode;
|
|
dwErr = GetTrusteeNode(
|
|
&(pList->pAccessList[iIndex].Trustee),
|
|
TRUSTEE_OPT_SID,
|
|
&pATNode);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
BOOL fAddMask;
|
|
dwErr = MemberCheck.IsMemberOf(pATNode,
|
|
&fAddMask);
|
|
if(dwErr == ERROR_SUCCESS && fAddMask == TRUE)
|
|
{
|
|
dwErr = MemberList.Insert((PVOID)
|
|
&pList->pAccessList[iIndex]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ok, if we have everything, build our list
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
*pcEntries = 0;
|
|
if(MemberList.QueryCount() == 0)
|
|
{
|
|
*ppAEList = NULL;
|
|
}
|
|
else
|
|
{
|
|
dwErr = GetTrusteeNode(pTrustee,
|
|
TRUSTEE_OPT_NAME,
|
|
&pTNode);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ULONG cSize = SIZE_PWSTR(pTNode->pwszTrusteeName);
|
|
|
|
cSize += MemberList.QueryCount() *
|
|
sizeof(ACTRL_ACCESS_ENTRY);
|
|
|
|
*ppAEList = (PACTRL_ACCESS_ENTRY)AccAlloc(cSize);
|
|
|
|
if(*ppAEList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
PWSTR pwszTrustee = (PWSTR)((PBYTE)(*ppAEList) +
|
|
(MemberList.QueryCount() *
|
|
sizeof(ACTRL_ACCESS_ENTRY)));
|
|
wcscpy(pwszTrustee,
|
|
pTNode->pwszTrusteeName);
|
|
|
|
//
|
|
// Now, copy the rest of the information
|
|
//
|
|
MemberList.Reset();
|
|
PACTRL_ACCESS_ENTRY pCurrent =
|
|
(PACTRL_ACCESS_ENTRY)MemberList.NextData();
|
|
while(pCurrent != NULL)
|
|
{
|
|
memcpy(&((*ppAEList)[*pcEntries]),
|
|
pCurrent,
|
|
sizeof(ACTRL_ACCESS_ENTRY));
|
|
|
|
//
|
|
// Then, adjust the trustee...
|
|
//
|
|
(*ppAEList)[*pcEntries].Trustee.TrusteeType =
|
|
pTrustee->TrusteeType;
|
|
|
|
(*ppAEList)[*pcEntries].Trustee.TrusteeForm =
|
|
TRUSTEE_IS_NAME;
|
|
(*ppAEList)[*pcEntries].Trustee.ptstrName =
|
|
pwszTrustee;
|
|
pCurrent =
|
|
(PACTRL_ACCESS_ENTRY)MemberList.NextData();
|
|
(*pcEntries)++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::GetExplicitEntries: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::RevokeTrusteeAccess, public
|
|
//
|
|
// Synopsis: Removes any explicit entries that exist for the named
|
|
// trustees
|
|
//
|
|
// Arguments: [IN SeInfo] -- Whether to process the access and
|
|
// or audit list
|
|
// [IN pSrcList] -- Trustee information list to
|
|
// process
|
|
// [IN pwszProperty] -- Optional property to do the revoke for
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::RevokeTrusteeAccess(IN SECURITY_INFORMATION SeInfo,
|
|
IN PACTRL_ACCESSW pSrcList,
|
|
IN PWSTR pwszProperty OPTIONAL)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::RevokeTrusteeAccess\n"));
|
|
|
|
CSList TrusteeList(NULL);
|
|
|
|
//
|
|
// First, generate a list of all of the passed in trustees
|
|
//
|
|
for(ULONG iAcc = 0;
|
|
iAcc < pSrcList->cEntries && dwErr == ERROR_SUCCESS;
|
|
iAcc++)
|
|
{
|
|
PACTRL_ACCESS_ENTRY_LIST pAEL =
|
|
pSrcList->pPropertyAccessList[iAcc].pAccessEntryList;
|
|
|
|
//
|
|
// Then the access entry strings
|
|
//
|
|
for(ULONG iEntry = 0;
|
|
pAEL && iEntry < pAEL->cEntries && dwErr == ERROR_SUCCESS;
|
|
iEntry++)
|
|
{
|
|
dwErr = TrusteeList.InsertIfUnique(
|
|
(PVOID)&(pAEL->pAccessList[iEntry].Trustee),
|
|
CompTrustees);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ok, now if that worked, we have a list of trustees... We'll simply
|
|
// go through and revoke them all from our current list before
|
|
// continuing
|
|
//
|
|
TrusteeList.Reset();
|
|
PTRUSTEE pTrustee = (PTRUSTEE)TrusteeList.NextData();
|
|
while(pTrustee != NULL && dwErr == ERROR_SUCCESS)
|
|
{
|
|
TRUSTEE TempTrustee;
|
|
TempTrustee.TrusteeForm = TRUSTEE_IS_SID;
|
|
TempTrustee.ptstrName = NULL;
|
|
|
|
//
|
|
// If we have a domain relative name, we'll look the name as a sid
|
|
//
|
|
if(pTrustee->TrusteeForm == TRUSTEE_IS_NAME && wcschr(pTrustee->ptstrName, L'\\') == NULL)
|
|
{
|
|
SID_NAME_USE Type;
|
|
dwErr = AccctrlLookupSid(_pwszLookupServer,
|
|
pTrustee->ptstrName,
|
|
TRUE,
|
|
(PSID *)&(TempTrustee.ptstrName),
|
|
&Type);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pTrustee = &TempTrustee;
|
|
}
|
|
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = RemoveTrusteeFromAccess(SeInfo,
|
|
pTrustee,
|
|
pwszProperty);
|
|
}
|
|
|
|
AccFree(TempTrustee.ptstrName);
|
|
|
|
pTrustee = (PTRUSTEE)TrusteeList.NextData();
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::GetExplicitEntries: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::CompressList, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [] -- Whether to process the access and
|
|
// or audit list
|
|
// [] -- Trustee information list to
|
|
// process
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::CompressList(IN SECURITY_INFORMATION SeInfo,
|
|
OUT PACCLIST_CNODE *ppList,
|
|
OUT PULONG pcItems)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::CompressList\n"));
|
|
BOOL fEmpty = FALSE;
|
|
|
|
//
|
|
// Ok, first, we'll have to go through and determine how many items there
|
|
// are
|
|
//
|
|
*pcItems = 0;
|
|
*ppList = 0;
|
|
_AccList.Reset();
|
|
PACCLIST_NODE pAccNode = (PACCLIST_NODE)_AccList.NextData();
|
|
while(pAccNode != NULL)
|
|
{
|
|
if(FLAG_ON(pAccNode->SeInfo, SeInfo))
|
|
{
|
|
(*pcItems)++;
|
|
}
|
|
pAccNode = (PACCLIST_NODE)_AccList.NextData();
|
|
}
|
|
|
|
//
|
|
// Now, do some allocations
|
|
//
|
|
if(*pcItems != 0)
|
|
{
|
|
*ppList = (PACCLIST_CNODE)AccAlloc(sizeof(ACCLIST_CNODE) * *pcItems);
|
|
if(*ppList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
_AccList.Reset();
|
|
ULONG i = 0;
|
|
while(i < *pcItems )
|
|
{
|
|
pAccNode = (PACCLIST_NODE)_AccList.NextData();
|
|
|
|
if(FLAG_ON(pAccNode->SeInfo, SeInfo))
|
|
{
|
|
(*ppList)[i++].pONode = pAccNode;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, sort the list based upon the property name
|
|
//
|
|
qsort(*ppList,
|
|
*pcItems,
|
|
sizeof(ACCLIST_CNODE),
|
|
CNodeCompare);
|
|
//
|
|
// Now, start processing them all...
|
|
//
|
|
for(i = 0; i < *pcItems; i++)
|
|
{
|
|
PACCLIST_CNODE pCN = &(*ppList)[i];
|
|
PACTRL_ACCESS_ENTRY_LIST pList =
|
|
SeInfo == DACL_SECURITY_INFORMATION ?
|
|
pCN->pONode->pAccessList :
|
|
pCN->pONode->pAuditList;
|
|
if(pList == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(pList->cEntries == 0)
|
|
{
|
|
|
|
fEmpty = TRUE;
|
|
(*ppList)[i].Empty = TRUE;
|
|
pList->pAccessList = NULL;
|
|
}
|
|
else
|
|
{
|
|
fEmpty = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Go through and build some temprorary lists for each
|
|
// type.
|
|
//
|
|
CSList ExpList(NULL);
|
|
CSList L1List(NULL);
|
|
CSList L2List(NULL);
|
|
|
|
//
|
|
// We'll go through each entry and add it to our
|
|
// proper list. We'll also check for entries to
|
|
// collapse here as well. We'll do this by having our
|
|
// node comparrison routine mark the new access entry with
|
|
// a special bit if it finds a match
|
|
//
|
|
for(ULONG j = 0; j < pList->cEntries && !fEmpty; j++)
|
|
{
|
|
//
|
|
// Mark our ordering information
|
|
//
|
|
pList->pAccessList[j].fAccessFlags |=
|
|
GetOrderTypeForAccessEntry(
|
|
(*ppList)[i].pONode->pwszProperty,
|
|
&pList->pAccessList[j],
|
|
SeInfo);
|
|
if(FLAG_ON(pList->pAccessList[j].Inheritance,
|
|
INHERITED_GRANDPARENT))
|
|
{
|
|
dwErr = L2List.InsertIfUnique(
|
|
&(pList->pAccessList[j]),
|
|
CompAndMarkCompressNode);
|
|
}
|
|
else if(FLAG_ON(pList->pAccessList[j].Inheritance,
|
|
INHERITED_PARENT) ||
|
|
FLAG_ON(pList->pAccessList[j].Inheritance,
|
|
INHERITED_ACCESS_ENTRY))
|
|
{
|
|
dwErr = L1List.InsertIfUnique(
|
|
&(pList->pAccessList[j]),
|
|
CompAndMarkCompressNode);
|
|
}
|
|
else
|
|
{
|
|
dwErr = ExpList.InsertIfUnique(
|
|
&(pList->pAccessList[j]),
|
|
CompAndMarkCompressNode);
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
} // for(j = 0; j < pList->cEntries; j++)
|
|
|
|
if ( fEmpty ) {
|
|
|
|
dwErr = ExpList.Insert( &(pList->pAccessList));
|
|
|
|
}
|
|
|
|
//
|
|
// Ok, now we are read to actually build our new list
|
|
//
|
|
ULONG cUsed = ExpList.QueryCount() + L1List.QueryCount() +
|
|
L2List.QueryCount();
|
|
ULONG cCompressed = pList->cEntries - cUsed;
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pCN->pList = (PACTRL_ACCESS_ENTRY)AccAlloc(
|
|
sizeof(ACTRL_ACCESS_ENTRY) * cUsed);
|
|
if(pCN->pList == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Start processing them all...
|
|
//
|
|
ULONG iIndex = 0;
|
|
ULONG cComp;
|
|
pCN->cExp = ExpList.QueryCount();
|
|
pCN->cL1Inherit = L1List.QueryCount();
|
|
pCN->cL2Inherit = L2List.QueryCount();
|
|
|
|
if(pCN->cExp != 0)
|
|
{
|
|
dwErr = AddSubList(pCN,
|
|
ExpList,
|
|
iIndex);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS && pCN->cL1Inherit != 0)
|
|
{
|
|
iIndex += pCN->cExp;
|
|
|
|
dwErr = AddSubList(pCN,
|
|
L1List,
|
|
iIndex);
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS && pCN->cL2Inherit != 0)
|
|
{
|
|
iIndex += pCN->cL1Inherit;
|
|
dwErr = AddSubList(pCN,
|
|
L2List,
|
|
iIndex);
|
|
}
|
|
|
|
|
|
//
|
|
// If that worked, we'll see about compressing
|
|
//
|
|
if(dwErr == ERROR_SUCCESS && cCompressed > 0)
|
|
{
|
|
for(j = 0;
|
|
j < pList->cEntries && cCompressed > 0;
|
|
j++)
|
|
{
|
|
if(FLAG_ON(pList->pAccessList[j].fAccessFlags,
|
|
ACCLIST_COMPRESS))
|
|
{
|
|
for(ULONG k = 0; k < cUsed; k++)
|
|
{
|
|
if(CompAndMarkCompressNode(
|
|
&(pList->pAccessList[j]),
|
|
&(pCN->pList[k])) == TRUE)
|
|
{
|
|
pList->pAccessList[j].fAccessFlags &=
|
|
~ACCLIST_COMPRESS;
|
|
pCN->pList[k].fAccessFlags |=
|
|
pList->pAccessList[j].fAccessFlags;
|
|
pCN->pList[k].Access |=
|
|
pList->pAccessList[j].Access;
|
|
pCN->pList[k].Inheritance |=
|
|
pList->pAccessList[j].Inheritance;
|
|
pCN->pList[k].ProvSpecificAccess |=
|
|
pList->pAccessList[j].ProvSpecificAccess;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS && cCompressed > 0)
|
|
{
|
|
//
|
|
// We'll have to go through and undo any compress
|
|
// bits we may have set
|
|
//
|
|
for(ULONG k = 0; k < j; k++)
|
|
{
|
|
pList->pAccessList[j].fAccessFlags &=
|
|
~ACCLIST_COMPRESS;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
FreeCompressedList(*ppList,
|
|
*pcItems);
|
|
*ppList = 0;
|
|
}
|
|
//
|
|
// Handle the special case of the non-zero, empty list
|
|
//
|
|
else if(fEmpty == TRUE)
|
|
{
|
|
(*ppList)[0].cExp = 1;
|
|
}
|
|
}
|
|
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::CompressList: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::CompressList, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [] -- Whether to process the access and
|
|
// or audit list
|
|
// [] -- Trustee information list to
|
|
// process
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID CAccessList::FreeCompressedList(IN PACCLIST_CNODE pList,
|
|
IN ULONG cItems)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::FreeCompressedList\n"));
|
|
|
|
if(pList != NULL)
|
|
{
|
|
for(ULONG i = 0; i < cItems; i++)
|
|
{
|
|
if(pList[i].pList == NULL)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
AccFree(pList[i].pList);
|
|
}
|
|
}
|
|
|
|
AccFree(pList);
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::FreeCompressedList\n"));
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::AddSubList, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [] -- Whether to process the access and
|
|
// or audit list
|
|
// [] -- Trustee information list to
|
|
// process
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::AddSubList(IN PACCLIST_CNODE pCList,
|
|
IN CSList& TempList,
|
|
IN ULONG iStart)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::AddSubList\n"));
|
|
|
|
if ( pCList->Empty ) {
|
|
|
|
return( dwErr );
|
|
}
|
|
//
|
|
// First, we copy all of the list entries
|
|
//
|
|
TempList.Reset();
|
|
PACTRL_ACCESS_ENTRY pAE = (PACTRL_ACCESS_ENTRY)TempList.NextData();
|
|
ULONG i = iStart;
|
|
while(pAE != NULL)
|
|
{
|
|
memcpy(&(pCList->pList[i]), pAE, sizeof(ACTRL_ACCESS_ENTRY));
|
|
i++;
|
|
pAE = (PACTRL_ACCESS_ENTRY)TempList.NextData();
|
|
}
|
|
|
|
//
|
|
// Now, order them...
|
|
//
|
|
dwErr = OrderListBySid(pCList,
|
|
iStart,
|
|
TempList.QueryCount());
|
|
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::AddSubList: %lu\n", dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::CompressList, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [] -- Whether to process the access and
|
|
// or audit list
|
|
// [] -- Trustee information list to
|
|
// process
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::SizeCompressedListAsAcl(IN PACCLIST_CNODE pList,
|
|
IN ULONG cItems,
|
|
OUT PULONG pcSize,
|
|
IN BOOL fForceNullToEmpty)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::SizeCompressedListAsAcl\n"));
|
|
ULONG cTotalEnts = 0;
|
|
BOOL Empty = FALSE;
|
|
|
|
*pcSize = 0;
|
|
|
|
for(ULONG i = 0; i < cItems; i++)
|
|
{
|
|
ULONG cEnts = pList[i].cExp + pList[i].cL1Inherit + pList[i].cL2Inherit;
|
|
cTotalEnts += cEnts;
|
|
for(ULONG j = 0; j < cEnts; j++)
|
|
{
|
|
BOOL fObjectAce = FALSE;
|
|
if(pList[i].pONode->pwszProperty != NULL)
|
|
{
|
|
(*pcSize) += sizeof(GUID);
|
|
fObjectAce = TRUE;
|
|
}
|
|
|
|
if(pList[i].pList == NULL || pList[i].Empty == TRUE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(pList[i].pList[j].lpInheritProperty != NULL)
|
|
{
|
|
(*pcSize) += sizeof(GUID);
|
|
fObjectAce = TRUE;
|
|
}
|
|
|
|
//
|
|
// Find the trustee for this node
|
|
//
|
|
PTRUSTEE_NODE pTN = NULL;
|
|
dwErr = GetTrusteeNode(&(pList[i].pList[j].Trustee),
|
|
TRUSTEE_OPT_SID,
|
|
&pTN);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Then, add in the SID
|
|
//
|
|
(*pcSize) += RtlLengthSid(pTN->pSid) - sizeof(ULONG);
|
|
if(pTN->pImpersonate != NULL)
|
|
{
|
|
(*pcSize) += RtlLengthSid(pTN->pSid);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Then, add the size of the ACE
|
|
//
|
|
if(pTN->pImpersonate != NULL)
|
|
{
|
|
if(fObjectAce == FALSE)
|
|
{
|
|
(*pcSize) += sizeof(KNOWN_COMPOUND_ACE);
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(fObjectAce == TRUE)
|
|
{
|
|
(*pcSize) += sizeof(KNOWN_OBJECT_ACE);
|
|
}
|
|
else
|
|
{
|
|
(*pcSize) += sizeof(KNOWN_ACE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(cEnts == 0 && fForceNullToEmpty == TRUE)
|
|
{
|
|
Empty = TRUE;
|
|
}
|
|
}
|
|
|
|
if(cTotalEnts != 0 || Empty == TRUE)
|
|
{
|
|
(*pcSize) += sizeof(ACL);
|
|
}
|
|
|
|
acDebugOut((DEB_TRACE_ACC,
|
|
"Out CAccessList::SizeCompressedListAsAcl: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::BuildAcl, private
|
|
//
|
|
// Synopsis: The method will build an acl out of the individual access entries
|
|
//
|
|
// Arguments: [pList] -- List of entries in compressed form
|
|
// [cItems] -- Number of items in the list
|
|
// [pAcl] -- Acl to fill in
|
|
// [SeInfo] -- Building DACL or SACL
|
|
// [pfProtected] -- If TRUE, the acl should be protected
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::BuildAcl(IN PACCLIST_CNODE pList,
|
|
IN ULONG cItems,
|
|
IN PACL pAcl,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
OUT BOOL *pfProtected)
|
|
{
|
|
acDebugOut((DEB_TRACE_ACC,"In CAccessList::BuildAcl\n"));
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
BOOL fIsSacl = FALSE;
|
|
|
|
|
|
PULONG pIList = (PULONG)AccAlloc(cItems * sizeof(ULONG));
|
|
if(pIList == NULL)
|
|
{
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
|
|
//
|
|
// Ok, now we'll process this list several times, so we get entries
|
|
// in the following order:
|
|
//
|
|
// ACCESS_DENIED_ACE on the object
|
|
// ACCESS_DENIED_OBJECT_ACE
|
|
// ACCESS_ALLOWED_ACE on the object
|
|
// ACCESS_ALLOWED_OBJECT_ACE on an object
|
|
// ACCESS_ALLOWED_OBJECT_ACE on a property set
|
|
// ACCESS_ALLOWED_OBJECT_ACE on a property
|
|
//
|
|
|
|
//
|
|
// List of entry attributes we're looking for
|
|
//
|
|
ULONG EntryAttribs[] = {ACCLIST_DENIED,
|
|
ACCLIST_OBJ_DENIED,
|
|
ACCLIST_ALLOWED,
|
|
ACCLIST_OBJ_ALLOWED,
|
|
ACCLIST_PSET_ALLOWED,
|
|
ACCLIST_PROP_ALLOWED,
|
|
0}; // Cover anything out of place...
|
|
|
|
//
|
|
// Process all of the items
|
|
//
|
|
|
|
*pfProtected = FALSE;
|
|
//
|
|
// We'll process the list of compressed entries each time, looking for
|
|
// entries from a different level (base, then inherited, then grandparent
|
|
// inherited
|
|
//
|
|
ULONG InheritAttribs[] = {0,
|
|
INHERITED_PARENT,
|
|
INHERITED_GRANDPARENT};
|
|
|
|
for(ULONG iInherit = 0;
|
|
iInherit < sizeof(InheritAttribs) / sizeof(ULONG) && dwErr == ERROR_SUCCESS;
|
|
iInherit++)
|
|
{
|
|
for(ULONG iEntry = 0;
|
|
iEntry < sizeof(EntryAttribs) / sizeof(ULONG) && dwErr == ERROR_SUCCESS;
|
|
iEntry++)
|
|
{
|
|
for(ULONG i = 0; i < cItems && dwErr == ERROR_SUCCESS; i++)
|
|
{
|
|
LPGUID pObjectId = NULL;
|
|
if(pList[i].pONode->pwszProperty != NULL)
|
|
{
|
|
dwErr = AccctrlLookupGuid(_pLDAP,
|
|
_pwszDsPathReference,
|
|
pList[i].pONode->pwszProperty,
|
|
FALSE,
|
|
&pObjectId);
|
|
|
|
}
|
|
|
|
//
|
|
// Process the items in the lists that match our criteria...
|
|
//
|
|
for(ULONG j = pIList[i];
|
|
j < pList[i].cExp + pList[i].cL1Inherit +
|
|
pList[i].cL2Inherit &&
|
|
dwErr == ERROR_SUCCESS;
|
|
j++)
|
|
{
|
|
if((FLAG_ON(pList[i].pList[j].Inheritance,
|
|
InheritAttribs[iInherit]) ||
|
|
InheritAttribs[iInherit] == 0 &&
|
|
!FLAG_ON(pList[i].pList[j].Inheritance,
|
|
INHERITED_PARENT | INHERITED_GRANDPARENT)) &&
|
|
(FLAG_ON(pList[i].pList[j].fAccessFlags,
|
|
EntryAttribs[iEntry]) ||
|
|
EntryAttribs[iEntry] == 0))
|
|
{
|
|
//
|
|
// Ok, we can add this in
|
|
//
|
|
dwErr = InsertEntryInAcl(&(pList[i].pList[j]),
|
|
pObjectId,
|
|
pAcl);
|
|
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
pIList[i] = j;
|
|
|
|
//
|
|
// See if it's protected
|
|
//
|
|
if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION) &&
|
|
FLAG_ON(pList[i].pONode->fState, ACCLIST_DACL_PROTECTED))
|
|
{
|
|
*pfProtected = TRUE;
|
|
}
|
|
|
|
if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION) &&
|
|
FLAG_ON(pList[i].pONode->fState, ACCLIST_SACL_PROTECTED))
|
|
{
|
|
*pfProtected = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
AccFree(pIList);
|
|
|
|
acDebugOut((DEB_TRACE_ACC,"Out CAccessList::BuildAcl: %lu\n",
|
|
dwErr));
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CAccessList::InsertEntryInAcl, private
|
|
//
|
|
// Synopsis: Inserts an access entry into the acl
|
|
//
|
|
// Arguments: [pAE] -- Access entry to insert
|
|
// [pObject] -- If present, this is an object type ace
|
|
// [pAcl] -- Acl to do the insertion for
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_INVALID_ACL A compound ace type was specified
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD CAccessList::InsertEntryInAcl(IN PACTRL_ACCESS_ENTRY pAE,
|
|
IN GUID *pObject,
|
|
IN PACL pAcl)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
LPGUID pInheritId = NULL;
|
|
BOOL fIsObjectAce = FALSE;
|
|
BOOL fIsSacl = FALSE;
|
|
|
|
if(pAE->lpInheritProperty != NULL)
|
|
{
|
|
dwErr = AccctrlLookupGuid(_pLDAP,
|
|
_pwszDsPathReference,
|
|
pAE->lpInheritProperty,
|
|
FALSE,
|
|
&pInheritId);
|
|
fIsObjectAce = TRUE;
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
return(dwErr);
|
|
}
|
|
}
|
|
|
|
if(pObject != NULL)
|
|
{
|
|
fIsObjectAce = TRUE;
|
|
}
|
|
|
|
//
|
|
// First, get the trustee
|
|
//
|
|
PTRUSTEE_NODE pTN;
|
|
dwErr = GetTrusteeNode(&(pAE->Trustee),
|
|
TRUSTEE_OPT_SID,
|
|
&pTN);
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
return(dwErr);
|
|
}
|
|
|
|
//
|
|
// Add the ace
|
|
//
|
|
ACCESS_MASK AM = AccessMaskForAccessEntry(pAE, _ObjType);
|
|
ACCESS_RIGHTS fAccess = pAE->fAccessFlags & ~ACCLIST_VALID_TYPE_FLAGS;
|
|
INHERIT_FLAGS Inherit = pAE->Inheritance & ~ACCLIST_VALID_IN_LEVEL_FLAGS;
|
|
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(pTN->pImpersonate == NULL)
|
|
{
|
|
if(fAccess == ACTRL_ACCESS_ALLOWED)
|
|
{
|
|
if(fIsObjectAce == TRUE)
|
|
{
|
|
if(AddAccessAllowedObjectAce(
|
|
pAcl,
|
|
ACL_REVISION4,
|
|
Inherit,
|
|
AM,
|
|
pObject,
|
|
pInheritId,
|
|
pTN->pSid) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if(AddAccessAllowedAceEx(
|
|
pAcl,
|
|
ACL_REVISION2,
|
|
Inherit,
|
|
AM,
|
|
pTN->pSid) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
else if(fAccess == ACTRL_ACCESS_DENIED)
|
|
{
|
|
if(fIsObjectAce == TRUE)
|
|
{
|
|
if(AddAccessDeniedObjectAce(
|
|
pAcl,
|
|
ACL_REVISION4,
|
|
Inherit,
|
|
AM,
|
|
pObject,
|
|
pInheritId,
|
|
pTN->pSid) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if(AddAccessDeniedAceEx(
|
|
pAcl,
|
|
ACL_REVISION2,
|
|
Inherit,
|
|
AM,
|
|
pTN->pSid) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
else if(FLAG_ON(fAccess,
|
|
(ACTRL_AUDIT_SUCCESS |
|
|
ACTRL_AUDIT_FAILURE)))
|
|
{
|
|
fIsSacl = TRUE;
|
|
if(fIsObjectAce == TRUE)
|
|
{
|
|
if(AddAuditAccessObjectAce(
|
|
pAcl,
|
|
ACL_REVISION4,
|
|
Inherit,
|
|
AM,
|
|
pObject,
|
|
pInheritId,
|
|
pTN->pSid,
|
|
FLAG_ON(fAccess,
|
|
ACTRL_AUDIT_SUCCESS),
|
|
FLAG_ON(fAccess,
|
|
ACTRL_AUDIT_FAILURE)) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if(AddAuditAccessAceEx(
|
|
pAcl,
|
|
ACL_REVISION2,
|
|
Inherit,
|
|
AM,
|
|
pTN->pSid,
|
|
(BOOL)FLAG_ON(fAccess,
|
|
ACTRL_AUDIT_SUCCESS),
|
|
(BOOL)FLAG_ON(fAccess,
|
|
ACTRL_AUDIT_FAILURE)) == FALSE)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_INVALID_ACL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
if(pAE->fAccessFlags == ACTRL_ACCESS_ALLOWED)
|
|
{
|
|
NTSTATUS Status;
|
|
if(pANList[j].pNode->pwszProperty != NULL)
|
|
{
|
|
dwErr = ERROR_INVALID_ACL;
|
|
}
|
|
else
|
|
{
|
|
Status = RtlAddCompoundAce(
|
|
pAcl,
|
|
ACL_REVISION3,
|
|
ACCESS_ALLOWED_COMPOUND_ACE_TYPE,
|
|
AM,
|
|
pTN->pSid,
|
|
pTN->pImpersonate->pSid);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_INVALID_ACL;
|
|
}
|
|
#endif
|
|
//
|
|
// Compound aces are disabled for the PDC
|
|
//
|
|
dwErr = ERROR_INVALID_ACL;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Add in our protected flag...
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
ULONG fFlags = fIsSacl == FALSE ?
|
|
_fDAclFlags :
|
|
_fSAclFlags;
|
|
if(FLAG_ON(fFlags,ACTRL_ACCESS_PROTECTED))
|
|
{
|
|
pAcl->Sbz1 |= fIsSacl == FALSE ?
|
|
SE_DACL_PROTECTED :
|
|
SE_SACL_PROTECTED;
|
|
}
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|