|
|
//
// 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
HRESULT CLDAPGenObject::get_PropertyCount( THIS_ long FAR *plCount ) { HRESULT hr = E_FAIL;
BSTR bstrProperty = NULL; SAFEARRAY *psaProperty = NULL; SAFEARRAYBOUND rgsabound[1]; long lsaDim[1]; VARIANT varProperty;
// ??? _pPropertyCache canNOT be NULL or bailed out during
// CLDAPGenObject creation already
// assert(_PropertyCache);
if (_pPropertyCache) { hr = _pPropertyCache->get_PropertyCount((PDWORD)plCount); }
RRETURN_EXP_IF_ERR(hr);
}
////////////////////////////////////////////////////////////////////////////
//
// - Return the "next" item (item with the current index) in cache, if any,
// in a property entry [*pVariant].
// - Return E_ADS_PROPERTY_NOT_FOUND when current index is out of bound.
//
////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CLDAPGenObject::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;
if(!_pPropertyCache->index_valid()) RRETURN_EXP_IF_ERR(E_FAIL);
LDAPOBJECTARRAY_INIT(ldapSrcObjects);
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 sucess of Skip().
//
Skip(1);
LdapTypeFreeLdapObjects(&ldapSrcObjects);
RRETURN_EXP_IF_ERR(hr); }
STDMETHODIMP CLDAPGenObject::Skip( THIS_ long cElements ) { HRESULT hr = S_OK;
hr = _pPropertyCache->skip_propindex( cElements ); RRETURN_EXP_IF_ERR(hr); }
STDMETHODIMP CLDAPGenObject::Reset(
) { _pPropertyCache->reset_propindex();
RRETURN_EXP_IF_ERR(S_OK); }
STDMETHODIMP CLDAPGenObject::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); }
//////////////////////////////////////////////////////////////////////////
//
// Retrieve property [bstrName] from the cache (only, no wire calls) as
// a PropertyEntry.
//
// [*pVariant]
// - store ptr to IDispatch of the PropertyEntry.
//
// If the property in cache has control code = ADS_PROPERTY_DELETE,
// - PropertyEntry will contain an empty variant and
// - adstype = ADSTYPE_INVALID.
//
// If property in cache has UNKNWON type, (not deleted, for schemaless-server
// property which is not in ADSI default schema)
// - [lnAdsType] must be a valid type (NO ADSTYPE_UNKNWON/INVALID)
// - property will be retrieved as [lnADsType]
//
// If property in cache has KNOWN type,
// - [lnADsType] must either match type in cache or == ADSTYPE_UNKNOWN
// - property will be retreived as the type in cache.
//
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CLDAPGenObject::GetPropertyItem( THIS_ IN BSTR bstrName, IN LONG lnADsType, IN OUT VARIANT * pVariant ) { HRESULT hr = S_OK; DWORD dwCachedSyntax = LDAPTYPE_UNKNOWN; DWORD dwUserSyntax = LDAPTYPE_UNKNOWN; DWORD dwSyntaxUsed = LDAPTYPE_UNKNOWN; // extra, make code easier to read
DWORD dwPropStatus = 0; DWORD dwCtrlCode = 0; LDAPOBJECTARRAY ldapSrcObjects; LDAPOBJECTARRAY ldapSrc2Objects; LDAPOBJECTARRAY * pLdapSrcObjects = NULL;
LDAPOBJECTARRAY_INIT(ldapSrcObjects); LDAPOBJECTARRAY_INIT(ldapSrc2Objects);
if (!bstrName || !pVariant) RRETURN(E_ADS_BAD_PARAMETER);
//
// retrieve property from cache; CONTINUE if property exist but
// has no value (control code flag as a DELETE)
//
hr = _pPropertyCache->unboundgetproperty( bstrName, &dwCachedSyntax, &dwPropStatus, &ldapSrcObjects ); BAIL_ON_FAILURE(hr);
// For backward compatibility -- no issue as you
// need to return a value even if it is delete.
//
// map adstype from client to ldap type;
//
dwUserSyntax = MapADSTypeToLDAPType((ADSTYPE)lnADsType);
//
// determine the syntax to retrieve property in
//
if ( (dwCachedSyntax == LDAPTYPE_UNKNOWN) || (dwCachedSyntax == 0) // should NOT be 0, but misuse of 0 everywhere
) // and in case i didn't clean up all
{ //
// syntax not stored in cache, user must spcify a valid sytax
// Exception: cleared property values have LDAPTYPE_UNKNOWN, and we
// return them as ADSTYPE_UNKNOWN
//
if ((dwUserSyntax == LDAPTYPE_UNKNOWN) && (dwPropStatus != PROPERTY_DELETE)) { hr = E_ADS_CANT_CONVERT_DATATYPE; BAIL_ON_FAILURE(hr); }
dwSyntaxUsed = dwUserSyntax;
//
// convert from cached data from ldap binary format to ldap string
// IFF necessary based on dwUserSyntax
//
hr = LdapTypeBinaryToString( dwSyntaxUsed, &ldapSrcObjects, &ldapSrc2Objects );
//
// dwSyntaxUsed (dwUserSyntax) must be valid from
// MapADSTypeToLDAPType() or code bug in MapADsTypeToLDAPType() !!
//
ADsAssert(SUCCEEDED(hr));
if (hr==S_OK) { pLdapSrcObjects = &ldapSrc2Objects; // conversion done
} else // hr == S_FALSE
{ pLdapSrcObjects = &ldapSrcObjects; // no conversion
} }
else // dwCachedSyntax known and valid
{ //
// syntax stored in cache, user MUST either specify
// 1) ADSTYPE_UNKNWON or
// 2) a syntax which matches the one in cache. The comparision must
// be done in ADsType, not LdapType, since LdapType To ADSType
// is n to 1 mapping and as long as ADsType match, ok.
//
if ( ! ( (dwUserSyntax == LDAPTYPE_UNKNOWN) || ( (ADSTYPE) lnADsType == MapLDAPTypeToADSType(dwCachedSyntax)) ) ) {
if (dwUserSyntax != dwCachedSyntax) {
//
// Check if the user wants the data back for the
// security descriptor as an octet or vice versa
//
if ( (dwUserSyntax == LDAPTYPE_OCTETSTRING && dwCachedSyntax == LDAPTYPE_SECURITY_DESCRIPTOR) ||(dwUserSyntax == LDAPTYPE_SECURITY_DESCRIPTOR && dwCachedSyntax == LDAPTYPE_OCTETSTRING)) { dwCachedSyntax = dwUserSyntax;
} else { //
// Check for UTC/GenTime mismatch before ret error.
//
if (!((dwCachedSyntax == LDAPTYPE_GENERALIZEDTIME) && (dwUserSyntax == LDAPTYPE_UTCTIME))) {
hr = E_ADS_CANT_CONVERT_DATATYPE; BAIL_ON_FAILURE(hr); } } } // if dwUserSyntax != dwCachedSyntax
}
dwSyntaxUsed = dwCachedSyntax;
pLdapSrcObjects = &ldapSrcObjects; // no conversion needed
}
//
// translate ldap prop status to ads control code
//
dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
//
// translate the property from Ldap objects to a PropertyEntry
//
hr = ConvertLdapValuesToVariant( bstrName, pLdapSrcObjects, dwSyntaxUsed, dwCtrlCode, pVariant, _pszLDAPServer, &_Credentials );
error:
LdapTypeFreeLdapObjects( &ldapSrcObjects ); LdapTypeFreeLdapObjects( &ldapSrc2Objects );
RRETURN_EXP_IF_ERR(hr); }
STDMETHODIMP CLDAPGenObject::PutPropertyItem( THIS_ VARIANT varData ) { HRESULT hr = S_OK; DWORD dwFlags = 0;
DWORD dwIndex = 0; DWORD dwControlCode = 0; LDAPOBJECTARRAY ldapDestObjects; WCHAR* pszPropertyName = NULL; DWORD dwSyntaxId = 0;
LDAPOBJECTARRAY_INIT(ldapDestObjects);
hr = ConvertVariantToLdapValues( varData, &pszPropertyName, &dwControlCode, &ldapDestObjects, &dwSyntaxId, _pszLDAPServer, &_Credentials, _dwPort ); BAIL_ON_FAILURE(hr);
switch ( dwControlCode ) {
case 0 : //
// Users better know what they are doing here,
// This the property as cleared so we do not send it
// on the wire on th next SetInfo.
//
dwFlags = PROPERTY_INIT; break;
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
//
dwFlags = PROPERTY_ADD; break;
case ADS_PROPERTY_DELETE: //
// Delete a value(s) from the property
dwFlags = PROPERTY_DELETE_VALUE; break;
default: BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); }
//
// Find this property in the cache
//
hr = _pPropertyCache->findproperty( pszPropertyName, &dwIndex );
//
// If this property does not exist in the
// cache, add this property into the cache.
//
if (FAILED(hr)) {
hr = _pPropertyCache->addproperty( pszPropertyName );
//
// 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( pszPropertyName, dwFlags, dwSyntaxId, ldapDestObjects ); BAIL_ON_FAILURE(hr);
error:
LdapTypeFreeLdapObjects( &ldapDestObjects );
if(pszPropertyName) { FreeADsStr(pszPropertyName); }
RRETURN_EXP_IF_ERR(hr); }
HRESULT CreatePropEntry( LPWSTR szPropName, DWORD ADsType, DWORD numValues, DWORD dwOperation, VARIANT varData, REFIID riid, LPVOID * ppDispatch )
{ HRESULT hr = S_OK; IADsPropertyEntry * pPropEntry = NULL;
hr = CoCreateInstance( CLSID_PropertyEntry, NULL, CLSCTX_INPROC_SERVER, IID_IADsPropertyEntry, (void **)&pPropEntry ); BAIL_ON_FAILURE(hr);
hr = pPropEntry->put_Name(szPropName);
BAIL_ON_FAILURE(hr);
hr = pPropEntry->put_ADsType(ADsType);
BAIL_ON_FAILURE(hr);
hr = pPropEntry->put_Values(varData);
BAIL_ON_FAILURE(hr);
if (dwOperation) { hr = pPropEntry->put_ControlCode((long)dwOperation); }
BAIL_ON_FAILURE(hr);
hr = pPropEntry->QueryInterface( riid, ppDispatch ); BAIL_ON_FAILURE(hr);
error:
if (pPropEntry) { pPropEntry->Release(); }
RRETURN(hr);
}
STDMETHODIMP CLDAPGenObject::Item( THIS_ VARIANT varIndex, VARIANT * pVariant )
{ HRESULT hr = S_OK; DWORD dwSyntaxId; LDAPOBJECTARRAY ldapSrcObjects; PADSVALUE pAdsValues = NULL; DWORD dwNumAdsValues = 0; DWORD dwAdsType = 0; DWORD dwNumValues = 0; LPWSTR szPropName = NULL; DWORD dwPropStatus = 0; DWORD dwCtrlCode = (DWORD) -1; VARIANT * pvVar = &varIndex;
LDAPOBJECTARRAY_INIT(ldapSrcObjects);
//
// retrieve data object from cache; if one exis
//
// If the object has been deleted (and is in the cache
// marked for deletion), we return
// the item with DELETE ctrl code in all
// the cases below. This is consistent with GetPropertyItem's
// behavior as well.
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
//
hr = _pPropertyCache->unboundgetproperty( V_BSTR(pvVar), &dwSyntaxId, &dwPropStatus, &ldapSrcObjects ); BAIL_ON_FAILURE(hr);
dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
hr = ConvertLdapValuesToVariant( V_BSTR(pvVar), &ldapSrcObjects, dwSyntaxId, dwCtrlCode, pVariant, _pszLDAPServer, &_Credentials );
BAIL_ON_FAILURE(hr);
break;
case VT_I4:
hr = _pPropertyCache->unboundgetproperty( (DWORD)V_I4(pvVar), &dwSyntaxId, &dwPropStatus, &ldapSrcObjects ); BAIL_ON_FAILURE(hr);
szPropName = _pPropertyCache->get_PropName( (DWORD)V_I4(pvVar) );
dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
hr = ConvertLdapValuesToVariant( szPropName, &ldapSrcObjects, dwSyntaxId, dwCtrlCode, pVariant, _pszLDAPServer, &_Credentials );
BAIL_ON_FAILURE(hr);
break;
case VT_I2:
hr = _pPropertyCache->unboundgetproperty( (DWORD)V_I2(pvVar), &dwSyntaxId, &dwPropStatus, &ldapSrcObjects ); BAIL_ON_FAILURE(hr);
szPropName = _pPropertyCache->get_PropName( (DWORD)V_I2(pvVar) );
dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
hr = ConvertLdapValuesToVariant( szPropName, &ldapSrcObjects, dwSyntaxId, dwCtrlCode, pVariant, _pszLDAPServer, &_Credentials ); BAIL_ON_FAILURE(hr);
break;
default: hr = E_FAIL; BAIL_ON_FAILURE(hr);
}
//
// translate the Ldap objects to variants
//
error: LdapTypeFreeLdapObjects( &ldapSrcObjects );
RRETURN_EXP_IF_ERR(hr); }
STDMETHODIMP CLDAPGenObject::PurgePropertyList() { _pPropertyCache->flushpropertycache(); RRETURN(S_OK); }
DWORD MapPropCacheFlagToControlCode( DWORD dwPropStatus ) { DWORD dwADsCtrlCode = (DWORD) -1;
switch (dwPropStatus) {
case PROPERTY_INIT: //
// 0 is not defined as any of the ADS_PROPERTY_ flags
// use it to indicate that property is in init state
//
dwADsCtrlCode = 0; break;
case PROPERTY_UPDATE: dwADsCtrlCode = ADS_PROPERTY_UPDATE; break;
case PROPERTY_ADD: dwADsCtrlCode = ADS_PROPERTY_APPEND; break;
case PROPERTY_DELETE: dwADsCtrlCode = ADS_PROPERTY_CLEAR; break;
case PROPERTY_DELETE_VALUE: dwADsCtrlCode = ADS_PROPERTY_DELETE; break;
default: // set to speical value to indicate unknow code
dwADsCtrlCode = (DWORD) -1; break; }
return dwADsCtrlCode; }
|