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

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);
}