//--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1996 // // File: cgenobj.cxx // // Contents: Microsoft ADs LDAP Provider Generic Object // // // History: 08-30-96 yihsins Created. // //---------------------------------------------------------------------------- #include "ldap.hxx" #pragma hdrstop // Class CLDAPRootDSE DEFINE_IDispatch_Implementation(CLDAPRootDSE) DEFINE_IADs_Implementation(CLDAPRootDSE) CLDAPRootDSE::CLDAPRootDSE(): _pPropertyCache( NULL ), _pDispMgr( NULL ), _pszLDAPServer(NULL), _pszLDAPDn(NULL), _pLdapHandle( NULL ) { VariantInit(&_vFilter); VariantInit(&_vHints); ENLIST_TRACKING(CLDAPRootDSE); } HRESULT CLDAPRootDSE::CreateRootDSE( BSTR Parent, BSTR CommonName, BSTR LdapClassName, CCredentials& Credentials, DWORD dwObjectState, REFIID riid, void **ppvObj ) { CLDAPRootDSE FAR * pGenObject = NULL; HRESULT hr = S_OK; hr = AllocateGenObject(Credentials, &pGenObject); BAIL_ON_FAILURE(hr); hr = pGenObject->InitializeCoreObject( Parent, CommonName, LdapClassName, CLSID_LDAPGenObject, dwObjectState ); BAIL_ON_FAILURE(hr); hr = BuildLDAPPathFromADsPath2( pGenObject->_ADsPath, &pGenObject->_pszLDAPServer, &pGenObject->_pszLDAPDn, &pGenObject->_dwPort ); BAIL_ON_FAILURE(hr); // // At this point update the info in the property cache // pGenObject->_pPropertyCache->SetObjInformation( &(pGenObject->_Credentials), pGenObject->_pszLDAPServer, pGenObject->_dwPort ); BAIL_ON_FAILURE(hr); hr = LdapOpenObject( pGenObject->_pszLDAPServer, NULL, &(pGenObject->_pLdapHandle), pGenObject->_Credentials, pGenObject->_dwPort ); BAIL_ON_FAILURE(hr); if (Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) { // // From Umi so we need to return UMI Object not RootDSE. // hr = ((CCoreADsObject*)pGenObject)->InitUmiObject( IntfPropsGeneric, pGenObject->_pPropertyCache, (IADs*) pGenObject, (IADs*) pGenObject, riid, ppvObj, &(pGenObject->_Credentials), pGenObject->_dwPort, pGenObject->_pszLDAPServer, NULL, pGenObject->_pLdapHandle ); BAIL_ON_FAILURE(hr); RRETURN(S_OK); } hr = pGenObject->QueryInterface(riid, ppvObj); BAIL_ON_FAILURE(hr); pGenObject->Release(); RRETURN(hr); error: *ppvObj = NULL; delete pGenObject; RRETURN_EXP_IF_ERR(hr); } CLDAPRootDSE::~CLDAPRootDSE( ) { VariantClear(&_vFilter); VariantClear(&_vHints); if ( _pLdapHandle ) { LdapCloseObject(_pLdapHandle); _pLdapHandle = NULL; } if (_pszLDAPServer) { FreeADsStr(_pszLDAPServer); _pszLDAPServer = NULL; } if (_pszLDAPDn) { FreeADsStr(_pszLDAPDn); _pszLDAPDn = NULL; } delete _pDispMgr; delete _pPropertyCache; } STDMETHODIMP CLDAPRootDSE::QueryInterface(REFIID iid, LPVOID FAR* ppv) { if (ppv == NULL) { RRETURN(E_POINTER); } if (IsEqualIID(iid, IID_IUnknown)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_IADs)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_IDispatch)) { *ppv = (IADs FAR *) this; } else if (IsEqualIID(iid, IID_IADsPropertyList)) { *ppv = (IADsPropertyList FAR *) this; } else if (IsEqualIID(iid, IID_IADsObjectOptions)) { *ppv = (IADsObjectOptions FAR *) this; } else if (IsEqualIID(iid, IID_ISupportErrorInfo)) { *ppv = (ISupportErrorInfo FAR *) this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return NOERROR; } HRESULT CLDAPRootDSE::SetInfo() { HRESULT hr = S_OK; if (GetObjectState() == ADS_OBJECT_UNBOUND) { // // No concept of creating RootDSE objects // Any DS must have a RootDSE object // hr = E_FAIL; BAIL_ON_FAILURE(hr); // // If the create succeded, set the object type to bound // SetObjectState(ADS_OBJECT_BOUND); }else { hr = LDAPSetObject(); BAIL_ON_FAILURE(hr); } error: RRETURN_EXP_IF_ERR(hr); } HRESULT CLDAPRootDSE::LDAPSetObject() { HRESULT hr = S_OK; LDAPModW **aMod = NULL; BOOL fNTSecDes = FALSE; SECURITY_INFORMATION NewSeInfo; hr = _pPropertyCache->LDAPMarshallProperties( &aMod, &fNTSecDes, &NewSeInfo ); BAIL_ON_FAILURE(hr); if ( aMod == NULL ) // There are no changes that needs to be modified RRETURN(S_OK); hr = LdapModifyS( _pLdapHandle, NULL, aMod ); BAIL_ON_FAILURE(hr); // We are successful at this point, // So, clean up the flags in the cache so the same operation // won't be repeated on the next SetInfo() _pPropertyCache->ClearAllPropertyFlags(); error: if (aMod) { if ( *aMod ) FreeADsMem( *aMod ); FreeADsMem( aMod ); } RRETURN_EXP_IF_ERR(hr); } HRESULT CLDAPRootDSE::InterfaceSupportsErrorInfo(THIS_ REFIID riid) { if (IsEqualIID(riid, IID_IADs) || IsEqualIID(riid, IID_IADsPropertyList)) { RRETURN(S_OK); } else { RRETURN(S_FALSE); } } HRESULT CLDAPRootDSE::GetInfo() { RRETURN(GetInfo(GETINFO_FLAG_EXPLICIT)); } HRESULT CLDAPRootDSE::GetInfo( DWORD dwFlags ) { HRESULT hr = S_OK; DWORD dwSyntaxId = ADSTYPE_CASE_IGNORE_STRING; LDAPMessage *res = NULL; if (dwFlags == GETINFO_FLAG_IMPLICIT_AS_NEEDED) { if (_pPropertyCache->getGetInfoFlag()) { // // Nothing to do in this case. // RRETURN(S_OK); } } if (GetObjectState() == ADS_OBJECT_UNBOUND) { hr = E_ADS_OBJECT_UNBOUND; BAIL_ON_FAILURE(hr); } hr = LdapSearchS( _pLdapHandle, NULL, LDAP_SCOPE_BASE, TEXT("(objectClass=*)"), NULL, 0, &res ); BAIL_ON_FAILURE(hr); if ( dwFlags == GETINFO_FLAG_EXPLICIT ) { // If this is an explicit GetInfo, // delete the old cache and start a new cache from scratch. _pPropertyCache->flushpropertycache(); } hr = _pPropertyCache->LDAPUnMarshallPropertiesAs( _pszLDAPServer, _pLdapHandle, res, dwSyntaxId, (dwFlags == GETINFO_FLAG_EXPLICIT) ? TRUE : FALSE, _Credentials ); BAIL_ON_FAILURE(hr); _pPropertyCache->setGetInfoFlag(); error: if (res) { LdapMsgFree( res ); } RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved) { RRETURN_EXP_IF_ERR(E_NOTIMPL); } HRESULT CLDAPRootDSE::AllocateGenObject( CCredentials& Credentials, CLDAPRootDSE ** ppGenObject ) { CLDAPRootDSE FAR * pGenObject = NULL; CAggregatorDispMgr FAR * pDispMgr = NULL; CPropertyCache FAR * pPropertyCache = NULL; HRESULT hr = S_OK; pGenObject = new CLDAPRootDSE(); if (pGenObject == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); pDispMgr = new CAggregatorDispMgr(Credentials); if (pDispMgr == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr); hr = pDispMgr->LoadTypeInfoEntry( LIBID_ADs, IID_IADs, (IADs *)pGenObject, DISPID_REGULAR ); BAIL_ON_FAILURE(hr); hr = pDispMgr->LoadTypeInfoEntry( LIBID_ADs, IID_IADsPropertyList, (IADsPropertyList *)pGenObject, DISPID_VALUE ); BAIL_ON_FAILURE(hr); hr = pDispMgr->LoadTypeInfoEntry( LIBID_ADs, IID_IADsObjectOptions, (IADsObjectOptions *)pGenObject, DISPID_VALUE ); BAIL_ON_FAILURE(hr); hr = CPropertyCache::createpropertycache( (CCoreADsObject FAR *) pGenObject, (IGetAttributeSyntax *) pGenObject, &pPropertyCache ); BAIL_ON_FAILURE(hr); pDispMgr->RegisterPropertyCache(pPropertyCache); pGenObject->_Credentials = Credentials; pGenObject->_pPropertyCache = pPropertyCache; pGenObject->_pDispMgr = pDispMgr; *ppGenObject = pGenObject; RRETURN(hr); error: delete pDispMgr; delete pGenObject; RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::Get( THIS_ BSTR bstrName, VARIANT FAR* pvProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId; DWORD dwStatus = 0; LDAPOBJECTARRAY ldapSrcObjects; LDAPOBJECTARRAY_INIT(ldapSrcObjects); // // For some folks who have no clue what they are doing. // if (!pvProp) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } // // retrieve data object from cache; if one exists // if ( GetObjectState() == ADS_OBJECT_UNBOUND ) { hr = _pPropertyCache->unboundgetproperty( bstrName, &dwSyntaxId, &dwStatus, &ldapSrcObjects ); // For backward compatibility if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) { hr = E_FAIL; } } else { hr = _pPropertyCache->getproperty( bstrName, &dwSyntaxId, &dwStatus, &ldapSrcObjects ); // For backward compatibility if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) { hr = E_ADS_PROPERTY_NOT_FOUND; } } BAIL_ON_FAILURE(hr); // // translate the Ldap objects to variants // if ( ldapSrcObjects.dwCount == 1 ) { hr = LdapTypeToVarTypeCopy( _pszLDAPServer, _Credentials, ldapSrcObjects.pLdapObjects, dwSyntaxId, pvProp ); } else { hr = LdapTypeToVarTypeCopyConstruct( _pszLDAPServer, _Credentials, ldapSrcObjects, dwSyntaxId, pvProp ); } BAIL_ON_FAILURE(hr); error: LdapTypeFreeLdapObjects( &ldapSrcObjects ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::Put( THIS_ BSTR bstrName, VARIANT vProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId = 0; DWORD dwIndex = 0; LDAPOBJECTARRAY ldapDestObjects; DWORD dwNumValues = 0; VARIANT * pVarArray = NULL; VARIANT * pvProp = NULL; VARIANT vDefProp; VariantInit(&vDefProp); LDAPOBJECTARRAY_INIT(ldapDestObjects); // // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY. // We should dereference a VT_BYREF|VT_VARIANT once and see // what's inside. // pvProp = &vProp; if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) { pvProp = V_VARIANTREF(&vProp); } if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) || (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) { hr = ConvertSafeArrayToVariantArray( vProp, &pVarArray, &dwNumValues ); // returns E_FAIL if vProp is invalid if (hr == E_FAIL) hr = E_ADS_BAD_PARAMETER; BAIL_ON_FAILURE(hr); pvProp = pVarArray; } else { // // If this is a single VT_BYREF of a basic type, we dereference // it once. // if (V_ISBYREF(pvProp)) { hr = VariantCopyInd(&vDefProp, pvProp); BAIL_ON_FAILURE(hr); pvProp = &vDefProp; } dwNumValues = 1; } // // check if the variant maps to the syntax of this property // hr = GetLdapSyntaxFromVariant( pvProp, &dwSyntaxId, _pszLDAPServer, bstrName, _Credentials, _dwPort ); BAIL_ON_FAILURE(hr); if ( dwNumValues > 0 ) { hr = VarTypeToLdapTypeCopyConstruct( _pszLDAPServer, _Credentials, dwSyntaxId, pvProp, dwNumValues, &ldapDestObjects ); BAIL_ON_FAILURE(hr); } // // Find this property in the cache // hr = _pPropertyCache->findproperty( bstrName, &dwIndex ); // // If this property does not exist in the // cache, add this property into the cache. // if (FAILED(hr)) { hr = _pPropertyCache->addproperty( bstrName ); // // If dwNumValues == 0 ( delete the property ) but couldn't find // the property, or if the add operation fails, return the error. // BAIL_ON_FAILURE(hr); } // // Now update the property in the cache // hr = _pPropertyCache->putproperty( bstrName, PROPERTY_UPDATE, dwSyntaxId, ldapDestObjects ); BAIL_ON_FAILURE(hr); error: LdapTypeFreeLdapObjects( &ldapDestObjects ); if (pVarArray) { DWORD i = 0; for (i = 0; i < dwNumValues; i++) { VariantClear(pVarArray + i); } FreeADsMem(pVarArray); } RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::GetEx( THIS_ BSTR bstrName, VARIANT FAR* pvProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId; DWORD dwStatus = 0; LDAPOBJECTARRAY ldapSrcObjects; LDAPOBJECTARRAY_INIT(ldapSrcObjects); // // For those who know no not what they do // if (!pvProp) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } // // retrieve data object from cache; if one exists // if ( GetObjectState() == ADS_OBJECT_UNBOUND ) { hr = _pPropertyCache->unboundgetproperty( bstrName, &dwSyntaxId, &dwStatus, &ldapSrcObjects ); // For backward compatibility if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) { hr = E_FAIL; } } else { hr = _pPropertyCache->getproperty( bstrName, &dwSyntaxId, &dwStatus, &ldapSrcObjects ); // For backward compatibility if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) { hr = E_ADS_PROPERTY_NOT_FOUND; } } BAIL_ON_FAILURE(hr); // // translate the Ldap objects to variants // hr = LdapTypeToVarTypeCopyConstruct( _pszLDAPServer, _Credentials, ldapSrcObjects, dwSyntaxId, pvProp ); BAIL_ON_FAILURE(hr); error: LdapTypeFreeLdapObjects( &ldapSrcObjects ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::PutEx( THIS_ long lnControlCode, BSTR bstrName, VARIANT vProp ) { HRESULT hr = S_OK; DWORD dwSyntaxId = 0; DWORD dwFlags = 0; DWORD dwIndex = 0; LDAPOBJECTARRAY ldapDestObjects; DWORD dwNumValues = 0; VARIANT * pVarArray = NULL; VARIANT * pvProp = NULL; LDAPOBJECTARRAY_INIT(ldapDestObjects); switch ( lnControlCode ) { case ADS_PROPERTY_CLEAR: dwFlags = PROPERTY_DELETE; break; case ADS_PROPERTY_APPEND: dwFlags = PROPERTY_ADD; break; case ADS_PROPERTY_UPDATE: dwFlags = PROPERTY_UPDATE; break; default: RRETURN(hr = E_ADS_BAD_PARAMETER); } if ( dwFlags != PROPERTY_DELETE ) { // // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY. // We should dereference a VT_BYREF|VT_VARIANT once and see // what's inside. // pvProp = &vProp; if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) { pvProp = V_VARIANTREF(&vProp); } if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) || (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) { hr = ConvertSafeArrayToVariantArray( *pvProp, &pVarArray, &dwNumValues ); // returns E_FAIL if *pvProp is invalid if (hr == E_FAIL) hr = E_ADS_BAD_PARAMETER; BAIL_ON_FAILURE(hr); pvProp = pVarArray; } else { hr = E_FAIL; BAIL_ON_FAILURE(hr); } // // check if the variant maps to the syntax of this property // // // check if the variant maps to the syntax of this property // hr = GetLdapSyntaxFromVariant( pvProp, &dwSyntaxId, _pszLDAPServer, bstrName, _Credentials, _dwPort ); BAIL_ON_FAILURE(hr); if ( dwNumValues > 0 ) { hr = VarTypeToLdapTypeCopyConstruct( _pszLDAPServer, _Credentials, dwSyntaxId, pvProp, dwNumValues, &ldapDestObjects ); BAIL_ON_FAILURE(hr); } } // // Find this property in the cache // hr = _pPropertyCache->findproperty( bstrName, &dwIndex ); // // If this property does not exist in the // cache, add this property into the cache. // if (FAILED(hr)) { hr = _pPropertyCache->addproperty( bstrName ); // // If dwNumValues == 0 ( delete the property ) but couldn't find // the property, or if the add operation fails, return the error. // BAIL_ON_FAILURE(hr); } // // Now update the property in the cache // hr = _pPropertyCache->putproperty( bstrName, dwFlags, dwSyntaxId, ldapDestObjects ); BAIL_ON_FAILURE(hr); error: LdapTypeFreeLdapObjects( &ldapDestObjects ); if (pVarArray) { DWORD i = 0; for (i = 0; i < dwNumValues; i++) { VariantClear(pVarArray + i); } FreeADsMem(pVarArray); } RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::get_PropertyCount( THIS_ long FAR *plCount ) { HRESULT hr = E_FAIL; if (!plCount) { RRETURN(E_ADS_BAD_PARAMETER); } if (_pPropertyCache) { hr = _pPropertyCache->get_PropertyCount((PDWORD)plCount); } RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::Next( THIS_ VARIANT FAR *pVariant ) { HRESULT hr = E_FAIL; DWORD dwSyntaxId = 0; DWORD dwNumValues = 0; LDAPOBJECTARRAY ldapSrcObjects; IDispatch * pDispatch = NULL; DWORD dwNumAdsValues = 0; DWORD dwAdsType = 0; DWORD dwPropStatus = 0; DWORD dwCtrlCode = 0; LDAPOBJECTARRAY_INIT(ldapSrcObjects); if (!pVariant) { RRETURN(E_ADS_BAD_PARAMETER); } if(!_pPropertyCache->index_valid()) RRETURN_EXP_IF_ERR(E_FAIL); // // retreive the item with current idex; unboundgetproperty() // returns E_ADS_PROPERTY_NOT_FOUND if index out of bound // hr = _pPropertyCache->unboundgetproperty( _pPropertyCache->get_CurrentIndex(), &dwSyntaxId, &dwPropStatus, &ldapSrcObjects ); BAIL_ON_FAILURE(hr); dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus); // // translate the LDAP objects to variants // hr = ConvertLdapValuesToVariant( _pPropertyCache->get_CurrentPropName(), &ldapSrcObjects, dwSyntaxId, dwCtrlCode, pVariant, _pszLDAPServer, &_Credentials ); BAIL_ON_FAILURE(hr); error: // // - goto next one even if error to avoid infinite looping at a property // which we cannot convert (e.g. schemaless server property.) // - do not return the result of Skip() as current operation does not // depend on the success of Skip(). // Skip(1); LdapTypeFreeLdapObjects(&ldapSrcObjects); if (FAILED(hr)) { V_VT(pVariant) = VT_ERROR; } RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::Skip( THIS_ long cElements ) { HRESULT hr = E_FAIL; hr = _pPropertyCache->skip_propindex( cElements ); RRETURN(hr); } STDMETHODIMP CLDAPRootDSE::Reset( ) { _pPropertyCache->reset_propindex(); RRETURN(S_OK); } STDMETHODIMP CLDAPRootDSE::ResetPropertyItem(THIS_ VARIANT varEntry) { HRESULT hr = S_OK; DWORD dwIndex = 0; switch (V_VT(&varEntry)) { case VT_BSTR: hr = _pPropertyCache->findproperty( V_BSTR(&varEntry), &dwIndex ); BAIL_ON_FAILURE(hr); break; case VT_I4: dwIndex = V_I4(&varEntry); break; case VT_I2: dwIndex = V_I2(&varEntry); break; default: hr = E_FAIL; BAIL_ON_FAILURE(hr); } hr = _pPropertyCache->deleteproperty( dwIndex ); error: RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::GetPropertyItem( THIS_ BSTR bstrName, LONG lnType, VARIANT * pVariant ) { HRESULT hr = S_OK; DWORD dwSyntaxId; LDAPOBJECTARRAY ldapSrcObjects; DWORD dwNumValues = 0; DWORD dwUserSyntaxId = 0; DWORD dwStatus = 0; DWORD dwCtrlCode = 0; LDAPOBJECTARRAY_INIT(ldapSrcObjects); // // retrieve data object from cache; do NOT retreive from server // hr = _pPropertyCache->unboundgetproperty( bstrName, &dwSyntaxId, &dwStatus, &ldapSrcObjects ); BAIL_ON_FAILURE(hr); // // translate the Ldap objects to variants // dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus); hr = ConvertLdapValuesToVariant( bstrName, &ldapSrcObjects, dwSyntaxId, dwCtrlCode, pVariant, _pszLDAPServer, &_Credentials ); error: LdapTypeFreeLdapObjects( &ldapSrcObjects ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::PutPropertyItem( THIS_ VARIANT varData ) { HRESULT hr = S_OK; DWORD dwFlags = 0; DWORD dwIndex = 0; DWORD dwControlCode = 0; LDAPOBJECTARRAY ldapDestObjects; WCHAR szPropertyName[MAX_PATH]; DWORD dwSyntaxId = 0; LDAPOBJECTARRAY_INIT(ldapDestObjects); hr = ConvertVariantToLdapValues( varData, szPropertyName, &dwControlCode, &ldapDestObjects, &dwSyntaxId, _pszLDAPServer, &_Credentials, _dwPort ); BAIL_ON_FAILURE(hr); switch ( dwControlCode ) { case ADS_PROPERTY_CLEAR: // // Clears an entire property // dwFlags = PROPERTY_DELETE; break; case ADS_PROPERTY_UPDATE: // // Updates the entire property // dwFlags = PROPERTY_UPDATE; break; case ADS_PROPERTY_APPEND: // // Appends a set of values to the property // break; case ADS_PROPERTY_DELETE: // // Delete a value(s) from the property break; default: BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); } // // Find this property in the cache // hr = _pPropertyCache->findproperty( szPropertyName, &dwIndex ); // // If this property does not exist in the // cache, add this property into the cache. // if (FAILED(hr)) { hr = _pPropertyCache->addproperty( szPropertyName ); // // If dwNumValues == 0 ( delete the property ) but couldn't find // the property, or if the add operation fails, return the error. // BAIL_ON_FAILURE(hr); } // // Now update the property in the cache // hr = _pPropertyCache->putproperty( szPropertyName, dwFlags, dwSyntaxId, ldapDestObjects ); BAIL_ON_FAILURE(hr); error: LdapTypeFreeLdapObjects( &ldapDestObjects ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::Item(THIS_ VARIANT varIndex, VARIANT * pVariant) { HRESULT hr = S_OK; DWORD dwSyntaxId; LDAPOBJECTARRAY ldapSrcObjects; PADSVALUE pAdsValues = NULL; DWORD dwNumValues = 0; DWORD dwNumAdsValues = 0; DWORD dwAdsType = 0; DWORD dwStatus = 0; DWORD dwCtrlCode = 0; VARIANT *pvVar = &varIndex; LPWSTR szPropName = NULL; LDAPOBJECTARRAY_INIT(ldapSrcObjects); // // retrieve data object from cache; if one exis // if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) { // // The value is being passed in byref so we need to // deref it for vbs stuff to work // pvVar = V_VARIANTREF(&varIndex); } switch (V_VT(pvVar)) { case VT_BSTR: // // retrieve data object from cache; if one exists // if ( GetObjectState() == ADS_OBJECT_UNBOUND ) { hr = _pPropertyCache->unboundgetproperty( V_BSTR(pvVar), &dwSyntaxId, &dwStatus, &ldapSrcObjects ); // For backward compatibility -- nothing done, you // should be able to get an item marked as delete. } else { hr = _pPropertyCache->getproperty( V_BSTR(pvVar), &dwSyntaxId, &dwStatus, &ldapSrcObjects ); // For backward compatibility -- nothing done, // you should be able to get an item marked as delete. } BAIL_ON_FAILURE(hr); szPropName = V_BSTR(pvVar); dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus); break; case VT_I4: hr = _pPropertyCache->unboundgetproperty( (DWORD)V_I4(pvVar), &dwSyntaxId, &dwStatus, &ldapSrcObjects ); // For backward compatibility -- nothing done, you // should be able to get an item marked as delte. BAIL_ON_FAILURE(hr); szPropName = _pPropertyCache->get_PropName( (DWORD)V_I4(pvVar) ); dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus); break; case VT_I2: hr = _pPropertyCache->unboundgetproperty( (DWORD)V_I2(pvVar), &dwSyntaxId, &dwStatus, &ldapSrcObjects ); // For backward compatibility -- nothing done, you // should be able to get an item marked as delete. BAIL_ON_FAILURE(hr); szPropName = _pPropertyCache->get_PropName( (DWORD)V_I2(pvVar) ); dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus); break; default: hr = E_FAIL; BAIL_ON_FAILURE(hr); } // // translate the Ldap objects to variants // dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus); hr = ConvertLdapValuesToVariant( szPropName, &ldapSrcObjects, dwSyntaxId, dwCtrlCode, pVariant, _pszLDAPServer, &_Credentials ); error: LdapTypeFreeLdapObjects( &ldapSrcObjects ); RRETURN_EXP_IF_ERR(hr); } STDMETHODIMP CLDAPRootDSE::PurgePropertyList() { _pPropertyCache->flushpropertycache(); RRETURN(S_OK); } STDMETHODIMP CLDAPRootDSE::GetInfo( LPWSTR szPropertyName, DWORD dwSyntaxId, BOOL fExplicit ) { HRESULT hr = S_OK; LDAPMessage *res = NULL; if (GetObjectState() == ADS_OBJECT_UNBOUND) { hr = E_ADS_OBJECT_UNBOUND; BAIL_ON_FAILURE(hr); } hr = LdapSearchS( _pLdapHandle, _pszLDAPDn, LDAP_SCOPE_BASE, TEXT("(objectClass=*)"), NULL, 0, &res ); BAIL_ON_FAILURE(hr); if ( fExplicit ) { // If this is an explicit GetInfo, // delete the old cache and start a new cache from scratch. _pPropertyCache->flushpropertycache(); } hr = _pPropertyCache->LDAPUnMarshallPropertiesAs( _pszLDAPServer, _pLdapHandle, res, ADSTYPE_CASE_IGNORE_STRING, fExplicit, _Credentials ); BAIL_ON_FAILURE(hr); _pPropertyCache->setGetInfoFlag(); error: if (res) { LdapMsgFree( res ); } RRETURN_EXP_IF_ERR(hr); } // // Needed for dynamic dispid's in the property cache. // HRESULT CLDAPRootDSE::GetAttributeSyntax( LPWSTR szPropertyName, PDWORD pdwSyntaxId ) { HRESULT hr; hr = LdapGetSyntaxOfAttributeOnServer( _pszLDAPServer, szPropertyName, pdwSyntaxId, _Credentials, _dwPort ); RRETURN_EXP_IF_ERR(hr); } // // IADsObjecOptions methods // // // Unlike the cgenobj GetOption implementation, this will support // only a subset of the flags - mutual auth status being the only one. // STDMETHODIMP CLDAPRootDSE::GetOption( THIS_ long lnControlCode, VARIANT FAR* pvProp ) { HRESULT hr = S_OK; ULONG ulFlags = 0; CtxtHandle hCtxtHandle; DWORD dwErr = 0; VariantInit(pvProp); switch (lnControlCode) { case ADS_OPTION_MUTUAL_AUTH_STATUS : dwErr = ldap_get_option( _pLdapHandle->LdapHandle, LDAP_OPT_SECURITY_CONTEXT, (void *) &hCtxtHandle ); if (dwErr) { BAIL_ON_FAILURE(hr = E_FAIL); } //DSCLIENT #if (!defined(WIN95)) dwErr = QueryContextAttributesWrapper( &hCtxtHandle, SECPKG_ATTR_FLAGS, (void *) &ulFlags ); if (dwErr) { BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr)); } #else ulFlags = 0; #endif pvProp->vt = VT_I4; pvProp->lVal = ulFlags; break; default: hr = E_NOTIMPL; } error: RRETURN(hr); } STDMETHODIMP CLDAPRootDSE::SetOption( THIS_ long lnControlCode, VARIANT vProp ) { HRESULT hr = S_OK; DWORD dwOptVal = 0; VARIANT *pvProp = NULL; // // To make sure we handle variant by refs correctly. // pvProp = &vProp; if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) { pvProp = V_VARIANTREF(&vProp); } switch (lnControlCode) { case ADS_PRIVATE_OPTION_KEEP_HANDLES : hr = LdapcKeepHandleAround(_pLdapHandle); break; default: hr = E_NOTIMPL; } RRETURN(hr); }