2819 lines
64 KiB
C++
2819 lines
64 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
|
//
|
|
// File: cprops.cxx
|
|
//
|
|
// Contents: Property Cache functionality for LDAP
|
|
//
|
|
// Functions:
|
|
// CPropertyCache::addproperty
|
|
// CPropertyCache::updateproperty
|
|
// CPropertyCache::findproperty
|
|
// CPropertyCache::getproperty
|
|
// CPropertyCache::putproperty
|
|
// CProperyCache::CPropertyCache
|
|
// CPropertyCache::~CPropertyCache
|
|
// CPropertyCache::createpropertycache
|
|
//
|
|
// History: 15-Jun-96 yihsins Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include "ldap.hxx"
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::addproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] --
|
|
// [vt] --
|
|
// [vaData] --
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
addproperty(
|
|
LPWSTR szPropertyName
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PPROPERTY pNewProperty = NULL;
|
|
LPWSTR tempString1 = NULL;
|
|
LPWSTR tempString2 = NULL;
|
|
|
|
PPROPERTY pNewProperties = NULL;
|
|
|
|
PDISPPROPERTY pDispNewProperty = NULL;
|
|
PDISPPROPERTY pDispNewProperties = NULL;
|
|
DWORD dwDispLoc = 0;
|
|
|
|
|
|
//
|
|
// Allocate the string first
|
|
//
|
|
tempString1 = AllocADsStr(szPropertyName);
|
|
|
|
if (!tempString1)
|
|
BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
|
|
|
|
|
|
//
|
|
// Make a copy for the Dispatch Mgr Table.
|
|
//
|
|
|
|
tempString2 = AllocADsStr(szPropertyName);
|
|
|
|
if (!tempString2)
|
|
BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
|
|
|
|
|
|
//
|
|
// extend the property cache by adding a new property entry
|
|
//
|
|
|
|
pNewProperties = (PPROPERTY)ReallocADsMem(
|
|
_pProperties,
|
|
_cb,
|
|
_cb + sizeof(PROPERTY)
|
|
);
|
|
if (!pNewProperties) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
_pProperties = pNewProperties;
|
|
|
|
pNewProperty = (PPROPERTY)((LPBYTE)_pProperties + _cb);
|
|
|
|
|
|
//
|
|
// Since the memory has already been allocated in tempString
|
|
// just set the value/pointer now.
|
|
//
|
|
pNewProperty->szPropertyName = tempString1;
|
|
|
|
//
|
|
// Update the index
|
|
//
|
|
|
|
_dwMaxProperties++;
|
|
_cb += sizeof(PROPERTY);
|
|
|
|
//
|
|
// extend the property cache by adding a new property entry
|
|
//
|
|
|
|
//
|
|
// Need to check if this property is already there in the
|
|
// dispatch table - otherwise we are going to keep on growing
|
|
// forever - AjayR 7-31-98.
|
|
//
|
|
|
|
hr = DispatchFindProperty(szPropertyName, &dwDispLoc);
|
|
|
|
if (hr == S_OK) {
|
|
// we do not need this string in this case
|
|
if (tempString2) {
|
|
FreeADsStr(tempString2);
|
|
tempString2 = NULL;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// reset the hr otherwise we will return an
|
|
// error incorrectly when there was none.
|
|
//
|
|
hr = S_OK;
|
|
|
|
pDispNewProperties = (PDISPPROPERTY)ReallocADsMem(
|
|
_pDispProperties,
|
|
_cbDisp,
|
|
_cbDisp + sizeof(DISPPROPERTY)
|
|
);
|
|
if (!pDispNewProperties) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
_pDispProperties = pDispNewProperties;
|
|
|
|
pDispNewProperty = (PDISPPROPERTY)((LPBYTE)_pDispProperties + _cbDisp);
|
|
|
|
|
|
//
|
|
// Since the memory has already been allocated in tempString
|
|
// just set the value/pointer now.
|
|
//
|
|
pDispNewProperty->szPropertyName = tempString2;
|
|
|
|
//
|
|
// Update the index
|
|
//
|
|
|
|
_dwDispMaxProperties++;
|
|
_cbDisp += sizeof(DISPPROPERTY);
|
|
|
|
} // else clause - that is property not found in disp
|
|
|
|
RRETURN(hr);
|
|
error:
|
|
|
|
if (tempString1){
|
|
FreeADsStr(tempString1);
|
|
}
|
|
|
|
if (tempString2) {
|
|
FreeADsStr(tempString2);
|
|
}
|
|
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::putpropertyext
|
|
//
|
|
// Synopsis: Similar to put property only unlike update it will add
|
|
// the property to the cahce if it is not already there !
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] --
|
|
// [vaData] --
|
|
//
|
|
// History
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
putpropertyext(
|
|
LPWSTR szPropertyName,
|
|
DWORD dwFlags,
|
|
DWORD dwSyntaxId,
|
|
LDAPOBJECTARRAY ldapObjectArray
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwIndex;
|
|
BOOL fFound = FALSE;
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
|
|
//
|
|
// If the property is not in the cache we need to add it
|
|
// as updateproperty expects it to be in the cache.
|
|
//
|
|
if (hr == E_ADS_PROPERTY_NOT_FOUND) {
|
|
hr = addproperty(
|
|
szPropertyName
|
|
);
|
|
}
|
|
else {
|
|
fFound = TRUE;
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// at this time we can call putproperty
|
|
//
|
|
if (fFound) {
|
|
hr = putproperty(
|
|
dwIndex,
|
|
dwFlags,
|
|
dwSyntaxId,
|
|
ldapObjectArray
|
|
);
|
|
}
|
|
else {
|
|
hr = putproperty(
|
|
szPropertyName,
|
|
dwFlags,
|
|
dwSyntaxId,
|
|
ldapObjectArray
|
|
);
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::updateproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] --
|
|
// [vaData] --
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
updateproperty(
|
|
LPWSTR szPropertyName,
|
|
DWORD dwSyntaxId,
|
|
LDAPOBJECTARRAY ldapObjectArray,
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwIndex;
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
|
|
if (!fExplicit) {
|
|
if ( PROPERTY_FLAGS(pThisProperty) == PROPERTY_UPDATE ) {
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
// Free the old values first
|
|
LdapTypeFreeLdapObjects( &(PROPERTY_LDAPOBJECTARRAY(pThisProperty)));
|
|
|
|
PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
|
|
PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
|
|
|
|
hr = LdapTypeCopyConstruct(
|
|
ldapObjectArray,
|
|
&(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::findproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] --
|
|
// [pdwIndex] --
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
findproperty(
|
|
LPWSTR szPropertyName,
|
|
PDWORD pdwIndex
|
|
)
|
|
{
|
|
DWORD i = 0;
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
for (i = 0; i < _dwMaxProperties; i++) {
|
|
|
|
pThisProperty = _pProperties + i;
|
|
|
|
if (!_wcsicmp(pThisProperty->szPropertyName, szPropertyName)) {
|
|
*pdwIndex = i;
|
|
RRETURN(S_OK);
|
|
}
|
|
}
|
|
|
|
*pdwIndex = 0;
|
|
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
|
|
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::getproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] -- Property to retrieve from the cache
|
|
// [pvaData] -- Data returned in a variant
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
getproperty(
|
|
LPWSTR szPropertyName,
|
|
PDWORD pdwSyntaxId,
|
|
PDWORD pdwStatusFlag,
|
|
LDAPOBJECTARRAY *pLdapObjectArray
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwIndex = 0L;
|
|
|
|
|
|
//
|
|
// retrieve index of property in cache
|
|
//
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
|
|
//
|
|
// if property not already in cache, try get properties from svr
|
|
//
|
|
|
|
//
|
|
// INDEX_EMPTY(???) ???
|
|
//
|
|
|
|
if ((hr == E_ADS_PROPERTY_NOT_FOUND ||
|
|
(INDEX_EMPTY(dwIndex) && !PROP_DELETED(dwIndex))
|
|
) &&
|
|
!_fGetInfoDone)
|
|
{
|
|
BOOL fResult = FindSavingEntry(szPropertyName);
|
|
|
|
if(!fResult) {
|
|
hr = _pCoreADsObject->GetInfo(FALSE);
|
|
|
|
// workaround to avoid confusing callers of getproperty.
|
|
if (hr == E_NOTIMPL) {
|
|
hr = E_ADS_PROPERTY_NOT_FOUND;
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = findproperty(szPropertyName, &dwIndex);
|
|
}
|
|
else {
|
|
hr = E_ADS_PROPERTY_NOT_FOUND;
|
|
}
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// get property based on index in cache
|
|
//
|
|
|
|
hr = unboundgetproperty(
|
|
dwIndex,
|
|
pdwSyntaxId,
|
|
pdwStatusFlag,
|
|
pLdapObjectArray
|
|
);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::putproperty
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
putproperty(
|
|
LPWSTR szPropertyName,
|
|
DWORD dwFlags,
|
|
DWORD dwSyntaxId,
|
|
LDAPOBJECTARRAY ldapObjectArray
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwIndex = 0L;
|
|
|
|
hr = findproperty(szPropertyName, &dwIndex);
|
|
if (SUCCEEDED(hr))
|
|
hr = putproperty(dwIndex, dwFlags, dwSyntaxId, ldapObjectArray);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::putproperty
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
putproperty(
|
|
DWORD dwIndex,
|
|
DWORD dwFlags,
|
|
DWORD dwSyntaxId,
|
|
LDAPOBJECTARRAY ldapObjectArray
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
|
|
// Free the old values first
|
|
LdapTypeFreeLdapObjects( &(PROPERTY_LDAPOBJECTARRAY(pThisProperty)) );
|
|
|
|
PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
|
|
|
|
switch ( dwFlags ) {
|
|
|
|
case PROPERTY_INIT:
|
|
if ( ldapObjectArray.dwCount > 0 )
|
|
{
|
|
hr = LdapTypeCopyConstruct(
|
|
ldapObjectArray,
|
|
&(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
|
|
break;
|
|
|
|
case PROPERTY_DELETE:
|
|
PROPERTY_FLAGS(pThisProperty) = PROPERTY_DELETE;
|
|
break;
|
|
|
|
case PROPERTY_UPDATE:
|
|
if ( ldapObjectArray.dwCount > 0 )
|
|
{
|
|
hr = LdapTypeCopyConstruct(
|
|
ldapObjectArray,
|
|
&(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
PROPERTY_FLAGS(pThisProperty) = ldapObjectArray.dwCount?
|
|
PROPERTY_UPDATE : PROPERTY_DELETE;
|
|
break;
|
|
|
|
|
|
case PROPERTY_DELETE_VALUE:
|
|
if ( ldapObjectArray.dwCount > 0 )
|
|
{
|
|
hr = LdapTypeCopyConstruct(
|
|
ldapObjectArray,
|
|
&(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
PROPERTY_FLAGS(pThisProperty) = PROPERTY_DELETE_VALUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROPERTY_ADD:
|
|
hr = LdapTypeCopyConstruct(
|
|
ldapObjectArray,
|
|
&(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
PROPERTY_FLAGS(pThisProperty) = PROPERTY_ADD;
|
|
break;
|
|
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::CPropertyCache
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
CPropertyCache::
|
|
CPropertyCache():
|
|
_dwMaxProperties(0),
|
|
_pProperties(NULL),
|
|
_cb(0),
|
|
_dwCurrentIndex(0),
|
|
_pCoreADsObject(NULL),
|
|
_pGetAttributeSyntax(NULL),
|
|
_fGetInfoDone(FALSE),
|
|
_pDispProperties(NULL),
|
|
_dwDispMaxProperties(0),
|
|
_cbDisp(0),
|
|
_pCredentials(NULL),
|
|
_pszServerName(NULL),
|
|
_dwPort(0)
|
|
{
|
|
InitializeListHead(&_ListSavingEntries);
|
|
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::~CPropertyCache
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
CPropertyCache::
|
|
~CPropertyCache()
|
|
{
|
|
PPROPERTY pThisProperty = NULL;
|
|
PDISPPROPERTY pThisDispProperty = NULL;
|
|
|
|
if (_pProperties) {
|
|
|
|
for ( DWORD i = 0; i < _dwMaxProperties; i++ ) {
|
|
|
|
pThisProperty = _pProperties + i;
|
|
|
|
if (pThisProperty->szPropertyName) {
|
|
FreeADsStr(pThisProperty->szPropertyName);
|
|
pThisProperty->szPropertyName = NULL;
|
|
}
|
|
|
|
LdapTypeFreeLdapObjects(&(PROPERTY_LDAPOBJECTARRAY(pThisProperty)));
|
|
}
|
|
|
|
FreeADsMem(_pProperties);
|
|
}
|
|
|
|
if (_pDispProperties) {
|
|
|
|
for ( DWORD i = 0; i < _dwDispMaxProperties; i++ ) {
|
|
|
|
pThisDispProperty = _pDispProperties + i;
|
|
|
|
if (pThisDispProperty->szPropertyName) {
|
|
FreeADsStr(pThisDispProperty->szPropertyName);
|
|
pThisDispProperty->szPropertyName = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
FreeADsMem(_pDispProperties);
|
|
}
|
|
|
|
if (_pszServerName) {
|
|
FreeADsStr(_pszServerName);
|
|
_pszServerName = NULL;
|
|
}
|
|
|
|
DeleteSavingEntry();
|
|
|
|
|
|
//
|
|
// The property cache is deleted before the object is
|
|
// so the object will handle freeing the credentials.
|
|
// We just keep a pointer to the credentials.
|
|
//
|
|
if (_pCredentials) {
|
|
_pCredentials = NULL;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::ClearAllPropertyFlags
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT CPropertyCache::ClearAllPropertyFlags(VOID)
|
|
{
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
if (_pProperties) {
|
|
|
|
for ( DWORD i = 0; i < _dwMaxProperties; i++ ) {
|
|
|
|
pThisProperty = _pProperties + i;
|
|
PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
|
|
}
|
|
}
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::ClearPropertyFlag
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT CPropertyCache::ClearPropertyFlag( LPWSTR szPropertyName )
|
|
{
|
|
PPROPERTY pThisProperty = NULL;
|
|
HRESULT hr = S_OK;
|
|
DWORD dwIndex;
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
if (PROPERTY_LDAPOBJECTARRAY(pThisProperty).pLdapObjects) {
|
|
|
|
PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::ClearMarshalledProperties
|
|
//
|
|
// Synopsis: Once the properties have been marshalled and
|
|
// the set has been done, the properties on the cache are no
|
|
// longer valid. This method must be called to keep the property
|
|
// cache in a coherrent state.
|
|
// The method frees the 'dirty' entries, sets implicit get
|
|
// flag. If the dirty entries cannot be cleared, then the
|
|
// entire contents are flushed and they will be picked up at the
|
|
// next GetInfo call -- AjayR
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT CPropertyCache::ClearMarshalledProperties()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwIndx = 0;
|
|
DWORD dwCtr = 0;
|
|
DWORD dwChng = 0;
|
|
PPROPERTY pNewProperties = NULL;
|
|
PPROPERTY pThisProperty = NULL;
|
|
PPROPERTY pNewCurProperty = NULL;
|
|
DWORD dwNewProps = 0;
|
|
|
|
|
|
//
|
|
// Go through properties to see how many have changed
|
|
//
|
|
for (dwCtr = 0; dwCtr < _dwMaxProperties; dwCtr++ ) {
|
|
pThisProperty = _pProperties + dwCtr;
|
|
|
|
if (PROPERTY_FLAGS(pThisProperty) != PROPERTY_INIT)
|
|
dwChng++;
|
|
}
|
|
|
|
if (dwChng == 0) {
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
//
|
|
// Need to remove those entries which were changed
|
|
//
|
|
|
|
dwNewProps = _dwMaxProperties - dwChng;
|
|
|
|
if (dwNewProps != 0) {
|
|
pNewProperties = (PPROPERTY) AllocADsMem(
|
|
dwNewProps * sizeof(PROPERTY)
|
|
);
|
|
|
|
if (!pNewProperties) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
// if this fails, then we cannot recover
|
|
// effectively. What alternative is there ?
|
|
// We do not want to flush the cache.
|
|
}
|
|
}
|
|
|
|
for (dwCtr = 0, dwIndx = 0; dwCtr < _dwMaxProperties; dwCtr++ ) {
|
|
|
|
pThisProperty = _pProperties + dwCtr;
|
|
|
|
if (PROPERTY_FLAGS(pThisProperty) != PROPERTY_INIT) {
|
|
//
|
|
// delete the property
|
|
//
|
|
|
|
if (pThisProperty->szPropertyName) {
|
|
FreeADsStr(pThisProperty->szPropertyName);
|
|
pThisProperty->szPropertyName = NULL;
|
|
}
|
|
|
|
LdapTypeFreeLdapObjects(&(PROPERTY_LDAPOBJECTARRAY(pThisProperty)));
|
|
|
|
} else {
|
|
|
|
//
|
|
// Sanity Check, should not hit this if Assert preferable
|
|
//
|
|
if (dwIndx > dwNewProps || dwIndx == dwNewProps) {
|
|
BAIL_ON_FAILURE(hr = E_FAIL);
|
|
}
|
|
|
|
pNewCurProperty = pNewProperties + dwIndx;
|
|
|
|
pNewCurProperty->szPropertyName = pThisProperty->szPropertyName;
|
|
|
|
pNewCurProperty->ldapObjectArray =
|
|
PROPERTY_LDAPOBJECTARRAY(pThisProperty);
|
|
|
|
pNewCurProperty->dwFlags = pThisProperty->dwFlags;
|
|
|
|
pNewCurProperty->dwSyntaxId = pThisProperty->dwSyntaxId;
|
|
|
|
dwIndx++;
|
|
}
|
|
} // for, copying the old elements to new buffer
|
|
|
|
_dwMaxProperties -= dwChng;
|
|
|
|
_cb = dwNewProps * sizeof(PROPERTY);
|
|
|
|
if (_pProperties)
|
|
FreeADsMem(_pProperties);
|
|
|
|
_pProperties = pNewProperties;
|
|
|
|
|
|
// Need to set this flag to implicitly fetch properties
|
|
// the next time somebody asks for a poperty not in the cache.
|
|
_fGetInfoDone = FALSE;
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
if (pNewProperties) {
|
|
FreeADsMem(pNewProperties);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::SetPropertyFlag
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT CPropertyCache::SetPropertyFlag( LPWSTR szPropertyName, DWORD dwFlag )
|
|
{
|
|
PPROPERTY pThisProperty = NULL;
|
|
HRESULT hr = S_OK;
|
|
DWORD dwIndex;
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
if (PROPERTY_LDAPOBJECTARRAY(pThisProperty).pLdapObjects) {
|
|
|
|
PROPERTY_FLAGS(pThisProperty) = dwFlag;
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::IsPropertyUpdated
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] --
|
|
// [pdwIndex] --
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
IsPropertyUpdated(
|
|
LPWSTR szPropertyName,
|
|
BOOL *pfUpdated
|
|
)
|
|
{
|
|
PPROPERTY pThisProperty = NULL;
|
|
HRESULT hr = S_OK;
|
|
DWORD dwIndex;
|
|
|
|
*pfUpdated = FALSE;
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
if (PROPERTY_LDAPOBJECTARRAY(pThisProperty).pLdapObjects) {
|
|
|
|
if ( PROPERTY_FLAGS(pThisProperty) == PROPERTY_UPDATE )
|
|
*pfUpdated = TRUE;
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::createpropertycache
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
createpropertycache(
|
|
CCoreADsObject *pCoreADsObject,
|
|
IGetAttributeSyntax *pGetAttributeSyntax,
|
|
CPropertyCache **ppPropertyCache
|
|
)
|
|
{
|
|
CPropertyCache FAR * pPropertyCache = NULL;
|
|
|
|
pPropertyCache = new CPropertyCache();
|
|
|
|
if (!pPropertyCache) {
|
|
RRETURN_EXP_IF_ERR(E_FAIL);
|
|
}
|
|
|
|
pPropertyCache->_pCoreADsObject = pCoreADsObject;
|
|
pPropertyCache->_pGetAttributeSyntax = pGetAttributeSyntax;
|
|
pPropertyCache->_fGetInfoDone = FALSE;
|
|
|
|
*ppPropertyCache = pPropertyCache;
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CPropertyCache::SetObjInformation(
|
|
CCredentials* pCredentials,
|
|
LPWSTR pszServerName,
|
|
DWORD dwPortNo
|
|
)
|
|
{
|
|
//
|
|
// We need the credentials to be valid
|
|
//
|
|
if (!pCredentials) {
|
|
ADsAssert(!"InvalidCredentials to prop cache");
|
|
} else {
|
|
_pCredentials = pCredentials;
|
|
}
|
|
|
|
//
|
|
// This can be NULL, so it is better to allocate and dealloc
|
|
// in destructor
|
|
//
|
|
if (_pszServerName) {
|
|
FreeADsStr(_pszServerName);
|
|
_pszServerName = NULL;
|
|
}
|
|
|
|
if (pszServerName) {
|
|
_pszServerName = AllocADsStr(pszServerName);
|
|
if (_pszServerName == NULL) {
|
|
RRETURN(E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
_dwPort = dwPortNo;
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::flushpropertycache
|
|
//
|
|
// Synopsis: Flushes the property cache of all data.
|
|
//
|
|
// The name <-> index mappings need to stay until the property cache is
|
|
// destructed, because the indexes are also used as the DISPIDs of the
|
|
// properties. So this neither deallocates the names nor the array itself.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
void
|
|
CPropertyCache::
|
|
flushpropertycache()
|
|
{
|
|
DWORD i = 0;
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
if (_pProperties) {
|
|
|
|
for (i = 0; i < _dwMaxProperties; i++) {
|
|
|
|
pThisProperty = _pProperties + i;
|
|
|
|
if (pThisProperty->szPropertyName) {
|
|
FreeADsStr(pThisProperty->szPropertyName);
|
|
pThisProperty->szPropertyName = NULL;
|
|
}
|
|
|
|
LdapTypeFreeLdapObjects(&(PROPERTY_LDAPOBJECTARRAY(pThisProperty)));
|
|
PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
|
|
}
|
|
|
|
FreeADsMem(_pProperties);
|
|
|
|
_pProperties = NULL;
|
|
_dwMaxProperties = 0;
|
|
_cb = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// Reset the property cache
|
|
//
|
|
|
|
_dwCurrentIndex = 0;
|
|
_fGetInfoDone = FALSE;
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::unmarshallproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
unmarshallproperty(
|
|
LPWSTR szPropertyName,
|
|
PADSLDP pLdapHandle,
|
|
LDAPMessage *entry,
|
|
DWORD dwSyntaxId,
|
|
BOOL fExplicit,
|
|
BOOL * pfRangeRetrieval // defaulted to NULL
|
|
)
|
|
{
|
|
DWORD dwIndex = 0;
|
|
HRESULT hr = S_OK;
|
|
LDAPOBJECTARRAY ldapObjectArray;
|
|
LPWSTR pszTemp = NULL;
|
|
|
|
LDAPOBJECTARRAY_INIT(ldapObjectArray);
|
|
|
|
//
|
|
// If arg is valid default value to false.
|
|
//
|
|
if (pfRangeRetrieval) {
|
|
*pfRangeRetrieval = FALSE;
|
|
}
|
|
|
|
hr = UnMarshallLDAPToLDAPSynID(
|
|
szPropertyName,
|
|
pLdapHandle,
|
|
entry,
|
|
dwSyntaxId,
|
|
&ldapObjectArray
|
|
);
|
|
|
|
//
|
|
// Need to look for ; as in members;range or value;binary
|
|
// and strip the ; out before adding to cache.
|
|
//
|
|
if ((pszTemp = wcschr(szPropertyName, L';')) != NULL ) {
|
|
*pszTemp = L'\0';
|
|
}
|
|
//
|
|
// Find this property in the cache
|
|
//
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
|
|
//
|
|
// If this property does not exist in the
|
|
// cache, add this property into the cache.
|
|
//
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
hr = addproperty(
|
|
szPropertyName
|
|
);
|
|
|
|
//
|
|
// If the operation fails for some reason
|
|
// move on to the next property
|
|
//
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
//
|
|
// Now update the property in the cache
|
|
//
|
|
|
|
hr = updateproperty(
|
|
szPropertyName,
|
|
dwSyntaxId,
|
|
ldapObjectArray,
|
|
fExplicit
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// Put the ; back if we replaced it.
|
|
//
|
|
if (pszTemp) {
|
|
|
|
//
|
|
// Do we need to update the flag ?
|
|
//
|
|
if (pfRangeRetrieval) {
|
|
//
|
|
// See if this was members and update flag.
|
|
//
|
|
if (!_wcsicmp(L"member", szPropertyName)) {
|
|
*pfRangeRetrieval = TRUE;
|
|
}
|
|
}
|
|
|
|
*pszTemp = L';';
|
|
|
|
}
|
|
|
|
if ( ldapObjectArray.fIsString )
|
|
LdapValueFree( (TCHAR **) ldapObjectArray.pLdapObjects );
|
|
else
|
|
LdapValueFreeLen( (struct berval **) ldapObjectArray.pLdapObjects );
|
|
|
|
error:
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
LDAPUnMarshallProperties(
|
|
LPWSTR pszServerPath,
|
|
PADSLDP pLdapHandle,
|
|
LDAPMessage *ldapmsg,
|
|
BOOL fExplicit,
|
|
CCredentials& Credentials
|
|
)
|
|
{
|
|
int nNumberOfEntries = 0L;
|
|
int nNumberOfValues = 0L;
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0;
|
|
LDAPMessage *entry;
|
|
LPWSTR pszAttrName = NULL;
|
|
void *ptr;
|
|
|
|
OBJECTINFO ObjectInfo;
|
|
POBJECTINFO pObjectInfo = &ObjectInfo;
|
|
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
|
|
//
|
|
// Compute the number of attributes in the
|
|
// read buffer.
|
|
|
|
nNumberOfEntries = LdapCountEntries( pLdapHandle, ldapmsg );
|
|
|
|
if ( nNumberOfEntries == 0 )
|
|
RRETURN(S_OK);
|
|
|
|
hr = LdapFirstEntry( pLdapHandle, ldapmsg, &entry );
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = LdapFirstAttribute( pLdapHandle, entry, &ptr, &pszAttrName );
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
while ( pszAttrName != NULL )
|
|
{
|
|
DWORD dwSyntax = LDAPTYPE_UNKNOWN;
|
|
|
|
LPWSTR pszADsPath;
|
|
hr = _pCoreADsObject->get_CoreADsPath(&pszADsPath);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ADsObject(pszADsPath, pObjectInfo);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// unmarshall this property into the
|
|
// property cache.
|
|
// LdapGetSyntax takes care of ; while looking up
|
|
// the schema no need to handle at this level.
|
|
//
|
|
hr = LdapGetSyntaxOfAttributeOnServer(
|
|
pszServerPath,
|
|
pszAttrName,
|
|
&dwSyntax,
|
|
Credentials,
|
|
pObjectInfo->PortNumber,
|
|
TRUE // fForce
|
|
);
|
|
ADsFreeString(pszADsPath);
|
|
|
|
if ( SUCCEEDED(hr) && (dwSyntax != LDAPTYPE_UNKNOWN))
|
|
{
|
|
if ( (!_wcsicmp(pszAttrName, L"ntSecurityDescriptor")) &&
|
|
(dwSyntax == LDAPTYPE_OCTETSTRING) )
|
|
{
|
|
dwSyntax = LDAPTYPE_SECURITY_DESCRIPTOR;
|
|
}
|
|
|
|
(VOID) unmarshallproperty(
|
|
pszAttrName,
|
|
pLdapHandle,
|
|
entry,
|
|
dwSyntax,
|
|
fExplicit
|
|
);
|
|
}
|
|
|
|
LdapAttributeFree( pszAttrName );
|
|
pszAttrName = NULL;
|
|
|
|
//
|
|
// If we cannot find the syntax, ignore the property and
|
|
// continue with the next property
|
|
//
|
|
hr = S_OK;
|
|
|
|
hr = LdapNextAttribute( pLdapHandle, entry, ptr, &pszAttrName );
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
FreeObjectInfo(pObjectInfo);
|
|
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
|
|
}
|
|
|
|
error:
|
|
|
|
FreeObjectInfo(pObjectInfo);
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Unmarshall attributes (& their values) in [ldapmsg] into cache.
|
|
// Syntaxes of attributes are read from schema on server [pszServerPath].
|
|
// If an attribute not in the schema (e.g. not in our default schema used
|
|
// in case of schemaless server), the attribute is unmarshalled as ldap
|
|
// binary data with type = LDAPTYPE_UNKWNON.
|
|
//
|
|
// [Credentials]
|
|
// - used to access pszServerPath
|
|
//
|
|
// [pLdapHandle]
|
|
// - handle assoc with [ldapmsg]
|
|
// - used to retrive attributes and their values from [ldapmsg]
|
|
//
|
|
// [fExplicit]
|
|
// - overwrite value of exiting attributes in cache iff = TRUE
|
|
//
|
|
// NOTE: This function modified LDAPUnMarshallProperties to allow
|
|
// unmarshalling of attributes not in the schema.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
LDAPUnMarshallProperties2(
|
|
IN LPWSTR pszServerPath,
|
|
IN PADSLDP pLdapHandle,
|
|
IN LDAPMessage *ldapmsg,
|
|
IN BOOL fExplicit,
|
|
IN CCredentials& Credentials,
|
|
OUT BOOL * pfRangeRetrieval
|
|
)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
int nNumberOfEntries = 0L;
|
|
LDAPMessage *entry = NULL;
|
|
void *ptr = NULL;
|
|
LPWSTR pszAttrName = NULL;
|
|
DWORD dwSyntax = LDAPTYPE_UNKNOWN;
|
|
LPWSTR pszADsPath = NULL;
|
|
OBJECTINFO ObjectInfo;
|
|
BOOL fRange = FALSE;
|
|
memset(&ObjectInfo, 0, sizeof(OBJECTINFO));
|
|
|
|
ADsAssert(pfRangeRetrieval);
|
|
*pfRangeRetrieval = FALSE;
|
|
|
|
if (!pLdapHandle || !ldapmsg)
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
|
|
//
|
|
// Compute the number of attributes in the read buffer.
|
|
//
|
|
|
|
nNumberOfEntries = LdapCountEntries(pLdapHandle, ldapmsg);
|
|
|
|
if ( nNumberOfEntries == 0 )
|
|
RRETURN(S_OK);
|
|
|
|
|
|
//
|
|
// get port number to talk to server on which schema locate ???
|
|
//
|
|
|
|
hr = _pCoreADsObject->get_CoreADsPath(&pszADsPath);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ADsObject(pszADsPath, &ObjectInfo);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// Get first entry from ldapmsg first. Should be only one entry.
|
|
//
|
|
|
|
hr = LdapFirstEntry( pLdapHandle, ldapmsg, &entry );
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// get first attribute's name
|
|
//
|
|
|
|
hr = LdapFirstAttribute( pLdapHandle, entry, &ptr, &pszAttrName );
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
while ( pszAttrName != NULL )
|
|
{
|
|
//
|
|
// get syntax of attribute from schema on sever (may be cached);
|
|
// continue to unmarshall the attribute even if it isn't in the
|
|
// schema.
|
|
//
|
|
|
|
dwSyntax = LDAPTYPE_UNKNOWN;
|
|
|
|
(VOID) LdapGetSyntaxOfAttributeOnServer(
|
|
pszServerPath,
|
|
pszAttrName,
|
|
&dwSyntax,
|
|
Credentials,
|
|
ObjectInfo.PortNumber,
|
|
TRUE // fForce
|
|
);
|
|
|
|
|
|
//
|
|
// There is currently no such syntax as "SecurityDescriptor" on
|
|
// server, ADSI will unmarshall "OctetString" security descriptor
|
|
// as as ntSecurityDescriptor
|
|
//
|
|
|
|
if ( (!_wcsicmp(pszAttrName, L"ntSecurityDescriptor"))
|
|
&& (dwSyntax == LDAPTYPE_OCTETSTRING)
|
|
)
|
|
{
|
|
dwSyntax = LDAPTYPE_SECURITY_DESCRIPTOR;
|
|
}
|
|
|
|
//
|
|
// unmarshall the property into cache, LDAPTYPE_UNWKNOWN
|
|
// (dwSyntax) will be unmarshalled as binary data.
|
|
//
|
|
|
|
(VOID) unmarshallproperty(
|
|
pszAttrName,
|
|
pLdapHandle,
|
|
entry,
|
|
dwSyntax,
|
|
fExplicit,
|
|
fRange ? NULL : pfRangeRetrieval
|
|
);
|
|
|
|
//
|
|
// Small trick to make sure we do not loose the range
|
|
// retrieval information for members attribute.
|
|
//
|
|
fRange = *pfRangeRetrieval;
|
|
|
|
//
|
|
// get next attribute
|
|
//
|
|
|
|
LdapAttributeFree( pszAttrName );
|
|
pszAttrName = NULL;
|
|
hr = LdapNextAttribute( pLdapHandle, entry, ptr, &pszAttrName );
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
|
|
if (pszADsPath)
|
|
ADsFreeString(pszADsPath);
|
|
|
|
FreeObjectInfo(&ObjectInfo);
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
LDAPMarshallProperties(
|
|
LDAPModW ***aMods,
|
|
PBOOL pfNTSecDes,
|
|
SECURITY_INFORMATION *pSeInfo
|
|
)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0;
|
|
DWORD j = 0;
|
|
PPROPERTY pThisProperty = NULL;
|
|
int dwCount = 0;
|
|
LDAPModW *aModsBuffer = NULL;
|
|
LDAPOBJECTARRAY ldapObjectArray;
|
|
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
|
|
|
|
BOOL fDaclDefaulted = FALSE;
|
|
BOOL fSaclDefaulted = FALSE;
|
|
BOOL fOwnerDefaulted = FALSE;
|
|
BOOL fGroupDefaulted = FALSE;
|
|
|
|
PSID pOwnerSid = NULL;
|
|
PSID pGroupSid = NULL;
|
|
PACL pDacl = NULL;
|
|
PACL pSacl = NULL;
|
|
|
|
BOOL DaclPresent = FALSE;
|
|
BOOL SaclPresent = FALSE;
|
|
|
|
BOOL fSecDesProp = FALSE;
|
|
|
|
*pSeInfo = INVALID_SE_VALUE;
|
|
*pfNTSecDes = FALSE;
|
|
|
|
for (i = 0; i < _dwMaxProperties ; i++) {
|
|
|
|
pThisProperty = _pProperties + i;
|
|
|
|
//
|
|
// Bypass any property that has not been
|
|
// modified
|
|
//
|
|
|
|
if (PROPERTY_FLAGS(pThisProperty) != PROPERTY_INIT)
|
|
dwCount++;
|
|
}
|
|
|
|
if ( dwCount == 0 ) // Nothing to change
|
|
{
|
|
*aMods = NULL;
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
*aMods = (LDAPModW **) AllocADsMem((dwCount+1) * sizeof(LDAPModW *));
|
|
|
|
if ( *aMods == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
aModsBuffer = (LDAPModW *) AllocADsMem( dwCount * sizeof(LDAPModW));
|
|
|
|
if ( aModsBuffer == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
for (i = 0, j = 0; i < _dwMaxProperties; i++) {
|
|
|
|
pThisProperty = _pProperties + i;
|
|
|
|
//
|
|
// Bypass any property that has not been
|
|
// modified
|
|
//
|
|
|
|
if (PROPERTY_FLAGS(pThisProperty) == PROPERTY_INIT ) {
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
if (!_wcsicmp(PROPERTY_NAME(pThisProperty),L"ntSecurityDescriptor")) {
|
|
*pfNTSecDes = TRUE;
|
|
fSecDesProp = TRUE;
|
|
} else {
|
|
fSecDesProp = FALSE;
|
|
}
|
|
|
|
ldapObjectArray = PROPERTY_LDAPOBJECTARRAY(pThisProperty);
|
|
|
|
(*aMods)[j] = &aModsBuffer[j];
|
|
aModsBuffer[j].mod_type = PROPERTY_NAME(pThisProperty);
|
|
|
|
if ( ldapObjectArray.fIsString )
|
|
{
|
|
aModsBuffer[j].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
|
|
}
|
|
else
|
|
{
|
|
aModsBuffer[j].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
|
|
aModsBuffer[j].mod_op = LDAP_MOD_BVALUES;
|
|
if (fSecDesProp) {
|
|
pSecurityDescriptor = LDAPOBJECT_BERVAL_VAL(ldapObjectArray.pLdapObjects);
|
|
|
|
if ( GetSecurityDescriptorOwner(
|
|
pSecurityDescriptor,
|
|
&pOwnerSid,
|
|
&fOwnerDefaulted
|
|
)
|
|
&&
|
|
|
|
GetSecurityDescriptorGroup(
|
|
pSecurityDescriptor,
|
|
&pGroupSid,
|
|
&fGroupDefaulted
|
|
)
|
|
&&
|
|
|
|
GetSecurityDescriptorDacl(
|
|
pSecurityDescriptor,
|
|
&DaclPresent,
|
|
&pDacl,
|
|
&fDaclDefaulted
|
|
)
|
|
&&
|
|
|
|
GetSecurityDescriptorSacl(
|
|
pSecurityDescriptor,
|
|
&SaclPresent,
|
|
&pSacl,
|
|
&fSaclDefaulted
|
|
)
|
|
) {
|
|
//
|
|
// All the calls succeeded, so we should reset to 0
|
|
// instead of the invalid value.
|
|
//
|
|
*pSeInfo = 0;
|
|
|
|
if (!fOwnerDefaulted) {
|
|
*pSeInfo = *pSeInfo | OWNER_SECURITY_INFORMATION;
|
|
}
|
|
|
|
if (!fGroupDefaulted) {
|
|
*pSeInfo = *pSeInfo | GROUP_SECURITY_INFORMATION;
|
|
}
|
|
|
|
//
|
|
// If the DACL is present we need to send DACL bit.
|
|
//
|
|
if (DaclPresent) {
|
|
*pSeInfo = *pSeInfo | DACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
//
|
|
// If SACL present then we set the SACL bit.
|
|
if (SaclPresent) {
|
|
*pSeInfo = *pSeInfo | SACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
switch( PROPERTY_FLAGS(pThisProperty))
|
|
{
|
|
case PROPERTY_UPDATE:
|
|
aModsBuffer[j].mod_op |= LDAP_MOD_REPLACE;
|
|
break;
|
|
|
|
case PROPERTY_ADD:
|
|
aModsBuffer[j].mod_op |= LDAP_MOD_ADD;
|
|
break;
|
|
|
|
case PROPERTY_DELETE:
|
|
aModsBuffer[j].mod_op |= LDAP_MOD_DELETE;
|
|
break;
|
|
|
|
|
|
case PROPERTY_DELETE_VALUE:
|
|
aModsBuffer[j].mod_op |= LDAP_MOD_DELETE;
|
|
break;
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
FreeADsMem( aModsBuffer );
|
|
FreeADsMem( *aMods );
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
LDAPMarshallProperties2(
|
|
LDAPModW ***aMods,
|
|
DWORD *pdwNumOfMods
|
|
)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0;
|
|
DWORD j = 0;
|
|
PPROPERTY pThisProperty = NULL;
|
|
int dwCount = 0;
|
|
LDAPModW *aModsBuffer = NULL;
|
|
LDAPOBJECTARRAY ldapObjectArray;
|
|
|
|
for (i = 0; i < _dwMaxProperties ; i++) {
|
|
|
|
pThisProperty = _pProperties + i;
|
|
|
|
//
|
|
// Bypass any property that has not been
|
|
// modified
|
|
//
|
|
|
|
if (PROPERTY_FLAGS(pThisProperty) != PROPERTY_INIT)
|
|
dwCount++;
|
|
}
|
|
|
|
if ( dwCount == 0 ) // Nothing to change
|
|
RRETURN(S_OK);
|
|
|
|
if ( *aMods == NULL )
|
|
{
|
|
*aMods = (LDAPModW **) AllocADsMem((dwCount+1) * sizeof(LDAPModW *));
|
|
|
|
if ( *aMods == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
aModsBuffer = (LDAPModW *) AllocADsMem( dwCount * sizeof(LDAPModW));
|
|
|
|
if ( aModsBuffer == NULL )
|
|
{
|
|
FreeADsMem( *aMods );
|
|
*aMods = NULL;
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LDAPModW **aModsTemp = NULL;
|
|
|
|
aModsTemp = (LDAPModW **) AllocADsMem(
|
|
(*pdwNumOfMods+ dwCount + 1) * sizeof(LDAPModW *));
|
|
|
|
if ( aModsTemp == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
aModsBuffer = (LDAPModW *) AllocADsMem(
|
|
(*pdwNumOfMods + dwCount) * sizeof(LDAPModW));
|
|
|
|
if ( aModsBuffer == NULL )
|
|
{
|
|
FreeADsMem( aModsTemp );
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
memcpy( aModsBuffer, **aMods, *pdwNumOfMods * sizeof(LDAPModW));
|
|
FreeADsMem( **aMods );
|
|
FreeADsMem( *aMods );
|
|
|
|
*aMods = aModsTemp;
|
|
|
|
for ( j = 0; j < *pdwNumOfMods; j++ )
|
|
{
|
|
(*aMods)[j] = &aModsBuffer[j];
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < _dwMaxProperties; i++) {
|
|
|
|
pThisProperty = _pProperties + i;
|
|
|
|
//
|
|
// Bypass any property that has not been
|
|
// modified
|
|
//
|
|
|
|
if (PROPERTY_FLAGS(pThisProperty) == PROPERTY_INIT ) {
|
|
|
|
continue;
|
|
}
|
|
|
|
ldapObjectArray = PROPERTY_LDAPOBJECTARRAY(pThisProperty);
|
|
|
|
(*aMods)[j] = &aModsBuffer[j];
|
|
aModsBuffer[j].mod_type = PROPERTY_NAME(pThisProperty);
|
|
|
|
if ( ldapObjectArray.fIsString )
|
|
{
|
|
aModsBuffer[j].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
|
|
}
|
|
else
|
|
{
|
|
aModsBuffer[j].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
|
|
aModsBuffer[j].mod_op = LDAP_MOD_BVALUES;
|
|
}
|
|
|
|
switch( PROPERTY_FLAGS(pThisProperty))
|
|
{
|
|
case PROPERTY_UPDATE:
|
|
aModsBuffer[j].mod_op |= LDAP_MOD_REPLACE;
|
|
break;
|
|
|
|
case PROPERTY_ADD:
|
|
aModsBuffer[j].mod_op |= LDAP_MOD_ADD;
|
|
break;
|
|
|
|
case PROPERTY_DELETE:
|
|
aModsBuffer[j].mod_op |= LDAP_MOD_DELETE;
|
|
break;
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
*pdwNumOfMods += dwCount;
|
|
|
|
error:
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::unboundgetproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] -- Property to retrieve from the cache
|
|
// [pvaData] -- Data returned in a variant
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
unboundgetproperty(
|
|
LPWSTR szPropertyName,
|
|
PDWORD pdwSyntaxId,
|
|
PDWORD pdwStatusFlag,
|
|
LDAPOBJECTARRAY *pLdapObjectArray
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwIndex = 0L;
|
|
|
|
|
|
//
|
|
// get index of property in cache
|
|
//
|
|
|
|
hr = findproperty(
|
|
szPropertyName,
|
|
&dwIndex
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
//
|
|
// get property based on index in cache
|
|
//
|
|
|
|
hr = unboundgetproperty(
|
|
dwIndex,
|
|
pdwSyntaxId,
|
|
pdwStatusFlag,
|
|
pLdapObjectArray
|
|
);
|
|
|
|
error:
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::unboundgetproperty
|
|
//
|
|
// Synopsis: Note that this version takes the index of the element to
|
|
// fetch. It also returns the control code of the item in the cache.
|
|
//
|
|
//
|
|
// Arguments: [dwIndex] -- Index of the property to retrieve.
|
|
// [pdwSytnaxId] -- SyntaxId of the data.
|
|
// [pdwStatusFlag] -- Status of this property in cache.
|
|
// [pLdapObjectArray] -- Array of ldapObjects returned.
|
|
//
|
|
// NOTE: [dwIndex] is invalid -> E_ADS_PROPERTY_NOT_FOUND//E_FAIL ???
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
unboundgetproperty(
|
|
DWORD dwIndex,
|
|
PDWORD pdwSyntaxId,
|
|
PDWORD pdwStatusFlag,
|
|
LDAPOBJECTARRAY *pLdapObjectArray
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
|
|
if (!index_valid(dwIndex))
|
|
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
|
|
|
|
// Status flag has to be valid if we found the property
|
|
*pdwStatusFlag = PROPERTY_FLAGS(pThisProperty);
|
|
|
|
|
|
if (PROPERTY_LDAPOBJECTARRAY(pThisProperty).pLdapObjects) {
|
|
|
|
//
|
|
// property has non-empty values
|
|
//
|
|
|
|
*pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
|
|
|
|
hr = LdapTypeCopyConstruct(
|
|
PROPERTY_LDAPOBJECTARRAY(pThisProperty),
|
|
pLdapObjectArray
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
//
|
|
// property has empty values: E.g. status flag indicate delete
|
|
// operation (or empty values allowed on non-ntds ldap server?)
|
|
//
|
|
|
|
pLdapObjectArray->pLdapObjects = NULL;
|
|
pLdapObjectArray->dwCount = 0;
|
|
*pdwSyntaxId = LDAPTYPE_UNKNOWN;
|
|
//hr = E_FAIL;
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
void
|
|
CPropertyCache::
|
|
reset_propindex(
|
|
)
|
|
{
|
|
_dwCurrentIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
skip_propindex(
|
|
DWORD dwElements
|
|
)
|
|
{
|
|
DWORD newIndex = _dwCurrentIndex + dwElements;
|
|
|
|
if (!index_valid())
|
|
RRETURN_EXP_IF_ERR(E_FAIL);
|
|
|
|
//
|
|
// - allow current index to go from within range to out of range by 1
|
|
// - by 1 since initial state is out of range by 1
|
|
//
|
|
|
|
if ( newIndex > _dwMaxProperties )
|
|
RRETURN_EXP_IF_ERR(E_FAIL);
|
|
|
|
_dwCurrentIndex = newIndex;
|
|
RRETURN(S_OK);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
get_PropertyCount(
|
|
PDWORD pdwMaxProperties
|
|
)
|
|
{
|
|
ADsAssert(pdwMaxProperties); // function private -> use assertion
|
|
|
|
*pdwMaxProperties = _dwMaxProperties;
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
DWORD
|
|
CPropertyCache::
|
|
get_CurrentIndex(
|
|
)
|
|
{
|
|
return(_dwCurrentIndex);
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
CPropertyCache::
|
|
get_CurrentPropName(
|
|
)
|
|
|
|
{
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
if (!index_valid())
|
|
return(NULL);
|
|
|
|
pThisProperty = _pProperties + _dwCurrentIndex;
|
|
|
|
return(PROPERTY_NAME(pThisProperty));
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
CPropertyCache::
|
|
get_PropName(
|
|
DWORD dwIndex
|
|
)
|
|
|
|
{
|
|
PPROPERTY pThisProperty = NULL;
|
|
|
|
if (!index_valid(dwIndex))
|
|
return(NULL);
|
|
|
|
pThisProperty = _pProperties + dwIndex;
|
|
|
|
return(PROPERTY_NAME(pThisProperty));
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
LDAPUnMarshallPropertyAs(
|
|
LPWSTR pszServerPath,
|
|
PADSLDP pLdapHandle,
|
|
LDAPMessage *ldapmsg,
|
|
LPWSTR szPropertyName,
|
|
DWORD dwSyntaxId,
|
|
BOOL fExplicit,
|
|
CCredentials& Credentials
|
|
)
|
|
{
|
|
int nNumberOfEntries = 0L;
|
|
int nNumberOfValues = 0L;
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0;
|
|
LDAPMessage *entry;
|
|
LPWSTR pszAttrName = NULL;
|
|
void *ptr;
|
|
|
|
OBJECTINFO ObjectInfo;
|
|
POBJECTINFO pObjectInfo = &ObjectInfo;
|
|
|
|
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
|
|
//
|
|
// Compute the number of attributes in the
|
|
// read buffer.
|
|
//
|
|
|
|
nNumberOfEntries = LdapCountEntries( pLdapHandle, ldapmsg );
|
|
|
|
if ( nNumberOfEntries == 0 )
|
|
RRETURN(S_OK);
|
|
|
|
hr = LdapFirstEntry( pLdapHandle, ldapmsg, &entry );
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = LdapFirstAttribute( pLdapHandle, entry, &ptr, &pszAttrName );
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
while ( pszAttrName != NULL )
|
|
{
|
|
DWORD dwSyntax = LDAPTYPE_UNKNOWN;
|
|
|
|
LPWSTR pszADsPath;
|
|
hr = _pCoreADsObject->get_CoreADsPath(&pszADsPath);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ADsObject(pszADsPath, pObjectInfo);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// unmarshall this property into the
|
|
// property cache
|
|
//
|
|
hr = LdapGetSyntaxOfAttributeOnServer(
|
|
pszServerPath,
|
|
pszAttrName,
|
|
&dwSyntax,
|
|
Credentials,
|
|
pObjectInfo->PortNumber
|
|
);
|
|
ADsFreeString(pszADsPath);
|
|
|
|
if ( SUCCEEDED(hr) && (dwSyntax != LDAPTYPE_UNKNOWN))
|
|
{
|
|
if ( (!_wcsicmp(pszAttrName, L"ntSecurityDescriptor")) &&
|
|
(dwSyntax == LDAPTYPE_OCTETSTRING) )
|
|
{
|
|
dwSyntax = LDAPTYPE_SECURITY_DESCRIPTOR;
|
|
}
|
|
|
|
(VOID) unmarshallproperty(
|
|
pszAttrName,
|
|
pLdapHandle,
|
|
entry,
|
|
dwSyntax,
|
|
fExplicit
|
|
);
|
|
}else {
|
|
|
|
if (!_wcsicmp(pszAttrName, szPropertyName)) {
|
|
|
|
(VOID) unmarshallproperty(
|
|
pszAttrName,
|
|
pLdapHandle,
|
|
entry,
|
|
dwSyntaxId,
|
|
fExplicit
|
|
);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
LdapAttributeFree( pszAttrName );
|
|
pszAttrName = NULL;
|
|
|
|
//
|
|
// If we cannot find the syntax, ignore the property and
|
|
// continue with the next property
|
|
//
|
|
hr = S_OK;
|
|
|
|
hr = LdapNextAttribute( pLdapHandle, entry, ptr, &pszAttrName );
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
FreeObjectInfo(pObjectInfo);
|
|
|
|
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
|
|
|
|
}
|
|
|
|
error:
|
|
|
|
FreeObjectInfo(pObjectInfo);
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
LDAPUnMarshallPropertiesAs(
|
|
LPWSTR pszServerPath,
|
|
PADSLDP pLdapHandle,
|
|
LDAPMessage *ldapmsg,
|
|
DWORD dwSyntaxId,
|
|
BOOL fExplicit,
|
|
CCredentials& Credentials
|
|
)
|
|
{
|
|
int nNumberOfEntries = 0L;
|
|
int nNumberOfValues = 0L;
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0;
|
|
LDAPMessage *entry;
|
|
LPWSTR pszAttrName = NULL;
|
|
void *ptr;
|
|
|
|
//
|
|
// Compute the number of attributes in the
|
|
// read buffer.
|
|
//
|
|
|
|
nNumberOfEntries = LdapCountEntries( pLdapHandle, ldapmsg );
|
|
|
|
if ( nNumberOfEntries == 0 )
|
|
RRETURN(S_OK);
|
|
|
|
hr = LdapFirstEntry( pLdapHandle, ldapmsg, &entry );
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = LdapFirstAttribute( pLdapHandle, entry, &ptr, &pszAttrName );
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
while ( pszAttrName != NULL )
|
|
{
|
|
(VOID) unmarshallproperty(
|
|
pszAttrName,
|
|
pLdapHandle,
|
|
entry,
|
|
dwSyntaxId,
|
|
fExplicit
|
|
);
|
|
|
|
LdapAttributeFree( pszAttrName );
|
|
pszAttrName = NULL;
|
|
|
|
hr = LdapNextAttribute( pLdapHandle, entry, ptr, &pszAttrName );
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
deleteproperty(
|
|
DWORD dwIndex
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PPROPERTY pNewProperties = NULL;
|
|
PPROPERTY pThisProperty = _pProperties + dwIndex;
|
|
|
|
if (!index_valid(dwIndex)) {
|
|
hr = E_FAIL;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if (_dwMaxProperties == 1) {
|
|
//
|
|
// Deleting everything
|
|
//
|
|
FreeADsStr(pThisProperty->szPropertyName);
|
|
LdapTypeFreeLdapObjects( &(PROPERTY_LDAPOBJECTARRAY(pThisProperty)) );
|
|
FreeADsMem(_pProperties);
|
|
_pProperties = NULL;
|
|
_dwMaxProperties = 0;
|
|
_cb = 0;
|
|
//
|
|
// Need to reset the current index too just in case.
|
|
//
|
|
_dwCurrentIndex = 0;
|
|
RRETURN(hr);
|
|
}
|
|
|
|
pNewProperties = (PPROPERTY)AllocADsMem(
|
|
_cb - sizeof(PROPERTY)
|
|
);
|
|
if (!pNewProperties) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// Copying the memory before the deleted item
|
|
//
|
|
if (dwIndex != 0) {
|
|
memcpy( pNewProperties,
|
|
_pProperties,
|
|
dwIndex * sizeof(PROPERTY));
|
|
}
|
|
|
|
//
|
|
// Copying the memory following the deleted item
|
|
//
|
|
if (dwIndex != (_dwMaxProperties-1)) {
|
|
memcpy( pNewProperties + dwIndex,
|
|
_pProperties + dwIndex + 1,
|
|
(_dwMaxProperties - dwIndex - 1) * sizeof(PROPERTY));
|
|
}
|
|
|
|
FreeADsStr(pThisProperty->szPropertyName);
|
|
LdapTypeFreeLdapObjects( &(PROPERTY_LDAPOBJECTARRAY(pThisProperty)) );
|
|
FreeADsMem(_pProperties);
|
|
_pProperties = pNewProperties;
|
|
_dwMaxProperties--;
|
|
_cb -= sizeof(PROPERTY);
|
|
|
|
//
|
|
// Reset the current index if necesary so we do not skip a property.
|
|
//
|
|
if (_dwCurrentIndex > dwIndex) {
|
|
_dwCurrentIndex--;
|
|
}
|
|
error:
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
//
|
|
// For dynamic dispid's.
|
|
//
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::locateproperty
|
|
//
|
|
// Synopsis: Finds a property in the cache by name.
|
|
//
|
|
// This differs from findproperty() in return code; this returns no ADSI
|
|
// errors, since it's going to a VB interface.
|
|
//
|
|
// If the property is not found in the cache, this uses the IDirectoryObject
|
|
// interface of the containing object to get the attributes of the object.
|
|
// If GetObjectAttributes doesn't return any information about the property,
|
|
// this method returns DISP_E_UNKNOWNNAME.
|
|
//
|
|
// Arguments: [szPropertyName] -- Name of the property.
|
|
// [pdwIndex] -- Index in the array of properties.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::locateproperty(
|
|
LPWSTR szPropertyName,
|
|
PDWORD pdwIndex
|
|
)
|
|
{
|
|
HRESULT hr = findproperty(szPropertyName, pdwIndex);
|
|
|
|
if (hr == E_ADS_PROPERTY_NOT_FOUND)
|
|
{
|
|
DWORD dwLdapSyntaxId = 0;
|
|
PPROPERTY pProperty = NULL;
|
|
|
|
hr = _pGetAttributeSyntax->GetAttributeSyntax(
|
|
szPropertyName,
|
|
&dwLdapSyntaxId
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = addproperty(szPropertyName);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = findproperty(szPropertyName, pdwIndex);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pProperty = _pProperties + *pdwIndex;
|
|
PROPERTY_SYNTAX(pProperty) = dwLdapSyntaxId;
|
|
PROPERTY_FLAGS(pProperty) = PROPERTY_INIT;
|
|
PROPERTY_LDAPOBJECTARRAY(pProperty).dwCount = 0;
|
|
PROPERTY_LDAPOBJECTARRAY(pProperty).pLdapObjects = NULL;
|
|
}
|
|
|
|
error:
|
|
//
|
|
// Automation return code would be DISP_E_UNKNOWNNAME.
|
|
// ADSI return code would be E_ADS_PROPERTY_NOT_FOUND (like findproperty.)
|
|
//
|
|
if (FAILED(hr))
|
|
hr = E_ADS_PROPERTY_NOT_FOUND;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::getproperty
|
|
//
|
|
// Synopsis: Get the values of a property from the cache.
|
|
// The values are returned as a VARIANT.
|
|
//
|
|
// Arguments: [dwIndex] -- Index of property to retrieve
|
|
// [pVarResult] -- Data returned as a VARIANT
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::getproperty(
|
|
DWORD dwIndex,
|
|
PDWORD dwStatusFlag,
|
|
VARIANT *pVarResult,
|
|
CCredentials &Credentials
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId;
|
|
LDAPOBJECTARRAY LdapObjectArray;
|
|
|
|
LDAPOBJECTARRAY_INIT(LdapObjectArray);
|
|
|
|
//
|
|
// This should not return E_ADS_PROPERTY_NOT_FOUND in this case.
|
|
// We have an index, which should indicate that we have an array entry.
|
|
// If we weren't dealing with VB, I'd be tempted to make this an Assert.
|
|
//
|
|
if (!index_valid(dwIndex))
|
|
BAIL_ON_FAILURE(hr = DISP_E_MEMBERNOTFOUND);
|
|
|
|
if (INDEX_EMPTY(dwIndex) &&
|
|
!PROP_DELETED(dwIndex) &&
|
|
!_fGetInfoDone)
|
|
{
|
|
hr = _pCoreADsObject->GetInfo(FALSE);
|
|
|
|
// workaround to avoid confusing callers of getproperty.
|
|
if (hr == E_NOTIMPL)
|
|
hr = DISP_E_MEMBERNOTFOUND;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = unboundgetproperty(
|
|
dwIndex,
|
|
&dwSyntaxId,
|
|
dwStatusFlag,
|
|
&LdapObjectArray
|
|
);
|
|
|
|
// For backward compatibility
|
|
if (!LdapObjectArray.pLdapObjects && SUCCEEDED(hr)) {
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (LdapObjectArray.dwCount == 1) {
|
|
hr = LdapTypeToVarTypeCopy(
|
|
NULL,
|
|
Credentials,
|
|
LdapObjectArray.pLdapObjects,
|
|
dwSyntaxId,
|
|
pVarResult);
|
|
}
|
|
else {
|
|
hr = LdapTypeToVarTypeCopyConstruct(
|
|
NULL,
|
|
Credentials,
|
|
LdapObjectArray,
|
|
dwSyntaxId,
|
|
pVarResult);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// unboundgetproperty() returns E_FAIL on failure.
|
|
// But getproperty() should return E_ADS_PROPERTY_NOT_FOUND.
|
|
//
|
|
if (hr == E_FAIL)
|
|
hr = E_ADS_PROPERTY_NOT_FOUND;
|
|
|
|
//
|
|
// A proper Automation return value would be
|
|
// hr = DISP_E_MEMBERNOTFOUND;
|
|
//
|
|
ADsAssert(pVarResult);
|
|
V_VT(pVarResult) = VT_ERROR;
|
|
}
|
|
|
|
error:
|
|
LdapTypeFreeLdapObjects(&LdapObjectArray);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// This is here just so that we can compile, no one should be
|
|
// calling this
|
|
//
|
|
// - The comment above and within the function is INCORRECT.
|
|
// - At present, this function is called and works with known bug.
|
|
// This function should NOT be a wrap around of getproperty with
|
|
// 3 param. The [dwIndex] in this function should have a DIFFERENT
|
|
// meaning than the index in the cache.
|
|
// - Please LEAVE this for irenef to fix before beta2.
|
|
//
|
|
|
|
HRESULT
|
|
CPropertyCache::getproperty(
|
|
DWORD dwIndex,
|
|
VARIANT *pVarResult,
|
|
CCredentials &Credentials
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwStatus = 0;
|
|
|
|
// Ideally we need to get rid of this but this would mean that
|
|
// we need to change the cdispmgr code and the IPropertyCache
|
|
// interface.
|
|
hr = getproperty(
|
|
dwIndex,
|
|
&dwStatus,
|
|
pVarResult,
|
|
Credentials
|
|
);
|
|
|
|
if (hr == E_ADS_PROPERTY_NOT_FOUND)
|
|
{
|
|
hr = DISP_E_MEMBERNOTFOUND;
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::putproperty
|
|
//
|
|
// Synopsis: Updates a property in the property cache.
|
|
// The property is specified by its index in the array of
|
|
// properties (which is also its DISPID), and the new value
|
|
// is given by a VARIANT.
|
|
//
|
|
// Arguments: [dwIndex] -- Index of the property.
|
|
// [varValue] -- Value of the property.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::putproperty(
|
|
DWORD dwIndex,
|
|
VARIANT vValue
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
LDAPOBJECTARRAY LdapObjectArray;
|
|
DWORD dwLdapType;
|
|
|
|
LDAPOBJECTARRAY_INIT(LdapObjectArray);
|
|
|
|
VARIANT *pvValue = &vValue, *pvArray = NULL;
|
|
DWORD dwNumValues = 1;
|
|
|
|
//
|
|
// This should not return E_ADS_PROPERTY_NOT_FOUND in this case.
|
|
// We have an index, which should indicate that we have an array entry.
|
|
// If we weren't dealing with VB, I'd be tempted to make this an Assert.
|
|
//
|
|
if (!index_valid(dwIndex))
|
|
BAIL_ON_FAILURE(hr = DISP_E_MEMBERNOTFOUND);
|
|
|
|
|
|
//
|
|
// If we get a safe array of variants, convert it to a regular array
|
|
// of variants, so we can pass the first one to GetLdapSyntaxFromVariant.
|
|
// We assume that all the elements of the array are of the same type
|
|
//
|
|
if (V_VT(pvValue) == (VT_VARIANT|VT_ARRAY))
|
|
{
|
|
hr = ConvertSafeArrayToVariantArray(vValue, &pvArray, &dwNumValues);
|
|
BAIL_ON_FAILURE(hr);
|
|
pvValue = pvArray;
|
|
}
|
|
|
|
//
|
|
// - dwLdapType in cache can be LDAPTYPE_UNKNOWN.
|
|
// - for consistency btw this function and Put/PutEx, will
|
|
// get type from input VARIANT and overwrite existing type in
|
|
// cache if any
|
|
//
|
|
|
|
ADsAssert(_pCredentials);
|
|
|
|
hr = GetLdapSyntaxFromVariant(
|
|
pvValue,
|
|
&dwLdapType,
|
|
_pszServerName,
|
|
(_pProperties+dwIndex)->szPropertyName,
|
|
*_pCredentials,
|
|
_dwPort
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = VarTypeToLdapTypeCopyConstruct(
|
|
_pszServerName,
|
|
*_pCredentials,
|
|
dwLdapType,
|
|
pvValue,
|
|
dwNumValues,
|
|
&LdapObjectArray
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = putproperty(dwIndex, PROPERTY_UPDATE, dwLdapType, LdapObjectArray);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
// if (hr == E_ADS_CANT_CONVERT_DATATYPE)
|
|
// hr = DISP_E_TYPEMISMATCH;
|
|
|
|
LdapTypeFreeLdapObjects(&LdapObjectArray);
|
|
|
|
if (pvArray) {
|
|
|
|
for (DWORD i=0; i < dwNumValues; i++) {
|
|
VariantClear(pvArray + i);
|
|
}
|
|
|
|
FreeADsMem(pvArray);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// This method is called by _pCoreADsObject->GetInfo(). It signifies
|
|
// exactly that the property cache has been filled with all the data
|
|
// the server has, i.e. that a GetInfo() has been done. When this is
|
|
// set, further implicit calls to GetInfo are skipped. This flag is
|
|
// cleared only by "flushpropertycache".
|
|
//
|
|
void
|
|
CPropertyCache::setGetInfoFlag()
|
|
{
|
|
_fGetInfoDone = TRUE;
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: CPropertyCache::findproperty
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments: [szPropertyName] --
|
|
// [pdwIndex] --
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::
|
|
DispatchFindProperty(
|
|
LPWSTR szPropertyName,
|
|
PDWORD pdwIndex
|
|
)
|
|
{
|
|
DWORD i = 0;
|
|
PDISPPROPERTY pThisDispProperty = NULL;
|
|
|
|
for (i = 0; i < _dwDispMaxProperties; i++) {
|
|
|
|
pThisDispProperty = _pDispProperties + i;
|
|
|
|
if (!_wcsicmp(pThisDispProperty->szPropertyName, szPropertyName)) {
|
|
*pdwIndex = i;
|
|
RRETURN(S_OK);
|
|
}
|
|
}
|
|
|
|
*pdwIndex = 0;
|
|
RRETURN(E_ADS_PROPERTY_NOT_FOUND);
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// Function: CPropertyCache::GetPropertyNames.
|
|
//
|
|
// Synopsis: Gets a list of the names of the properties in this object.
|
|
//
|
|
// Arguments: ppUmiPropVals - Contains the return value.
|
|
//
|
|
// Returns: S_OK, or any appropriate error code.
|
|
//
|
|
// Modifies: N/A.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
CPropertyCache::GetPropertyNames(
|
|
UMI_PROPERTY_VALUES **ppUmiPropVals
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PUMI_PROPERTY_VALUES pUmiPropVals = NULL;
|
|
PUMI_PROPERTY pUmiProps = NULL;
|
|
PPROPERTY pNextProperty = NULL;
|
|
DWORD dwCtr = 0;
|
|
|
|
ADsAssert(ppUmiPropVals);
|
|
|
|
//
|
|
// Always have only 1 value.
|
|
//
|
|
pUmiPropVals = (PUMI_PROPERTY_VALUES)
|
|
AllocADsMem(sizeof(UMI_PROPERTY_VALUES));
|
|
if (!pUmiPropVals) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
if (!_dwMaxProperties) {
|
|
//
|
|
// No properties, we need to special case this.
|
|
//
|
|
*ppUmiPropVals = pUmiPropVals;
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
pUmiProps = (PUMI_PROPERTY) AllocADsMem(
|
|
_dwMaxProperties * sizeof(UMI_PROPERTY)
|
|
);
|
|
|
|
if (!pUmiProps) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
|
|
for(dwCtr = 0; dwCtr < _dwMaxProperties; dwCtr++) {
|
|
pNextProperty = _pProperties + dwCtr;
|
|
|
|
pUmiProps[dwCtr].pszPropertyName =
|
|
(LPWSTR) AllocADsStr(pNextProperty->szPropertyName);
|
|
if(pUmiProps[dwCtr].pszPropertyName == NULL) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
pUmiProps[dwCtr].uCount = 0;
|
|
//
|
|
// Put correct operation type
|
|
//
|
|
hr = ConvertLdapCodeToUmiPropCode(
|
|
pNextProperty->dwFlags,
|
|
pUmiProps[dwCtr].uOperationType
|
|
);
|
|
//
|
|
// Verify that this is the right thing to do.
|
|
//
|
|
pUmiProps[dwCtr].uType = UMI_TYPE_NULL;
|
|
}
|
|
|
|
pUmiPropVals->uCount = _dwMaxProperties;
|
|
pUmiPropVals->pPropArray = pUmiProps;
|
|
|
|
*ppUmiPropVals = pUmiPropVals;
|
|
|
|
RRETURN(S_OK);
|
|
|
|
error:
|
|
|
|
if(pUmiProps != NULL) {
|
|
for(dwCtr = 0; dwCtr < _dwMaxProperties; dwCtr++) {
|
|
if(pUmiProps[dwCtr].pszPropertyName != NULL) {
|
|
FreeADsStr(pUmiProps[dwCtr].pszPropertyName);
|
|
}
|
|
}
|
|
FreeADsMem(pUmiProps);
|
|
}
|
|
|
|
if (pUmiProps) {
|
|
FreeADsMem(pUmiPropVals);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
AddSavingEntry(
|
|
LPWSTR propertyName
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PSAVINGENTRY tempEntry = NULL;
|
|
BOOL fResult = FALSE;
|
|
|
|
fResult = FindSavingEntry(propertyName);
|
|
|
|
if(!fResult) {
|
|
tempEntry = new SAVINGENTRY;
|
|
if(!tempEntry) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
tempEntry->entryData = AllocADsStr(propertyName);
|
|
if(!(tempEntry->entryData)) {
|
|
hr = E_OUTOFMEMORY;
|
|
delete tempEntry;
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
InsertTailList( &_ListSavingEntries, &tempEntry->ListEntry );
|
|
}
|
|
|
|
error:
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
BOOL
|
|
CPropertyCache::
|
|
FindSavingEntry(
|
|
LPWSTR propertyName
|
|
)
|
|
{
|
|
PLIST_ENTRY listEntry = NULL;
|
|
PSAVINGENTRY EntryInfo = NULL;
|
|
BOOL fResult = FALSE;
|
|
|
|
listEntry = _ListSavingEntries.Flink;
|
|
while (listEntry != &_ListSavingEntries) {
|
|
EntryInfo = CONTAINING_RECORD( listEntry, SAVINGENTRY, ListEntry );
|
|
if (!_wcsicmp(EntryInfo->entryData, propertyName)) {
|
|
fResult = TRUE;
|
|
break;
|
|
}
|
|
|
|
listEntry = listEntry->Flink;
|
|
}
|
|
|
|
return fResult;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CPropertyCache::
|
|
DeleteSavingEntry()
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
PSAVINGENTRY EntryInfo;
|
|
|
|
while (!IsListEmpty (&_ListSavingEntries)) {
|
|
pEntry = RemoveHeadList (&_ListSavingEntries);
|
|
EntryInfo = CONTAINING_RECORD (pEntry, SAVINGENTRY, ListEntry);
|
|
|
|
if(EntryInfo->entryData) {
|
|
FreeADsStr(EntryInfo->entryData);
|
|
EntryInfo->entryData = NULL;
|
|
}
|
|
|
|
delete EntryInfo;
|
|
}
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
|