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