465 lines
10 KiB
C++
465 lines
10 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996
|
|
//
|
|
// File: cenumns.cxx
|
|
//
|
|
// Contents: LDAP Enumerator Code
|
|
//
|
|
// History:
|
|
//----------------------------------------------------------------------------
|
|
#include "ldap.hxx"
|
|
#pragma hdrstop
|
|
|
|
|
|
DWORD
|
|
GetDefaultServer(
|
|
DWORD dwPort,
|
|
BOOL fVerify,
|
|
LPWSTR szDomainDnsName,
|
|
LPWSTR szServerName,
|
|
BOOL fWriteable
|
|
);
|
|
|
|
DWORD
|
|
GetDefaultLdapServer(
|
|
LPWSTR Addresses[],
|
|
LPDWORD Count,
|
|
BOOL Verify,
|
|
DWORD dwPort
|
|
) ;
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLDAPNamespaceEnum::Create
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [pCollection]
|
|
// [ppEnumVariant]
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History: 01-30-95 krishnag Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
CLDAPNamespaceEnum::Create(
|
|
CLDAPNamespaceEnum FAR* FAR* ppenumvariant,
|
|
VARIANT var,
|
|
CCredentials& Credentials,
|
|
LPTSTR pszNamespace
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CLDAPNamespaceEnum FAR* penumvariant = NULL;
|
|
|
|
penumvariant = new CLDAPNamespaceEnum();
|
|
|
|
if (penumvariant == NULL){
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = ObjectTypeList::CreateObjectTypeList(
|
|
var,
|
|
&penumvariant->_pObjList
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
penumvariant->_Credentials = Credentials;
|
|
|
|
penumvariant->_pszNamespace = AllocADsStr(pszNamespace);
|
|
if (!(penumvariant->_pszNamespace)) {
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if( IsGCNamespace(pszNamespace) )
|
|
penumvariant->_dwPort = (DWORD) USE_DEFAULT_GC_PORT;
|
|
else
|
|
penumvariant->_dwPort = (DWORD) USE_DEFAULT_LDAP_PORT;
|
|
|
|
*ppenumvariant = penumvariant;
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
if (penumvariant) {
|
|
delete penumvariant;
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLDAPNamespaceEnum::CLDAPNamespaceEnum
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
// Returns:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History: 01-30-95 krishnag Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CLDAPNamespaceEnum::CLDAPNamespaceEnum()
|
|
{
|
|
_dwIndex = 0;
|
|
_pObjList = NULL;
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLDAPNamespaceEnum::~CLDAPNamespaceEnum
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History: 01-30-95 krishnag Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CLDAPNamespaceEnum::~CLDAPNamespaceEnum()
|
|
{
|
|
if (_pszNamespace)
|
|
FreeADsMem(_pszNamespace);
|
|
|
|
if ( _pObjList )
|
|
delete _pObjList;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLDAPNamespaceEnum::Next
|
|
//
|
|
// Synopsis: Returns cElements number of requested ADs objects in the
|
|
// array supplied in pvar.
|
|
//
|
|
// Arguments: [cElements] -- The number of elements requested by client
|
|
// [pvar] -- ptr to array of VARIANTs to for return objects
|
|
// [pcElementFetched] -- if non-NULL, then number of elements
|
|
// -- actually returned is placed here
|
|
//
|
|
// Returns: HRESULT -- S_OK if number of elements requested are returned
|
|
// -- S_FALSE if number of elements is < requested
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CLDAPNamespaceEnum::Next(
|
|
ULONG cElements,
|
|
VARIANT FAR* pvar,
|
|
ULONG FAR* pcElementFetched
|
|
)
|
|
{
|
|
ULONG cElementFetched = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( _dwIndex > 0 ) // only your default ds will be returned, one element
|
|
{
|
|
if (pcElementFetched)
|
|
*pcElementFetched = 0;
|
|
|
|
RRETURN(S_FALSE);
|
|
}
|
|
|
|
hr = EnumObjects(
|
|
cElements,
|
|
pvar,
|
|
&cElementFetched
|
|
);
|
|
|
|
|
|
if (pcElementFetched) {
|
|
*pcElementFetched = cElementFetched;
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CLDAPNamespaceEnum::EnumObjects(
|
|
ULONG cElements,
|
|
VARIANT FAR* pvar,
|
|
ULONG FAR* pcElementFetched
|
|
)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
IDispatch *pDispatch = NULL;
|
|
DWORD i = 0;
|
|
|
|
while (i < cElements) {
|
|
|
|
if ( _dwIndex > 0 ) // only your default ds will be returned,
|
|
// i.e. one element only
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
_dwIndex++;
|
|
|
|
hr = GetTreeObject(&pDispatch);
|
|
if (hr == S_FALSE) {
|
|
break;
|
|
}
|
|
|
|
VariantInit(&pvar[i]);
|
|
pvar[i].vt = VT_DISPATCH;
|
|
pvar[i].pdispVal = pDispatch;
|
|
(*pcElementFetched)++;
|
|
i++;
|
|
}
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CLDAPNamespaceEnum::GetTreeObject(
|
|
IDispatch ** ppDispatch
|
|
)
|
|
{
|
|
DWORD err = NO_ERROR;
|
|
HRESULT hr = S_OK;
|
|
LPTSTR *aValuesNamingContext = NULL;
|
|
LPTSTR *aValuesObjectClass = NULL;
|
|
int nCountValues = 0;
|
|
TCHAR *pszLDAPPathName = NULL;
|
|
TCHAR szADsClassName[64];
|
|
WCHAR szDomainName[MAX_PATH];
|
|
WCHAR szServerName[MAX_PATH];
|
|
TCHAR *pszNewADsPath = NULL;
|
|
TCHAR *pszLast = NULL;
|
|
|
|
LPWSTR pszNamingContext = NULL;
|
|
|
|
LPWSTR pszNewADsParent = NULL;
|
|
LPWSTR pszNewADsCommonName = NULL;
|
|
|
|
DWORD fVerify = FALSE;
|
|
|
|
*ppDispatch = NULL;
|
|
ADS_LDP *ld = NULL;
|
|
|
|
BOOL fGCDefaulted = FALSE;
|
|
|
|
//
|
|
// Now send back the current object
|
|
//
|
|
|
|
RetryGetDefaultServer:
|
|
|
|
if ( err = GetDefaultServer(
|
|
_dwPort,
|
|
fVerify,
|
|
szDomainName,
|
|
szServerName,
|
|
TRUE) ){
|
|
|
|
hr = HRESULT_FROM_WIN32(err);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// Read the naming contexts
|
|
//
|
|
|
|
|
|
if (_dwPort == USE_DEFAULT_GC_PORT) {
|
|
fGCDefaulted = TRUE;
|
|
pszNamingContext = NULL;
|
|
} else {
|
|
pszNamingContext = TEXT(LDAP_OPATT_DEFAULT_NAMING_CONTEXT);
|
|
}
|
|
|
|
|
|
hr = LdapOpenObject2(
|
|
szDomainName,
|
|
szServerName,
|
|
NULL,
|
|
&ld,
|
|
_Credentials,
|
|
_dwPort
|
|
);
|
|
|
|
if (((hr == HRESULT_FROM_WIN32(ERROR_BAD_NETPATH)) ||
|
|
(hr == HRESULT_FROM_WIN32(ERROR_DS_SERVER_DOWN)))
|
|
&& !fVerify) {
|
|
fVerify = TRUE;
|
|
goto RetryGetDefaultServer ;
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (!fGCDefaulted) {
|
|
|
|
hr = LdapReadAttributeFast(
|
|
ld,
|
|
NULL,
|
|
pszNamingContext,
|
|
&aValuesNamingContext,
|
|
&nCountValues
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if ( nCountValues == 0 ) {
|
|
|
|
//
|
|
// The hr will be modified at the end of the function to S_FALSE
|
|
// in case of error
|
|
|
|
BAIL_ON_FAILURE(hr = E_FAIL);
|
|
|
|
}
|
|
|
|
hr = BuildADsPathFromLDAPPath2(
|
|
FALSE, //Server is present till DSSnapin Works
|
|
_pszNamespace,
|
|
szDomainName,
|
|
_dwPort,
|
|
fGCDefaulted ?
|
|
TEXT("") :
|
|
aValuesNamingContext[0],
|
|
&pszNewADsPath
|
|
);
|
|
|
|
} else {
|
|
//
|
|
// In this case we want to force it to be GC://yourDomain
|
|
// so that all searches will be truly global
|
|
//
|
|
|
|
hr = BuildADsPathFromLDAPPath2(
|
|
TRUE, // server is present
|
|
_pszNamespace,
|
|
szDomainName,
|
|
_dwPort,
|
|
TEXT(""),
|
|
&pszNewADsPath
|
|
);
|
|
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// this part is common to both code paths
|
|
hr = BuildADsParentPath(
|
|
pszNewADsPath,
|
|
&pszNewADsParent,
|
|
&pszNewADsCommonName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
nCountValues = 0;
|
|
|
|
//
|
|
// Read the object class of the path if necessary
|
|
//
|
|
|
|
if (!fGCDefaulted) {
|
|
|
|
hr = LdapReadAttributeFast(
|
|
ld,
|
|
aValuesNamingContext[0],
|
|
L"objectClass",
|
|
&aValuesObjectClass,
|
|
&nCountValues
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
if ( nCountValues == 0 && !fGCDefaulted)
|
|
{
|
|
// This object exists but does not contain objectClass attribute
|
|
// which is required for all DS objects. Hence, ignore the object
|
|
// and return error.
|
|
|
|
hr = E_ADS_BAD_PATHNAME;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// Create the object
|
|
//
|
|
|
|
if (fGCDefaulted) {
|
|
|
|
hr = CLDAPGenObject::CreateGenericObject(
|
|
pszNewADsParent,
|
|
pszNewADsCommonName,
|
|
L"top",
|
|
_Credentials,
|
|
ADS_OBJECT_BOUND,
|
|
IID_IUnknown,
|
|
(void **) ppDispatch
|
|
);
|
|
|
|
} else {
|
|
//
|
|
// Send all the classes so we can load all extensions
|
|
//
|
|
hr = CLDAPGenObject::CreateGenericObject(
|
|
pszNewADsParent,
|
|
pszNewADsCommonName,
|
|
aValuesObjectClass,
|
|
nCountValues,
|
|
_Credentials,
|
|
ADS_OBJECT_BOUND,
|
|
IID_IDispatch,
|
|
(void **) ppDispatch
|
|
);
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
|
|
if ( aValuesNamingContext )
|
|
LdapValueFree( aValuesNamingContext );
|
|
|
|
if ( aValuesObjectClass )
|
|
LdapValueFree( aValuesObjectClass );
|
|
|
|
if ( pszNewADsPath )
|
|
FreeADsStr( pszNewADsPath );
|
|
|
|
if ( pszNewADsParent) {
|
|
FreeADsStr(pszNewADsParent);
|
|
}
|
|
|
|
if (pszNewADsCommonName) {
|
|
FreeADsStr(pszNewADsCommonName);
|
|
}
|
|
|
|
if ( ld ){
|
|
LdapCloseObject( ld );
|
|
}
|
|
|
|
RRETURN_ENUM_STATUS(hr);
|
|
}
|