1081 lines
22 KiB
C++
1081 lines
22 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995
|
|
//
|
|
// File: cAccessControlList.cxx
|
|
//
|
|
// Contents: AccessControlList object
|
|
//
|
|
// History: 11-1-95 krishnag Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "oleds.hxx"
|
|
#pragma hdrstop
|
|
|
|
// Class CAccessControlList
|
|
|
|
DEFINE_IDispatch_Implementation(CAccessControlList)
|
|
|
|
CAccessControlList::CAccessControlList():
|
|
_pDispMgr(NULL),
|
|
_dwAclRevision(0),
|
|
_dwAceCount(0),
|
|
_pAccessControlEntry(NULL),
|
|
_pCurrentEntry(NULL),
|
|
_pACLEnums(NULL)
|
|
{
|
|
ENLIST_TRACKING(CAccessControlList);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CAccessControlList::CreateAccessControlList(
|
|
REFIID riid,
|
|
void **ppvObj
|
|
)
|
|
{
|
|
CAccessControlList FAR * pAccessControlList = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = AllocateAccessControlListObject(&pAccessControlList);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pAccessControlList->QueryInterface(riid, ppvObj);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pAccessControlList->Release();
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
delete pAccessControlList;
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
}
|
|
|
|
|
|
CAccessControlList::~CAccessControlList( )
|
|
{
|
|
PACCESS_CONTROL_ENTRY pTemp = NULL;
|
|
PACCESS_CONTROL_ENTRY pNext = NULL;
|
|
|
|
PACL_ENUM_ENTRY pACL = _pACLEnums;
|
|
|
|
|
|
delete _pDispMgr;
|
|
|
|
pTemp = _pAccessControlEntry;
|
|
|
|
while (pTemp) {
|
|
|
|
pNext = pTemp->pNext;
|
|
|
|
if (pTemp->pAccessControlEntry) {
|
|
|
|
(pTemp->pAccessControlEntry)->Release();
|
|
}
|
|
FreeADsMem(pTemp);
|
|
pTemp = pNext;
|
|
}
|
|
|
|
|
|
//
|
|
// since each enumerator hold ref count on this ACL, this destructor should
|
|
// never be called unless all of its enumerators' destructors have been
|
|
// invoked. In the enumerator's destructor, RemoveEnumerator is called
|
|
// first before release ref count on this. Thus, by the time, at this
|
|
// point, pACL should be empty.
|
|
//
|
|
|
|
ADsAssert(!pACL);
|
|
|
|
//
|
|
// just in case we have bug in codes, e.g enumerators not all destroyed
|
|
// before dll detachement. don't want to leak here anyway
|
|
//
|
|
|
|
while (pACL) {
|
|
|
|
_pACLEnums = pACL->pNext;
|
|
|
|
//
|
|
// free the entry but do not destroy the enumerator since clients
|
|
// should release all interface ptrs to enumerator for destruction.
|
|
//
|
|
|
|
FreeADsMem(pACL);
|
|
pACL = _pACLEnums;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::QueryInterface(
|
|
REFIID iid,
|
|
LPVOID FAR* ppv
|
|
)
|
|
{
|
|
if (IsEqualIID(iid, IID_IUnknown))
|
|
{
|
|
*ppv = (IADsAccessControlList FAR *) this;
|
|
}
|
|
else if (IsEqualIID(iid, IID_IADsAccessControlList))
|
|
{
|
|
*ppv = (IADsAccessControlList FAR *) this;
|
|
}
|
|
else if (IsEqualIID(iid, IID_IDispatch))
|
|
{
|
|
*ppv = (IADsAccessControlList FAR *) this;
|
|
}
|
|
else if (IsEqualIID(iid, IID_ISupportErrorInfo))
|
|
{
|
|
*ppv = (ISupportErrorInfo FAR *) this;
|
|
}
|
|
else if (IsEqualIID(iid, IID_IEnumVARIANT))
|
|
{
|
|
|
|
*ppv = (IEnumVARIANT FAR *) this;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT
|
|
CAccessControlList::AllocateAccessControlListObject(
|
|
CAccessControlList ** ppAccessControlList
|
|
)
|
|
{
|
|
CAccessControlList FAR * pAccessControlList = NULL;
|
|
CDispatchMgr FAR * pDispMgr = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
pAccessControlList = new CAccessControlList();
|
|
if (pAccessControlList == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pDispMgr = new CDispatchMgr;
|
|
if (pDispMgr == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = LoadTypeInfoEntry(
|
|
pDispMgr,
|
|
LIBID_ADs,
|
|
IID_IADsAccessControlList,
|
|
(IADsAccessControlList *)pAccessControlList,
|
|
DISPID_NEWENUM
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pAccessControlList->_pDispMgr = pDispMgr;
|
|
*ppAccessControlList = pAccessControlList;
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
delete pDispMgr;
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
}
|
|
|
|
//
|
|
// ISupportErrorInfo method
|
|
//
|
|
STDMETHODIMP
|
|
CAccessControlList::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
|
|
{
|
|
if (IsEqualIID(riid, IID_IADsAccessControlList) ||
|
|
IsEqualIID(riid, IID_IEnumVARIANT)) {
|
|
return S_OK;
|
|
} else {
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::CopyAccessList(
|
|
THIS_ IDispatch FAR * FAR * ppAccessControlList
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwAceCount = 0;
|
|
DWORD dwNewAceCount = 0;
|
|
DWORD dwAclRevision = 0;
|
|
DWORD i = 0;
|
|
VARIANT varAce;
|
|
IADsAccessControlEntry * pSourceAce = NULL;
|
|
IADsAccessControlEntry * pTargetAce = NULL;
|
|
IDispatch * pTargDisp = NULL;
|
|
DWORD cElementFetched = 0;
|
|
IADsAccessControlList * pAccessControlList = NULL;
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_AccessControlList,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IADsAccessControlList,
|
|
(void **)&pAccessControlList
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwAceCount = _dwAceCount;
|
|
dwAclRevision = _dwAclRevision;
|
|
|
|
//
|
|
// Reset the enumerator
|
|
//
|
|
|
|
_pCurrentEntry = _pAccessControlEntry;
|
|
|
|
for (i = 0; i < dwAceCount; i++) {
|
|
|
|
VariantInit(&varAce);
|
|
hr = Next(1, &varAce, &cElementFetched);
|
|
CONTINUE_ON_FAILURE(hr);
|
|
|
|
hr = (V_DISPATCH(&varAce))->QueryInterface(
|
|
IID_IADsAccessControlEntry,
|
|
(void **)&pSourceAce
|
|
);
|
|
CONTINUE_ON_FAILURE(hr);
|
|
|
|
hr = CopyAccessControlEntry(
|
|
pSourceAce,
|
|
&pTargetAce
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pTargetAce->QueryInterface(
|
|
IID_IDispatch,
|
|
(void **)&pTargDisp
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pAccessControlList->AddAce(pTargDisp);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
dwNewAceCount++;
|
|
|
|
if (pTargDisp) {
|
|
pTargDisp->Release();
|
|
pTargDisp = NULL;
|
|
}
|
|
|
|
if (pTargetAce) {
|
|
pTargetAce->Release();
|
|
pTargetAce = NULL;
|
|
}
|
|
|
|
if (pSourceAce) {
|
|
pSourceAce->Release();
|
|
pSourceAce = NULL;
|
|
}
|
|
|
|
VariantClear(&varAce);
|
|
}
|
|
|
|
hr= pAccessControlList->put_AceCount(dwNewAceCount);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pAccessControlList->put_AclRevision((long)dwAclRevision);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
*ppAccessControlList = pAccessControlList;
|
|
|
|
error:
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::AddAce(
|
|
THIS_ IDispatch FAR * pAccessControlEntry
|
|
)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
PACCESS_CONTROL_ENTRY pAccessEntry = NULL;
|
|
PACCESS_CONTROL_ENTRY pTemp = NULL;
|
|
IADsAccessControlEntry * pAce = NULL;
|
|
|
|
hr = pAccessControlEntry->QueryInterface(
|
|
IID_IADsAccessControlEntry,
|
|
(void **)&pAce
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pAccessEntry = (PACCESS_CONTROL_ENTRY)AllocADsMem(
|
|
sizeof(ACCESS_CONTROL_ENTRY)
|
|
);
|
|
if (!pAccessEntry) {
|
|
|
|
pAce->Release();
|
|
RRETURN(E_OUTOFMEMORY);
|
|
}
|
|
|
|
pAccessEntry->pAccessControlEntry = pAce;
|
|
|
|
//
|
|
// - Now append this ace to the very end.
|
|
// - Since ACE is added to the end, no need to call
|
|
// AdjustCurPtrOfEnumerators().
|
|
//
|
|
|
|
if (!_pAccessControlEntry) {
|
|
|
|
_pAccessControlEntry = pAccessEntry;
|
|
|
|
}else {
|
|
|
|
pTemp = _pAccessControlEntry;
|
|
|
|
while (pTemp->pNext) {
|
|
|
|
pTemp = pTemp->pNext;
|
|
}
|
|
|
|
pTemp->pNext = pAccessEntry;
|
|
|
|
}
|
|
|
|
//
|
|
// Now up the ace count
|
|
//
|
|
|
|
_dwAceCount++;
|
|
|
|
error:
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::RemoveAce(
|
|
THIS_ IDispatch FAR * pAccessControlEntry
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PACCESS_CONTROL_ENTRY pTemp = NULL;
|
|
IADsAccessControlEntry * pAce = NULL;
|
|
PACCESS_CONTROL_ENTRY pAccessEntry = NULL;
|
|
DWORD dwRemovePos = 1; // one-based indexing since enumerator was
|
|
// written that way
|
|
|
|
if (!_pAccessControlEntry) {
|
|
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
|
|
hr = pAccessControlEntry->QueryInterface(
|
|
IID_IADsAccessControlEntry,
|
|
(void **)&pAce
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
pAccessEntry = _pAccessControlEntry;
|
|
|
|
|
|
//
|
|
// It is the first entry
|
|
//
|
|
|
|
|
|
if (EquivalentAces(pAccessEntry->pAccessControlEntry, pAce)) {
|
|
|
|
//
|
|
// Check if we have an enumerator pointed to us
|
|
//
|
|
|
|
if (pAccessEntry == _pCurrentEntry) {
|
|
|
|
_pCurrentEntry = pAccessEntry->pNext;
|
|
}
|
|
|
|
_pAccessControlEntry = pAccessEntry->pNext;
|
|
|
|
(pAccessEntry->pAccessControlEntry)->Release();
|
|
|
|
FreeADsMem(pAccessEntry);
|
|
|
|
|
|
if (pAce) {
|
|
pAce->Release();
|
|
}
|
|
|
|
//
|
|
// Decrement the Ace count
|
|
//
|
|
|
|
_dwAceCount--;
|
|
|
|
//
|
|
// Adjust "current" ptr of all enumerators if necessary
|
|
//
|
|
|
|
AdjustCurPtrOfEnumerators(dwRemovePos, FALSE);
|
|
|
|
RRETURN(S_OK);
|
|
|
|
}
|
|
|
|
while (pAccessEntry->pNext) {
|
|
|
|
pTemp = pAccessEntry->pNext;
|
|
dwRemovePos++;
|
|
|
|
if (EquivalentAces(pTemp->pAccessControlEntry, pAce)){
|
|
|
|
//
|
|
// Check if we have an enumerator pointed to us
|
|
//
|
|
|
|
if (pAccessEntry == _pCurrentEntry) {
|
|
|
|
_pCurrentEntry = pAccessEntry->pNext;
|
|
}
|
|
|
|
pAccessEntry->pNext = pTemp->pNext;
|
|
|
|
(pTemp->pAccessControlEntry)->Release();
|
|
|
|
FreeADsMem(pTemp);
|
|
|
|
if (pAce) {
|
|
pAce->Release();
|
|
}
|
|
|
|
//
|
|
// Decrement the Ace count
|
|
//
|
|
|
|
_dwAceCount--;
|
|
|
|
//
|
|
// Adjust "current" ptr of all enumerators if necessary
|
|
//
|
|
|
|
AdjustCurPtrOfEnumerators(dwRemovePos, FALSE);
|
|
|
|
|
|
RRETURN(S_OK);
|
|
|
|
}
|
|
|
|
pAccessEntry = pAccessEntry->pNext;
|
|
}
|
|
|
|
|
|
if (pAce) {
|
|
pAce->Release();
|
|
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN_EXP_IF_ERR(E_FAIL);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::get_AclRevision(THIS_ long FAR * retval)
|
|
{
|
|
|
|
*retval = _dwAclRevision;
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::put_AclRevision(THIS_ long lnAclRevision)
|
|
{
|
|
|
|
_dwAclRevision = lnAclRevision;
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::get_AceCount(THIS_ long FAR * retval)
|
|
{
|
|
|
|
*retval = _dwAceCount;
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::put_AceCount(THIS_ long lnAceCount)
|
|
{
|
|
|
|
_dwAceCount = lnAceCount;
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::Next(ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched)
|
|
{
|
|
DWORD i = 0;
|
|
DWORD j = 0;
|
|
IDispatch * pDispatch = NULL;
|
|
IADsAccessControlEntry * pAccessControlEntry = NULL;
|
|
PACCESS_CONTROL_ENTRY pTemp = NULL;
|
|
PVARIANT pThisVar;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
pTemp = _pCurrentEntry;
|
|
|
|
if (!pTemp) {
|
|
if (pcElementFetched) {
|
|
*pcElementFetched = 0;
|
|
}
|
|
|
|
RRETURN(S_FALSE);
|
|
}
|
|
|
|
|
|
while (pTemp && (j < cElements)){
|
|
|
|
pThisVar = pvar + j;
|
|
VariantInit(pThisVar);
|
|
|
|
pAccessControlEntry = pTemp->pAccessControlEntry;
|
|
|
|
hr = pAccessControlEntry->QueryInterface(
|
|
IID_IDispatch,
|
|
(void **)&pDispatch
|
|
);
|
|
|
|
V_DISPATCH(pThisVar) = pDispatch;
|
|
V_VT(pThisVar) = VT_DISPATCH;
|
|
|
|
pTemp = pTemp->pNext;
|
|
j++;
|
|
}
|
|
|
|
if (pcElementFetched) {
|
|
*pcElementFetched = j;
|
|
}
|
|
|
|
//
|
|
// Advance _pCurrentEntry
|
|
//
|
|
|
|
|
|
_pCurrentEntry = pTemp;
|
|
|
|
if (j < cElements) {
|
|
RRETURN (S_FALSE);
|
|
}
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CAccessControlList::GetElement
|
|
//
|
|
// Synopsis: Get the dwPos'th ACE in the ACL. Note that no
|
|
// refCount is added to the ACE, it is the responsibility
|
|
// of the caller to handle that.
|
|
//
|
|
// Arguments: [dwPos] the ACE required
|
|
// [pAce] Pointer to ACE returned in this param.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Modifies: [pAce]
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
CAccessControlList::GetElement(
|
|
DWORD dwPos,
|
|
IADsAccessControlEntry ** pAce
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD j = 1;
|
|
PACCESS_CONTROL_ENTRY pTemp = NULL;
|
|
|
|
*pAce = NULL;
|
|
// set to the acl head
|
|
pTemp = _pAccessControlEntry;
|
|
|
|
if (_dwAceCount < dwPos) {
|
|
BAIL_ON_FAILURE(hr = E_FAIL);
|
|
}
|
|
|
|
while (pTemp && (j < dwPos)) {
|
|
pTemp = pTemp->pNext;
|
|
j++;
|
|
}
|
|
|
|
if (!pTemp || pTemp == NULL) {
|
|
BAIL_ON_FAILURE(hr = E_FAIL);
|
|
}
|
|
|
|
// we should have the correct ACE here
|
|
*pAce = pTemp->pAccessControlEntry;
|
|
|
|
error:
|
|
if (FAILED(hr)) {
|
|
hr = S_FALSE;
|
|
}
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CAccessControlList::get__NewEnum(THIS_ IUnknown * FAR* retval)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IEnumVARIANT * penum = NULL;
|
|
|
|
*retval = NULL;
|
|
|
|
hr = CAccCtrlListEnum::CreateAclEnum(
|
|
(CAccCtrlListEnum **)&penum,
|
|
this
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = penum->QueryInterface(
|
|
IID_IUnknown,
|
|
(VOID FAR* FAR*)retval
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (penum) {
|
|
penum->Release();
|
|
}
|
|
|
|
//
|
|
// keep a linked list of all enumerators that enumerate on this ACL
|
|
// But don't hold on to inteface ptr of enumerators; otherwise, cycle
|
|
// reference count. Do this only after above succeed.
|
|
//
|
|
|
|
hr = AddEnumerator(
|
|
(CAccCtrlListEnum *)penum
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (FAILED(hr) && penum) {
|
|
delete penum;
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CAccessControlList::
|
|
AddEnumerator(
|
|
CAccCtrlListEnum *pACLEnum
|
|
)
|
|
{
|
|
PACL_ENUM_ENTRY pNewACLEnum = NULL;
|
|
|
|
//
|
|
// don't want add NULL enumerator as an entry to add complication everywhere
|
|
//
|
|
|
|
ADsAssert(pACLEnum);
|
|
|
|
|
|
pNewACLEnum = (PACL_ENUM_ENTRY) AllocADsMem(sizeof(ACL_ENUM_ENTRY));
|
|
|
|
if (!pNewACLEnum)
|
|
RRETURN(E_OUTOFMEMORY);
|
|
|
|
//
|
|
// We are only adding a ptr to the enumerator.
|
|
// Don't hold on to inteface ptr. Otherwise, this has ref count on
|
|
// enumerator has ref count on this. Cycle reference count.
|
|
//
|
|
|
|
pNewACLEnum->pACLEnum = pACLEnum;
|
|
|
|
pNewACLEnum->pNext = _pACLEnums;
|
|
_pACLEnums = pNewACLEnum;
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
HRESULT
|
|
CAccessControlList::
|
|
RemoveEnumerator(
|
|
CAccCtrlListEnum *pACLEnum
|
|
)
|
|
{
|
|
PACL_ENUM_ENTRY pCurACLEnum = _pACLEnums;
|
|
PACL_ENUM_ENTRY pPrevACLEnum = NULL;
|
|
|
|
//
|
|
// can't think of a case needing to remove a pACLEnum which may be
|
|
// NULL now. Don't want to add complication. Probably coding error.
|
|
//
|
|
|
|
ADsAssert(pACLEnum);
|
|
|
|
|
|
//
|
|
// optional, but we really shouldn't call this if _pACLEnums is NULL
|
|
//
|
|
|
|
ADsAssert(_pACLEnums);
|
|
|
|
|
|
//
|
|
// check the first enumerator
|
|
//
|
|
|
|
if (pCurACLEnum) {
|
|
|
|
//
|
|
// match what we want to remove
|
|
//
|
|
|
|
if (pCurACLEnum->pACLEnum == pACLEnum) {
|
|
|
|
//
|
|
// remove the enumerator from our list but don't destroy
|
|
// the enumerator
|
|
//
|
|
|
|
_pACLEnums = pCurACLEnum->pNext;
|
|
FreeADsMem(pCurACLEnum);
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
} else {
|
|
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
|
|
//
|
|
// start checking from the second element, if any, of the list
|
|
//
|
|
|
|
pPrevACLEnum = pCurACLEnum;
|
|
pCurACLEnum = pCurACLEnum->pNext;
|
|
|
|
while (pCurACLEnum && (pCurACLEnum->pACLEnum!=pACLEnum)) {
|
|
|
|
pPrevACLEnum = pCurACLEnum;
|
|
pCurACLEnum = pCurACLEnum->pNext;
|
|
}
|
|
|
|
|
|
if (pCurACLEnum) {
|
|
|
|
//
|
|
// match found
|
|
//
|
|
|
|
pPrevACLEnum->pNext = pCurACLEnum->pNext;
|
|
FreeADsMem(pCurACLEnum);
|
|
|
|
RRETURN(S_OK);
|
|
|
|
} else {
|
|
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
EquivalentStrings(
|
|
BSTR bstrSrcString,
|
|
BSTR bstrDestString
|
|
)
|
|
{
|
|
if (!bstrSrcString && !bstrDestString) {
|
|
return(TRUE);
|
|
}
|
|
if (!bstrSrcString && bstrDestString) {
|
|
return(FALSE);
|
|
}
|
|
if (!bstrDestString && bstrSrcString) {
|
|
return(FALSE);
|
|
}
|
|
#ifdef WIN95
|
|
if (!_wcsicmp(bstrSrcString, bstrDestString)) {
|
|
#else
|
|
if (CompareStringW(
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
NORM_IGNORECASE,
|
|
bstrSrcString,
|
|
-1,
|
|
bstrDestString,
|
|
-1
|
|
)
|
|
== CSTR_EQUAL) {
|
|
#endif
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
EquivalentAces(
|
|
IADsAccessControlEntry * pSourceAce,
|
|
IADsAccessControlEntry * pDestAce
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
BSTR bstrSrcTrustee = NULL;
|
|
BSTR bstrDestTrustee = NULL;
|
|
|
|
DWORD dwSrcMask = 0;
|
|
DWORD dwDestMask = 0;
|
|
|
|
DWORD dwSrcAceFlags = 0;
|
|
DWORD dwDestAceFlags = 0;
|
|
|
|
DWORD dwSrcAceType = 0;
|
|
DWORD dwDestAceType = 0;
|
|
|
|
DWORD dwSrcFlags = 0;
|
|
DWORD dwDestFlags = 0;
|
|
|
|
BSTR bstrSrcObjectType = NULL;
|
|
BSTR bstrDestObjectType = NULL;
|
|
|
|
BSTR bstrSrcInherObjType = NULL;
|
|
BSTR bstrDestInherObjType = NULL;
|
|
|
|
BOOL dwRet = FALSE;
|
|
|
|
hr = pSourceAce->get_Trustee(&bstrSrcTrustee);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pDestAce->get_Trustee(&bstrDestTrustee);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (!EquivalentStrings(bstrSrcTrustee, bstrDestTrustee)) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = pSourceAce->get_AccessMask((long *)&dwSrcMask);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pDestAce->get_AccessMask((long *)&dwDestMask);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (dwSrcMask != dwDestMask) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = pSourceAce->get_AceFlags((long *)&dwSrcAceFlags);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pDestAce->get_AceFlags((long *)&dwDestAceFlags);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (dwSrcAceFlags != dwDestAceFlags) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
hr = pSourceAce->get_AceType((long *)&dwSrcAceType);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pDestAce->get_AceType((long *)&dwDestAceType);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (dwSrcAceType != dwDestAceType) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
hr = pSourceAce->get_Flags((long *)&dwSrcFlags);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pDestAce->get_Flags((long *)&dwDestFlags);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (dwSrcFlags != dwDestFlags) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
hr = pSourceAce->get_ObjectType(&bstrSrcObjectType);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pDestAce->get_ObjectType(&bstrDestObjectType);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (!EquivalentStrings(bstrSrcObjectType, bstrDestObjectType)) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
|
|
hr = pSourceAce->get_InheritedObjectType(&bstrSrcInherObjType);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = pDestAce->get_InheritedObjectType(&bstrDestInherObjType);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (!EquivalentStrings(bstrSrcInherObjType, bstrDestInherObjType)) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
dwRet = TRUE;
|
|
|
|
cleanup:
|
|
|
|
if (bstrSrcTrustee) {
|
|
ADsFreeString(bstrSrcTrustee);
|
|
}
|
|
|
|
if (bstrDestTrustee) {
|
|
ADsFreeString(bstrDestTrustee);
|
|
}
|
|
|
|
if (bstrSrcObjectType) {
|
|
ADsFreeString(bstrSrcObjectType);
|
|
}
|
|
|
|
if (bstrDestObjectType) {
|
|
ADsFreeString(bstrDestObjectType);
|
|
}
|
|
|
|
if (bstrSrcInherObjType) {
|
|
ADsFreeString(bstrSrcInherObjType);
|
|
}
|
|
|
|
if (bstrDestInherObjType) {
|
|
ADsFreeString(bstrDestInherObjType);
|
|
}
|
|
|
|
return(dwRet);
|
|
|
|
error:
|
|
|
|
dwRet = FALSE;
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
void
|
|
CAccessControlList::
|
|
AdjustCurPtrOfEnumerators(
|
|
DWORD dwPosNewOrDeletedACE,
|
|
BOOL fACEAdded
|
|
)
|
|
{
|
|
PACL_ENUM_ENTRY pACLEnum = _pACLEnums;
|
|
CAccCtrlListEnum * pEnum = NULL;
|
|
BOOL fOk = FALSE;
|
|
|
|
|
|
if (fACEAdded) {
|
|
|
|
while (pACLEnum) {
|
|
|
|
pEnum = pACLEnum->pACLEnum;
|
|
ADsAssert(pEnum);
|
|
|
|
//
|
|
// NOTE: - Problem may occur in multithreaded model (manipulation
|
|
// on the enumerator & the actual ACL in two threads).
|
|
// - ADSI CLIENTS should use critical section protection, as
|
|
// with property cache.
|
|
//
|
|
|
|
if (dwPosNewOrDeletedACE <= pEnum->GetCurElement()) {
|
|
//
|
|
// the new ACE is added in front of the last ACE enumerated
|
|
// so, increment the position of the last enumerated element
|
|
// by one
|
|
|
|
fOk = pEnum->IncrementCurElement();
|
|
|
|
ADsAssert(fOk); // should be within bound after increment;
|
|
// otherwise, coding error
|
|
}
|
|
|
|
// else {
|
|
|
|
//
|
|
// the new ACE is added after the last ACE enumerated, so
|
|
// no effect on the position of the last enumerated element
|
|
//
|
|
// }
|
|
|
|
pACLEnum=pACLEnum->pNext;
|
|
}
|
|
|
|
} else { // ACE deleted
|
|
|
|
while (pACLEnum) {
|
|
|
|
pEnum = pACLEnum->pACLEnum;
|
|
ADsAssert(pEnum);
|
|
|
|
//
|
|
// NOTE: - Problem may occur in multithreaded model (manipulation
|
|
// on the enumerator & the actual ACL in two threads).
|
|
// - ADSI CLIENTS should use critical section protection,
|
|
// as with property cache.
|
|
//
|
|
|
|
if ( dwPosNewOrDeletedACE <= pEnum->GetCurElement() ) {
|
|
|
|
//
|
|
// the ACE deleted is in front of, or is, the last ACE
|
|
// enumerated, so decrement the position of the last
|
|
// enumerated element by one
|
|
|
|
fOk = pEnum->DecrementCurElement();
|
|
|
|
ADsAssert(fOk); // should be within bound after decrement;
|
|
// otherwise, coding error
|
|
}
|
|
|
|
// else {
|
|
|
|
//
|
|
// the new ACE deleted is after the last ACE enumerated, so
|
|
// no effect on the position of the last enumerated element
|
|
//
|
|
// }
|
|
|
|
pACLEnum=pACLEnum->pNext;
|
|
}
|
|
}
|
|
}
|
|
|