//+------------------------------------------------------------------- // // 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 #pragma hdrstop #include #include #include //+--------------------------------------------------------------------------- // // 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); }