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