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