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