|
|
//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995
//
// File: cggi.cxx
//
// Contents: This file contains the Group Object's
// IADsGroup and IADsGroupOperation methods
//
// History: 11-1-95 krishnag Created.
//
//----------------------------------------------------------------------------
#include "ldap.hxx"
#pragma hdrstop
#include <winldap.h>
#include "..\ldapc\ldpcache.hxx"
#include "..\ldapc\ldaputil.hxx"
#include "..\ldapc\parse.hxx"
HRESULT BuildLDAPPathFromADsPath2( LPWSTR szADsPathName, LPWSTR *pszLDAPServer, LPWSTR *pszLDAPDn, DWORD * pdwPort );
HRESULT LdapGetSyntaxOfAttributeOnServer( LPTSTR pszServerPath, LPTSTR pszAttrName, DWORD *pdwSyntaxId, CCredentials& Credentials, DWORD dwPort, BOOL fFromServer = FALSE );
HRESULT ReadServerSupportsIsADControl( LPWSTR pszLDAPServer, BOOL * pfDomScopeSupported, CCredentials& Credentials, DWORD dwPort );
BOOL VerifyIfMember( BSTR bstrMember, VARIANT * VariantArray, ULONG cElementFetched );
HRESULT ValidateProvider( POBJECTINFO pObjectInfo );
BOOL MapLdapClassToADsClass( LPTSTR *aLdapClasses, int nCount, LPTSTR pszADsClass );
struct _classmapping { LPTSTR pszLdapClassName; LPTSTR pszADsClassName; } aClassMap[] = { { TEXT("user"), USER_CLASS_NAME}, // NTDS
{ TEXT("group"), GROUP_CLASS_NAME}, { TEXT("localGroup"), GROUP_CLASS_NAME}, { TEXT("printQueue"), PRINTER_CLASS_NAME}, { TEXT("country"), TEXT("Country") }, { TEXT("locality"), TEXT("Locality") }, { TEXT("organization"), TEXT("Organization")}, { TEXT("organizationalUnit"), TEXT("Organizational Unit") }, { TEXT("domain"), DOMAIN_CLASS_NAME},
{ TEXT("person"), USER_CLASS_NAME }, { TEXT("organizationalPerson"), USER_CLASS_NAME }, { TEXT("residentialPerson"), USER_CLASS_NAME }, { TEXT("groupOfNames"), GROUP_CLASS_NAME }, { TEXT("groupOfUniqueNames"), GROUP_CLASS_NAME } };
// Class CLDAPGroup
STDMETHODIMP CLDAPGroup::get_Description(THIS_ BSTR FAR* retval) { GET_PROPERTY_BSTR((IADsGroup *)this, description); }
STDMETHODIMP CLDAPGroup::put_Description(THIS_ BSTR bstrdescription) { PUT_PROPERTY_BSTR((IADsGroup *)this, description); }
STDMETHODIMP CLDAPGroup::Members( THIS_ IADsMembers FAR* FAR* ppMembers ) { VARIANT v; HRESULT hr = S_OK; BSTR bstrParent = NULL; BSTR bstrName = NULL; BSTR bstrADsPath = NULL; IADsObjOptPrivate *pPrivOpt = NULL; BOOL fRangeRetrieval = FALSE;
VariantInit(&v); hr = get_VARIANT_Property((IADs *) ((IADsGroup *) this), TEXT("member"), &v );
if ( hr == E_ADS_PROPERTY_NOT_FOUND ) { SAFEARRAY *aList = NULL; SAFEARRAYBOUND aBound;
hr = S_OK;
aBound.lLbound = 0; aBound.cElements = 0;
aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
if ( aList == NULL ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); }
V_VT(&v) = VT_ARRAY | VT_VARIANT; V_ARRAY(&v) = aList; } BAIL_ON_FAILURE(hr);
hr = get_Parent( &bstrParent ); BAIL_ON_FAILURE(hr);
hr = get_Name( &bstrName ); BAIL_ON_FAILURE(hr);
hr = _pADs->get_ADsPath( &bstrADsPath); BAIL_ON_FAILURE(hr);
//
// We need to see if range retrieval was used.
// That info is needed in the enumerator.
//
hr = _pADs->QueryInterface( IID_IADsObjOptPrivate, (void **)&pPrivOpt ); BAIL_ON_FAILURE(hr);
//
// Not a problem if this fails.
//
hr = pPrivOpt->GetOption ( LDAP_MEMBER_HAS_RANGE, (void *) &fRangeRetrieval );
hr = CLDAPGroupCollection::CreateGroupCollection( bstrParent, bstrADsPath, bstrName, &v, _Credentials, _pADs, IID_IADsMembers, fRangeRetrieval, (void **)ppMembers ); BAIL_ON_FAILURE(hr);
error:
if ( bstrParent ) ADsFreeString( bstrParent );
if ( bstrName ) ADsFreeString( bstrName );
if (bstrADsPath) { ADsFreeString( bstrADsPath); }
if (pPrivOpt) { pPrivOpt->Release(); } VariantClear(&v);
RRETURN(hr); }
STDMETHODIMP CLDAPGroup::IsMember( THIS_ BSTR bstrMember, VARIANT_BOOL FAR *bMember ) { HRESULT hr = S_OK;
if (_dwServerType == SERVER_TYPE_UNKNOWN) { hr = UpdateServerType(); //
// The only reason the above call shoudl fail is
// if we could not read the ADsPath of the cgenobj.
//
BAIL_ON_FAILURE(hr); }
if (_dwServerType == SERVER_TYPE_AD) { hr = IsMemberOnAD( bstrMember, bMember ); } else { hr = IsMemberOnOther( bstrMember, bMember ); }
error:
RRETURN(hr); }
//
// Checks membership if the server is AD. This is because
// we know that AD supports the LDAPCompare operation. There
// is just one round trip on the wire this time.
//
HRESULT CLDAPGroup::IsMemberOnAD( THIS_ BSTR bstrMember, VARIANT_BOOL FAR *bMember ) { HRESULT hr = S_OK; PADSLDP pLdp = NULL; BSTR bstrParentADsPath = NULL; IADsObjOptPrivate *pADsPrivateObjectOptions = NULL;
LPWSTR pszGroupServer = NULL, pszGroupDn = NULL; LPWSTR pszMemberServer = NULL, pszMemberDn = NULL; DWORD dwGroupPort = 0, dwMemberPort = 0;
if (!bstrMember || !*bstrMember || !bMember) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); }
//
// Default to this value.
//
*bMember = VARIANT_FALSE;
//
// We need the ADsPath of the parent group object.
// Since the input parameter is an ADsPath, we need to
// make sure that the serverName if any matches before
// going onto doing the LDAPCompare operation on the
// DN to verify if the DN is part of member.
//
hr = _pADs->get_ADsPath(&bstrParentADsPath); BAIL_ON_FAILURE(hr);
//
// Split the path into components we are interesteed in.
//
hr = BuildLDAPPathFromADsPath2( bstrParentADsPath, &pszGroupServer, &pszGroupDn, &dwGroupPort ); BAIL_ON_FAILURE(hr);
hr = BuildLDAPPathFromADsPath2( bstrMember, &pszMemberServer, &pszMemberDn, &dwMemberPort );
BAIL_ON_FAILURE(hr);
if ((pszMemberServer && !pszGroupServer) || (pszGroupServer && !pszMemberServer) || (dwMemberPort != dwGroupPort) || ( (pszMemberServer && pszGroupServer) #ifdef WIN95
&& (_wcsicmp(pszMemberServer, pszGroupServer)) #else
&& (CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, pszMemberServer, -1, pszGroupServer, -1 ) != CSTR_EQUAL) #endif
) ) {
//
// Mismatched paths (e.g., bound to group with a serverless
// path, user is passing in a server path)
//
*bMember = VARIANT_FALSE; hr = E_ADS_BAD_PARAMETER; goto error; }
//
// At this point we have a match on the server names and port.
//
hr = _pADs->QueryInterface( IID_IADsObjOptPrivate, (void **)&pADsPrivateObjectOptions ); BAIL_ON_FAILURE(hr);
hr = pADsPrivateObjectOptions->GetOption ( LDP_CACHE_ENTRY, &pLdp ); BAIL_ON_FAILURE(hr);
//
// We can now do a LDAPCompare to see if the object is a member.
//
hr = LdapCompareExt( pLdp, pszGroupDn, L"member", pszMemberDn, NULL, // Data
NULL, // ClientControls
NULL // ServerControls
);
if (hr == HRESULT_FROM_WIN32(ERROR_DS_COMPARE_FALSE)) { hr = S_OK; *bMember = VARIANT_FALSE; } else if (hr == HRESULT_FROM_WIN32(ERROR_DS_COMPARE_TRUE)) { hr = S_OK; *bMember = VARIANT_TRUE; } else if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE)) { //
// This is also valid as the member attribute might be empty.
//
hr = S_OK; *bMember = VARIANT_FALSE; }
BAIL_ON_FAILURE(hr);
error:
//
// Cleanup all strings that could have been alloced.
//
if (bstrParentADsPath) { ADsFreeString(bstrParentADsPath); }
if (pszGroupServer) { FreeADsStr(pszGroupServer); }
if (pszGroupDn) { FreeADsStr(pszGroupDn); }
if (pszMemberServer) { FreeADsStr(pszMemberServer); }
if (pszMemberDn) { FreeADsStr(pszMemberDn); }
//
// Miscellaneous cleanup.
//
if (pADsPrivateObjectOptions) { pADsPrivateObjectOptions->Release(); }
RRETURN(hr); }
//
// This routine is used if the server is not AD - preserves
// older behaviour. It creates an Enumerator, goes through that
// comparing the paths to see if there is a match. This is
// pretty network intensive.
//
HRESULT CLDAPGroup::IsMemberOnOther( THIS_ BSTR bstrMember, VARIANT_BOOL FAR* bMember ) { IADsMembers FAR * pMembers = NULL; IUnknown FAR * pUnknown = NULL; IEnumVARIANT FAR * pEnumVar = NULL; DWORD i = 0; HRESULT hr = S_OK; VARIANT_BOOL fMember = FALSE; VARIANT VariantArray[10]; BOOL fContinue = TRUE; ULONG cElementFetched = 0;
hr = Members( &pMembers ); BAIL_ON_FAILURE(hr);
hr = pMembers->get__NewEnum( &pUnknown ); BAIL_ON_FAILURE(hr);
hr = pUnknown->QueryInterface( IID_IEnumVARIANT, (void **)&pEnumVar ); BAIL_ON_FAILURE(hr);
while (fContinue) {
IADs *pObject ;
hr = pEnumVar->Next( 10, VariantArray, &cElementFetched );
if (hr == S_FALSE) { fContinue = FALSE;
//
// Reset hr to S_OK, we want to return success
//
hr = S_OK; }
fMember = (VARIANT_BOOL)VerifyIfMember( bstrMember, VariantArray, cElementFetched );
if (fMember) { fContinue = FALSE; }
for (i = 0; i < cElementFetched; i++ ) {
IDispatch *pDispatch = NULL;
pDispatch = VariantArray[i].pdispVal; pDispatch->Release();
}
memset(VariantArray, 0, sizeof(VARIANT)*10);
}
error:
*bMember = fMember? VARIANT_TRUE : VARIANT_FALSE;
if (pEnumVar) { pEnumVar->Release(); }
if (pUnknown) { pUnknown->Release(); }
if (pMembers) { pMembers->Release(); }
RRETURN(hr); }
BOOL VerifyIfMember( BSTR bstrMember, VARIANT * VariantArray, ULONG cElementFetched ) { DWORD i = 0; HRESULT hr = S_OK; IADs FAR * pObject = NULL; IDispatch FAR * pDispatch = NULL;
for (i = 0; i < cElementFetched; i++ ) {
IDispatch *pDispatch = NULL; BSTR bstrName = NULL;
pDispatch = VariantArray[i].pdispVal;
hr = pDispatch->QueryInterface( IID_IADs, (VOID **) &pObject ); BAIL_ON_FAILURE(hr);
hr = pObject->get_ADsPath(&bstrName); BAIL_ON_FAILURE(hr);
#ifdef WIN95
if (!_wcsicmp(bstrName, bstrMember)) { #else
if (CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, bstrName, -1, bstrMember, -1 ) == CSTR_EQUAL ) { #endif
SysFreeString(bstrName); bstrName = NULL;
pObject->Release();
return(TRUE);
}
SysFreeString(bstrName); bstrName = NULL;
pObject->Release();
}
error:
return(FALSE);
}
STDMETHODIMP CLDAPGroup::Add(THIS_ BSTR bstrNewItem) { RRETURN( ModifyGroup(bstrNewItem, TRUE )); }
STDMETHODIMP CLDAPGroup::Remove(THIS_ BSTR bstrItemToBeRemoved) { RRETURN( ModifyGroup(bstrItemToBeRemoved, FALSE )); }
HRESULT CLDAPGroup::ModifyGroup( THIS_ BSTR bstrItem, BOOL fAdd ) {
HRESULT hr = S_OK; DWORD dwStatus = 0L;
TCHAR *pszLDAPServer = NULL; TCHAR *pszItemLDAPServer = NULL;
TCHAR *pszLDAPDn = NULL; TCHAR *pszItemLDAPDn = NULL;
BSTR bstrADsPath = NULL; DWORD dwSyntaxId; ADS_LDP * ld = NULL;
LDAPModW *aMod[2]; LDAPModW ldapmod; WCHAR *aStrings[2];
OBJECTINFO ObjectInfo; POBJECTINFO pObjectInfo = &ObjectInfo; DWORD dwPort = 0;
if (!bstrItem || !*bstrItem) { RRETURN(E_FAIL); }
memset(pObjectInfo, 0, sizeof(OBJECTINFO)); pObjectInfo->ObjectType = TOKEN_LDAPOBJECT; hr = ADsObject(bstrItem, pObjectInfo); BAIL_ON_FAILURE(hr);
hr = ValidateProvider(pObjectInfo); BAIL_ON_FAILURE(hr);
hr = BuildLDAPPathFromADsPath2( bstrItem, &pszItemLDAPServer, &pszItemLDAPDn, &dwPort ); BAIL_ON_FAILURE(hr);
hr = get_ADsPath( &bstrADsPath ); BAIL_ON_FAILURE(hr);
hr = BuildLDAPPathFromADsPath2( bstrADsPath, &pszLDAPServer, &pszLDAPDn, &dwPort ); BAIL_ON_FAILURE(hr);
hr = LdapGetSyntaxOfAttributeOnServer( pszLDAPServer, TEXT("member"), &dwSyntaxId, _Credentials, pObjectInfo->PortNumber );
BAIL_ON_FAILURE(hr);
hr = LdapOpenObject( pszLDAPServer, pszLDAPDn, &ld, _Credentials, dwPort ); BAIL_ON_FAILURE(hr);
aMod[0] = &ldapmod; aMod[1] = NULL; aStrings[0] = pszItemLDAPDn; aStrings[1] = NULL;
ldapmod.mod_type = L"member"; ldapmod.mod_values = aStrings; ldapmod.mod_op = fAdd? LDAP_MOD_ADD : LDAP_MOD_DELETE;
dwStatus = LdapModifyS( ld, pszLDAPDn, aMod );
if (dwStatus) { hr = HRESULT_FROM_WIN32(dwStatus); BAIL_ON_FAILURE(hr); }
error:
FreeObjectInfo( &ObjectInfo );
if (pszItemLDAPServer) FreeADsStr( pszItemLDAPServer );
if (pszItemLDAPDn) { FreeADsStr(pszItemLDAPDn); }
if (pszLDAPDn) { FreeADsStr(pszLDAPDn); }
if (pszLDAPServer) FreeADsStr( pszLDAPServer );
if (bstrADsPath) ADsFreeString( bstrADsPath );
if (ld) { LdapCloseObject(ld); }
RRETURN(hr); }
HRESULT CLDAPGroup::UpdateServerType() { HRESULT hr = S_OK; BSTR bstrADsPath = NULL; LPWSTR pszGroupServer = NULL; LPWSTR pszGroupDn = NULL; BOOL fServerIsAD = FALSE; DWORD dwGroupPort = 0;
//
// Read the servertype only if we have not already done so.
//
if (_dwServerType == SERVER_TYPE_UNKNOWN) {
hr = _pADs->get_ADsPath( &bstrADsPath); BAIL_ON_FAILURE(hr);
hr = BuildLDAPPathFromADsPath2( bstrADsPath, &pszGroupServer, &pszGroupDn, &dwGroupPort ); BAIL_ON_FAILURE(hr);
hr = ReadServerSupportsIsADControl( pszGroupServer, &fServerIsAD, _Credentials, dwGroupPort );
//
// Treat failure to mean server is not AD
//
if (FAILED(hr)) { fServerIsAD = FALSE; hr = S_OK; }
if (fServerIsAD) { _dwServerType = SERVER_TYPE_AD; } else { _dwServerType = SERVER_TYPE_NOT_AD; } }
error:
if (bstrADsPath) { ADsFreeString(bstrADsPath); }
if (pszGroupServer) { FreeADsStr(pszGroupServer); }
if (pszGroupDn) { FreeADsStr(pszGroupDn); }
RRETURN(hr);
}
HRESULT ValidateProvider( POBJECTINFO pObjectInfo ) {
//
// The provider name is case-sensitive. This is a restriction that OLE
// has put on us.
//
if (_tcscmp(pObjectInfo->ProviderName, L"LDAP") == 0) { RRETURN(S_OK); } RRETURN(E_FAIL); }
BOOL MapLdapClassToADsClass( LPTSTR *aLdapClasses, int nCount, LPTSTR pszADsClass ) { *pszADsClass = 0;
if ( nCount == 0 ) return FALSE;
if ( _tcsicmp( aLdapClasses[nCount-1], TEXT("Top")) == 0 ) { for ( int j = 0; j < nCount; j++ ) { LPTSTR pszLdapClass = aLdapClasses[j];
for ( int i = 0; i < ARRAY_SIZE(aClassMap); i++ ) { if ( _tcsicmp( pszLdapClass, aClassMap[i].pszLdapClassName ) == 0 ) { _tcscpy( pszADsClass, aClassMap[i].pszADsClassName ); return TRUE; } } }
_tcscpy( pszADsClass, aLdapClasses[0] ); return FALSE;
} else { for ( int j = nCount-1; j >= 0; j-- ) { LPTSTR pszLdapClass = aLdapClasses[j];
for ( int i = 0; i < ARRAY_SIZE(aClassMap); i++ ) { if ( _tcsicmp( pszLdapClass, aClassMap[i].pszLdapClassName ) == 0 ) { _tcscpy( pszADsClass, aClassMap[i].pszADsClassName ); return TRUE; } } }
_tcscpy( pszADsClass, aLdapClasses[nCount-1] ); return FALSE; }
}
|