windows-nt/Source/XPSP1/NT/ds/adsi/ldap/cprops.cxx
2020-09-26 16:20:57 +08:00

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