windows-nt/Source/XPSP1/NT/ds/adsi/ldap/getobj.cxx
2020-09-26 16:20:57 +08:00

1402 lines
36 KiB
C++

//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996
//
// File: getobj.cxx
//
// Contents: LDAP GetObject functionality
//
// History:
//----------------------------------------------------------------------------
#include "ldap.hxx"
#pragma hdrstop
DWORD
GetDefaultLdapServer(
LPWSTR Addresses[],
LPDWORD Count,
BOOL Verify,
DWORD dwPort
) ;
DWORD
GetDefaultServer(
DWORD dwPort,
BOOL fVerify,
LPWSTR szDomainDnsName,
LPWSTR szServerName,
BOOL fWriteable
);
LPWSTR gpszStickyServerName = NULL;
LPWSTR gpszStickyDomainName = NULL;
//
// Dont do DsGetDCName with FORCE_DISCOVERY too frequently.
// LastVerifyDefaultServer is uses to track tick count.
//
#define DC_NORETRY (1000 * 60 * 5)
DWORD LastVerifyDefaultServer = 0 ;
//+---------------------------------------------------------------------------
// Function: GetObject
//
// Synopsis: Called by ResolvePathName to return an object
//
// Arguments: [LPTSTR szBuffer]
// [LPVOID *ppObject]
//
// Returns: HRESULT
//
// Modifies: -
//
// History: 11-3-95 krishnag Created.
//
//----------------------------------------------------------------------------
HRESULT
GetServerBasedObject(
LPWSTR szBuffer,
POBJECTINFO pObjectInfo,
CCredentials& Credentials,
LPVOID * ppObject
)
{
HRESULT hr = S_OK;
TCHAR *pszLDAPServer = NULL;
TCHAR *pszLDAPDn = NULL;
TCHAR *pszParent = NULL;
TCHAR *pszCommonName = NULL;
TCHAR szNamespace[MAX_PATH];
IADs *pADs = NULL;
LPTSTR *aValues = NULL;
LPTSTR *aValuesNamingContext = NULL;
int nCount = 0;
TCHAR *pszNewADsPath = NULL;
LPWSTR pszNewADsParent = NULL;
LPWSTR pszNewADsCommonName = NULL;
LPWSTR pszNamingContext = NULL;
TCHAR *pszLast = NULL;
BOOL fVerify = FALSE ;
DWORD dwPort = 0;
ADS_LDP *ld = NULL;
BOOL fGCDefaulted = FALSE;
BOOL fNoDefaultNamingContext = FALSE;
BOOL fFastBind = Credentials.GetAuthFlags() & ADS_FAST_BIND;
//
// Validate that this ADs pathname is to be processed by
// us - as in the provider name is LDAP:
//
hr = ValidateProvider(pObjectInfo);
BAIL_ON_FAILURE(hr);
hr = ValidateObjectType(pObjectInfo);
BAIL_ON_FAILURE(hr);
// Get the namespace name
wcscpy(szNamespace, pObjectInfo->NamespaceName);
wcscat(szNamespace, L":");
switch (pObjectInfo->ObjectType) {
case TOKEN_NAMESPACE:
//
// This means that this is a namespace object;
// instantiate the namespace object
//
hr = GetNamespaceObject(
pObjectInfo,
Credentials,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
case TOKEN_ROOTDSE:
//
// This means that this is a RootDSE object;
// instantiate the RootDSE object
//
hr = GetRootDSEObject(
pObjectInfo,
Credentials,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
case TOKEN_SCHEMA:
case TOKEN_CLASS:
case TOKEN_PROPERTY:
case TOKEN_SYNTAX:
hr = GetSchemaObject(
pObjectInfo,
Credentials,
pObjectInfo->PortNumber,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
default:
hr = BuildLDAPPathFromADsPath2(
szBuffer,
&pszLDAPServer,
&pszLDAPDn,
&dwPort
);
hr = LdapOpenObject2(
pszLDAPServer,
NULL,
NULL,
&ld,
Credentials,
dwPort
);
BAIL_ON_FAILURE(hr);
if ( pszLDAPDn == NULL ) {
// If only server name is specified, we need to
// find the root of the naming context...
if (dwPort == USE_DEFAULT_GC_PORT) {
pszNamingContext = NULL;
fGCDefaulted = TRUE;
} else {
pszNamingContext = TEXT(LDAP_OPATT_DEFAULT_NAMING_CONTEXT);
}
// We already have an open connection so we can do
// fast read to avoid looking up the bind cache.
if (!fGCDefaulted ) {
hr = LdapReadAttributeFast(
ld,
NULL, // the DN is that of the RootDSE
pszNamingContext,
&aValuesNamingContext,
&nCount
);
if (SUCCEEDED(hr) && (nCount < 1)) {
hr = HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE);
}
}
//
// If we fail reading the naming context then we need to continue
// if the error was no attribute or value, set some flags
//
if (FAILED(hr)) {
if ( hr != HRESULT_FROM_WIN32(ERROR_DS_SERVER_DOWN) ) {
nCount = 1;
pszNamingContext = NULL;
hr = S_OK;
fNoDefaultNamingContext = TRUE;
fGCDefaulted = TRUE;
}
}
BAIL_ON_FAILURE(hr);
//
// At this point we have either
// 1) Valid defaultNamingContext and pszNamingContext
// 2) Either a GC or a case where defaultNamingContext
// is not available - essentially just a null dn
//
hr = BuildADsPathFromLDAPPath2(
TRUE, //Server is Present
szNamespace,
pszLDAPServer,
dwPort,
pszNamingContext ?
aValuesNamingContext[0] :
TEXT(""),
&pszNewADsPath
);
BAIL_ON_FAILURE(hr);
hr = BuildADsParentPath(
pszNewADsPath,
&pszNewADsParent,
&pszNewADsCommonName
);
BAIL_ON_FAILURE(hr);
if (pszLDAPServer) {
FreeADsStr(pszLDAPServer);
pszLDAPServer = NULL;
}
if (pszLDAPDn) {
FreeADsStr(pszLDAPDn);
pszLDAPDn = NULL;
}
//
// Put the info from the new path build above into the
// various components - matters if we are dealing with
// a valid defaultNanmingContext
//
hr = BuildLDAPPathFromADsPath2(
pszNewADsPath,
&pszLDAPServer,
&pszLDAPDn,
&dwPort
);
}
nCount = 0;
// At this point we have a valid DN
// so we can go ahead and do the a fast read rather than
// just a plain read to avoid the overhead of looking upt
// the bindcache.
if (!fGCDefaulted && !fFastBind) {
hr = LdapReadAttributeFast(
ld,
pszLDAPDn,
TEXT("objectClass"),
&aValues,
&nCount
);
BAIL_ON_FAILURE(hr);
if (nCount == 0) {
BAIL_ON_FAILURE(hr = E_ADS_BAD_PATHNAME);
}
}
if (fGCDefaulted) {
//
// This is either GC://server, where we want to
// set the object DN to null so that all
// searches will yield correct results.
// or the case of a server that did not have
// a default naming context in the RootDSE
//
hr = CLDAPGenObject::CreateGenericObject(
pszNewADsParent,
pszNewADsCommonName,
L"top",
Credentials,
ADS_OBJECT_BOUND,
IID_IADs,
(void **) &pADs
);
}
else if (aValuesNamingContext ) {
//
// Need to create the object with new parent
// and newADsCN
//
if (fFastBind) {
hr = CLDAPGenObject::CreateGenericObject(
pszNewADsParent,
pszNewADsCommonName,
L"top",
Credentials,
ADS_OBJECT_BOUND,
IID_IADs,
(void **) &pADs,
fFastBind
);
} else {
hr = CLDAPGenObject::CreateGenericObject(
pszNewADsParent,
pszNewADsCommonName,
aValues,
nCount,
Credentials,
ADS_OBJECT_BOUND,
IID_IADs,
(void **) &pADs,
fFastBind
);
}
} else {
//
// This is the default case where we build the info from
// the data passed into GetObject call
//
hr = BuildADsParentPathFromObjectInfo2(
pObjectInfo,
&pszParent,
&pszCommonName
);
BAIL_ON_FAILURE(hr);
if (fFastBind) {
hr = CLDAPGenObject::CreateGenericObject(
pszParent,
pszCommonName,
L"top",
Credentials,
ADS_OBJECT_BOUND,
IID_IADs,
(void **) &pADs,
fFastBind
);
} else {
hr = CLDAPGenObject::CreateGenericObject(
pszParent,
pszCommonName,
aValues,
nCount,
Credentials,
ADS_OBJECT_BOUND,
IID_IADs,
(void **) &pADs,
fFastBind
);
}
}
BAIL_ON_FAILURE(hr);
//
// InstantiateDerivedObject should add-ref this pointer for us.
//
hr = pADs->QueryInterface(
IID_IUnknown,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
}
error:
if ( ld ){
LdapCloseObject( ld );
}
if (pADs)
pADs->Release();
if ( aValuesNamingContext )
LdapValueFree( aValuesNamingContext );
if ( aValues )
LdapValueFree( aValues );
if ( pszLDAPServer )
FreeADsStr( pszLDAPServer );
if (pszLDAPDn) {
FreeADsStr(pszLDAPDn);
}
if ( pszNewADsPath )
FreeADsStr( pszNewADsPath );
if (pszNewADsParent) {
FreeADsStr(pszNewADsParent);
}
if (pszNewADsCommonName) {
FreeADsStr(pszNewADsCommonName);
}
if ( pszParent )
FreeADsStr( pszParent );
if ( pszCommonName )
FreeADsStr( pszCommonName );
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: GetNamespaceObject
//
// Synopsis: called by GetObject
//
// Arguments: [POBJECTINFO pObjectInfo]
// [LPVOID * ppObject]
//
// Returns: HRESULT
//
// Modifies: -
//
// History: 11-3-95 krishnag Created.
//
//----------------------------------------------------------------------------
HRESULT
GetNamespaceObject(
POBJECTINFO pObjectInfo,
CCredentials& Credentials,
LPVOID * ppObject
)
{
HRESULT hr;
WCHAR szNamespace[MAX_PATH];
hr = ValidateNamespaceObject(
pObjectInfo
);
BAIL_ON_FAILURE(hr);
wsprintf(szNamespace,L"%s:", pObjectInfo->NamespaceName);
hr = CLDAPNamespace::CreateNamespace(
TEXT("ADs:"),
szNamespace,
Credentials,
ADS_OBJECT_BOUND,
IID_IUnknown,
ppObject
);
error:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: GetRootDSEObject
//
// Synopsis: called by GetObject
//
// Arguments: [POBJECTINFO pObjectInfo]
// [LPVOID * ppObject]
//
// Returns: HRESULT
//
// Modifies: -
//
// History: 11-3-95 krishnag Created.
//
//----------------------------------------------------------------------------
HRESULT
GetRootDSEObject(
POBJECTINFO pObjectInfo,
CCredentials& Credentials,
LPVOID * ppObject
)
{
HRESULT hr;
LPWSTR pszParent = NULL;
LPWSTR pszCommonName = NULL;
hr = ValidateRootDSEObject(
pObjectInfo
);
BAIL_ON_FAILURE(hr);
hr = BuildADsParentPathFromObjectInfo2(
pObjectInfo,
&pszParent,
&pszCommonName
);
BAIL_ON_FAILURE(hr);
hr = CLDAPRootDSE::CreateRootDSE(
pszParent,
pszCommonName,
L"",
Credentials,
ADS_OBJECT_BOUND,
IID_IUnknown,
(void **)ppObject
);
error:
if (pszParent) {
FreeADsStr(pszParent);
}
if (pszCommonName) {
FreeADsStr(pszCommonName);
}
RRETURN(hr);
}
HRESULT
ValidateRootDSEObject(
POBJECTINFO pObjectInfo
)
{
if ( pObjectInfo->NumComponents > 1 )
{
RRETURN(E_ADS_BAD_PATHNAME);
}
RRETURN(S_OK);
}
HRESULT
ValidateNamespaceObject(
POBJECTINFO pObjectInfo
)
{
if (_tcsicmp(pObjectInfo->NamespaceName, szLDAPNamespaceName) == 0 ||
_tcsicmp(pObjectInfo->NamespaceName, szGCNamespaceName) == 0) {
RRETURN(S_OK);
}
RRETURN(E_FAIL);
}
HRESULT
ValidateProvider(
POBJECTINFO pObjectInfo
)
{
//
// The provider name is case-sensitive. This is a restriction that OLE
// has put on us.
//
if (_tcscmp(pObjectInfo->ProviderName, szProviderName) == 0) {
RRETURN(S_OK);
}
RRETURN(E_FAIL);
}
//+---------------------------------------------------------------------------
// Function: GetSchemaObject
//
// Synopsis: called by GetObject
//
// Arguments: [POBJECTINFO pObjectInfo]
// [LPVOID * ppObject]
//
// Returns: HRESULT
//
// Modifies: -
//
// History: 11-3-95 krishnag Created.
//
//----------------------------------------------------------------------------
HRESULT
GetSchemaObject(
POBJECTINFO pObjectInfo,
CCredentials& Credentials,
DWORD dwPort,
LPVOID * ppObject
)
{
HRESULT hr = S_OK;
TCHAR szDomainName[MAX_PATH];
TCHAR szServerName[MAX_PATH];
TCHAR *pszParent = NULL;
TCHAR *pszCommonName = NULL;
DWORD dwObjectType = 0;
DWORD i,dwStatus;
LDAP_SCHEMA_HANDLE hSchema = NULL;
BOOL fFound = FALSE;
hr = ValidateSchemaObject(
pObjectInfo,
&dwObjectType
);
BAIL_ON_FAILURE(hr);
if (pObjectInfo->TreeName) {
_tcscpy(szDomainName, pObjectInfo->TreeName);
}else {
LPTSTR aAddresses[5];
DWORD nCount = 5;
BOOL fVerify = FALSE;
dwStatus = GetDefaultServer(
dwPort,
fVerify,
szDomainName,
szServerName,
TRUE
);
if (dwStatus) {
hr = HRESULT_FROM_WIN32(dwStatus);
BAIL_ON_FAILURE(hr);
}
}
hr = SchemaOpen(
szDomainName,
&hSchema,
Credentials,
dwPort
);
BAIL_ON_FAILURE(hr);
hr = BuildADsParentPathFromObjectInfo2(
pObjectInfo,
&pszParent,
&pszCommonName
);
BAIL_ON_FAILURE(hr);
switch (dwObjectType) {
case LDAP_SCHEMA_ID:
hr = CLDAPSchema::CreateSchema(
pszParent,
pszCommonName,
szDomainName,
Credentials,
ADS_OBJECT_BOUND,
IID_IUnknown,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
case LDAP_CLASS_ID:
{
CLASSINFO *pClassInfo = NULL;
if ( pObjectInfo->NumComponents < 2 )
{
hr = E_ADS_BAD_PATHNAME;
BAIL_ON_FAILURE(hr);
}
//
// Look for the given class name
//
if (pObjectInfo->dwPathType == PATHTYPE_WINDOWS) {
hr = SchemaGetClassInfo(
hSchema,
pObjectInfo->ComponentArray[1].szComponent,
&pClassInfo );
}else {
hr = SchemaGetClassInfo(
hSchema,
pObjectInfo->ComponentArray[0].szComponent,
&pClassInfo);
}
if ( SUCCEEDED(hr))
{
if ( pClassInfo == NULL ) // could not find the class name
{
// Do not bail on failure here since we might need to fall
// through to the property case.
hr = E_ADS_BAD_PATHNAME;
}
}
if ( SUCCEEDED(hr))
{
//
// Class name found, create and return the object
//
hr = CLDAPClass::CreateClass( pszParent,
hSchema,
pClassInfo->pszName,
pClassInfo,
Credentials,
ADS_OBJECT_BOUND,
IID_IUnknown,
ppObject );
}
if ( SUCCEEDED(hr)
|| ( pObjectInfo->ObjectType == TOKEN_CLASS )
)
{
BAIL_ON_FAILURE(hr);
break;
}
hr = S_OK;
// Else the exact type was not specified and we guessed it to be class
// but since CreateClass failed, we need to try and see if it is a
// property object. Hence, falls through
}
case LDAP_PROPERTY_ID:
{
PROPERTYINFO *pPropertyInfo = NULL;
if ( pObjectInfo->NumComponents < 2)
{
hr = E_ADS_BAD_PATHNAME;
BAIL_ON_FAILURE(hr);
}
//
// Look for the given property name
//
if (pObjectInfo->dwPathType == PATHTYPE_WINDOWS) {
hr = SchemaGetPropertyInfo(
hSchema,
pObjectInfo->ComponentArray[1].szComponent,
&pPropertyInfo );
}else{
hr = SchemaGetPropertyInfo(
hSchema,
pObjectInfo->ComponentArray[0].szComponent,
&pPropertyInfo
);
}
if ( SUCCEEDED(hr))
{
if ( pPropertyInfo == NULL ) // could not find the property name
{
// Do not bail on failure here since we might need to fall
// through to the syntax case.
hr = E_ADS_BAD_PATHNAME;
}
}
if ( SUCCEEDED(hr))
{
//
// Property name found, so create and return the object
//
hr = CLDAPProperty::CreateProperty(
pszParent,
hSchema,
pPropertyInfo->pszPropertyName,
pPropertyInfo,
Credentials,
ADS_OBJECT_BOUND,
IID_IUnknown,
ppObject );
}
if ( SUCCEEDED(hr)
|| ( pObjectInfo->ObjectType == TOKEN_PROPERTY )
)
{
BAIL_ON_FAILURE(hr);
break;
}
hr = S_OK;
// Else the exact type was not specified and we guessed it to be
// property but since CreateProperty failed, we need to try and see if
// it is a syntax object. Hence, falls through
}
case LDAP_SYNTAX_ID:
if ( pObjectInfo->NumComponents < 2 )
{
hr = E_ADS_BAD_PATHNAME;
BAIL_ON_FAILURE(hr);
}
//
// Look for the given syntax name
//
for ( i = 0; i < g_cLDAPSyntax; i++ )
{
if ( _tcsicmp( g_aLDAPSyntax[i].pszName,
(pObjectInfo->dwPathType == PATHTYPE_WINDOWS)?
pObjectInfo->ComponentArray[1].szComponent:
pObjectInfo->ComponentArray[0].szComponent ) == 0 )
break;
}
if ( i == g_cLDAPSyntax )
{
hr = E_ADS_BAD_PATHNAME;
BAIL_ON_FAILURE(hr);
}
//
// Syntax name found, create and return the object
//
hr = CLDAPSyntax::CreateSyntax(
pszParent,
&(g_aLDAPSyntax[i]),
Credentials,
ADS_OBJECT_BOUND,
IID_IUnknown,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
default:
hr = E_ADS_UNKNOWN_OBJECT;
break;
}
error:
if ( pszParent )
FreeADsStr( pszParent );
if ( pszCommonName )
FreeADsStr( pszCommonName );
if ( hSchema )
SchemaClose( &hSchema );
RRETURN(hr);
}
HRESULT
ValidateSchemaObject(
POBJECTINFO pObjectInfo,
PDWORD pdwObjectType
)
{
DWORD dwNumComponents = 0;
HRESULT hr = S_OK;
switch ( pObjectInfo->ObjectType )
{
case TOKEN_CLASS:
*pdwObjectType = LDAP_CLASS_ID;
break;
case TOKEN_SYNTAX:
*pdwObjectType = LDAP_SYNTAX_ID;
break;
case TOKEN_PROPERTY:
*pdwObjectType = LDAP_PROPERTY_ID;
break;
case TOKEN_SCHEMA:
dwNumComponents = pObjectInfo->NumComponents;
switch (dwNumComponents) {
case 1:
if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,
SCHEMA_NAME))
*pdwObjectType = LDAP_SCHEMA_ID;
break;
case 2:
if (pObjectInfo->dwPathType == PATHTYPE_WINDOWS) {
if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,
SCHEMA_NAME))
*pdwObjectType = LDAP_CLASS_ID;
// Might also be a property or syntax object
// see function GetSchemaObject()
}else {
if (!_tcsicmp(pObjectInfo->ComponentArray[dwNumComponents - 1].szComponent,
SCHEMA_NAME))
*pdwObjectType = LDAP_CLASS_ID;
// Might also be a property or syntax object
// see function GetSchemaObject()
}
break;
default:
hr = E_FAIL;
break;
}
break;
default:
hr = E_FAIL;
break;
}
RRETURN(hr);
}
HRESULT
ValidateObjectType(
POBJECTINFO pObjectInfo
)
{
if ( pObjectInfo->ObjectType != TOKEN_LDAPOBJECT )
{
// The type has already been specified in this case using COMMA
RRETURN(S_OK);
}
if ( pObjectInfo->NamespaceName
&& !pObjectInfo->TreeName
&& !pObjectInfo->NumComponents
)
{
pObjectInfo->ObjectType = TOKEN_NAMESPACE;
}
else if ( pObjectInfo->NamespaceName
&& pObjectInfo->TreeName
&& pObjectInfo->NumComponents)
{
switch (pObjectInfo->dwPathType) {
case PATHTYPE_WINDOWS:
if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,SCHEMA_NAME))
pObjectInfo->ObjectType = TOKEN_SCHEMA;
else if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,ROOTDSE_NAME))
pObjectInfo->ObjectType = TOKEN_ROOTDSE;
break;
case PATHTYPE_X500:
default:
if (!_tcsicmp(pObjectInfo->ComponentArray[pObjectInfo->NumComponents - 1].szComponent,SCHEMA_NAME))
pObjectInfo->ObjectType = TOKEN_SCHEMA;
else if (!_tcsicmp(pObjectInfo->ComponentArray[pObjectInfo->NumComponents - 1].szComponent,ROOTDSE_NAME))
pObjectInfo->ObjectType = TOKEN_ROOTDSE;
break;
}
}else if ( pObjectInfo->NamespaceName
&& !pObjectInfo->TreeName
&& pObjectInfo->NumComponents)
{
switch (pObjectInfo->dwPathType) {
case PATHTYPE_WINDOWS:
if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,SCHEMA_NAME))
pObjectInfo->ObjectType = TOKEN_SCHEMA;
else if (!_tcsicmp(pObjectInfo->ComponentArray[0].szComponent,ROOTDSE_NAME))
pObjectInfo->ObjectType = TOKEN_ROOTDSE;
break;
case PATHTYPE_X500:
default:
if (!_tcsicmp(pObjectInfo->ComponentArray[pObjectInfo->NumComponents - 1].szComponent,SCHEMA_NAME))
pObjectInfo->ObjectType = TOKEN_SCHEMA;
else if (!_tcsicmp(pObjectInfo->ComponentArray[pObjectInfo->NumComponents - 1].szComponent,ROOTDSE_NAME))
pObjectInfo->ObjectType = TOKEN_ROOTDSE;
break;
}
}
RRETURN(S_OK);
}
HRESULT
GetServerLessBasedObject(
LPWSTR szBuffer,
POBJECTINFO pObjectInfo,
CCredentials& Credentials,
LPVOID * ppObject
)
{
HRESULT hr = S_OK;
DWORD dwStatus = NO_ERROR;
TCHAR *pszLDAPServer = NULL;
TCHAR *pszLDAPDn = NULL;
TCHAR *pszParent = NULL;
TCHAR *pszCommonName = NULL;
TCHAR szADsClassName[64];
WCHAR szDomainName[MAX_PATH];
WCHAR szServerName[MAX_PATH];
WCHAR *pszServerName=NULL;
IADs *pADs = NULL;
LPTSTR *aValues = NULL;
int nCount = 0;
TCHAR *pszLast = NULL;
BOOL fVerify = FALSE ;
DWORD dwPort = 0;
ADS_LDP *ld = NULL;
BOOL fFastBind = Credentials.GetAuthFlags() & ADS_FAST_BIND;
BOOL fUseSpecifiedServer = (gpszStickyServerName != NULL);
//
// Validate that this ADs pathname is to be processed by
// us - as in the provider name is LDAP:
//
hr = ValidateProvider(pObjectInfo);
BAIL_ON_FAILURE(hr);
hr = ValidateObjectType(pObjectInfo);
BAIL_ON_FAILURE(hr);
switch (pObjectInfo->ObjectType) {
case TOKEN_NAMESPACE:
//
// This means that this is a namespace object;
// instantiate the namespace object
//
hr = GetNamespaceObject(
pObjectInfo,
Credentials,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
case TOKEN_ROOTDSE:
//
// This means taht this is a namespace object;
// instantiate the namespace object
//
hr = GetRootDSEObject(
pObjectInfo,
Credentials,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
case TOKEN_SCHEMA:
case TOKEN_CLASS:
case TOKEN_PROPERTY:
case TOKEN_SYNTAX:
hr = GetSchemaObject(
pObjectInfo,
Credentials,
pObjectInfo->PortNumber,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
default:
if ( pObjectInfo->TreeName == NULL )
{
LPTSTR pszName;
LPTSTR aAddresses[5];
//
// fVerify is initially FALSE. If TRUE DsGetDCName will hit the net.
//
RetryGetDefaultServer:
dwStatus = GetDefaultServer(
pObjectInfo->PortNumber,
fVerify,
szDomainName,
szServerName,
TRUE
);
if (dwStatus) {
hr = HRESULT_FROM_WIN32(dwStatus);
BAIL_ON_FAILURE(hr);
}
pszServerName=szServerName;
if (fUseSpecifiedServer) {
//
// We need to change the name of the domain to be that of
// the server we want to target. The swap is made if
// 1) gpszDomainName == NULL, that implies that just
// a serverName was set and not which domain it applies to.
// 2) If a domainName is specified, then the domainName
// from above should be that set in the global pointer for
// the target server to be changed.
//
if ((gpszStickyDomainName
&& (!_wcsicmp(szDomainName, gpszStickyDomainName))
)
|| (gpszStickyDomainName == NULL)
) {
//
// We need to change the target to the server.
//
wcscpy(szDomainName,gpszStickyServerName);
pszServerName = NULL;
//
// Make sure if server is down we go to another
// server on the retryGetDefault server path.
//
fUseSpecifiedServer = FALSE;
}
}
hr = BuildLDAPPathFromADsPath2(
szBuffer,
&pszLDAPServer,
&pszLDAPDn,
&dwPort
);
nCount = 0;
// We need to open object here because we want to
// keep the handle open, read will open/close if there
// are no outstanding connections which is likely the case
hr = LdapOpenObject2(
szDomainName,
pszServerName,
pszLDAPDn,
&ld,
Credentials,
dwPort
);
if (SUCCEEDED(hr) && !fFastBind) {
hr = LdapReadAttributeFast(
ld,
pszLDAPDn,
TEXT("objectClass"),
&aValues,
&nCount
);
BAIL_ON_FAILURE(hr);
}
//
// If server not present and we have NOT tried with fVerify
// set to TRUE.
//
if (((hr == HRESULT_FROM_WIN32(ERROR_BAD_NETPATH)) ||
(hr == HRESULT_FROM_WIN32(ERROR_DS_SERVER_DOWN)))
&& !fVerify)
{
DWORD Last = LastVerifyDefaultServer ;
DWORD Current = GetTickCount() ;
//
// If tick is zero, assume first time. In the very unlikely
// event we wrapped managed to get exactly zero, we pay the
// cost of the DsGetDcName (with verify).
//
if ((Last == 0) ||
((Last <= Current) && ((Current-Last) > DC_NORETRY)) ||
((Last > Current) &&
((Current+(((DWORD)(-1))- Last)) > DC_NORETRY))) {
//
// Set the time. Note this is not critical section
// protected and in this case it is not necessary.
//
LastVerifyDefaultServer = GetTickCount() ;
fVerify = TRUE ;
goto RetryGetDefaultServer ;
}
}
}
BAIL_ON_FAILURE(hr);
if ( (nCount == 0) && !fFastBind)
{
// This object exists but does not have an objectClass. We
// can't do anything without the objectClass. Hence, return
// bad path error.
hr = E_ADS_BAD_PATHNAME;
BAIL_ON_FAILURE(hr);
}
hr = BuildADsParentPathFromObjectInfo2(
pObjectInfo,
&pszParent,
&pszCommonName
);
BAIL_ON_FAILURE(hr);
if (fFastBind) {
hr = CLDAPGenObject::CreateGenericObject(
pszParent,
pszCommonName,
L"Top",
Credentials,
ADS_OBJECT_BOUND,
IID_IADs,
(void **) &pADs,
fFastBind
);
} else {
hr = CLDAPGenObject::CreateGenericObject(
pszParent,
pszCommonName,
aValues,
nCount,
Credentials,
ADS_OBJECT_BOUND,
IID_IADs,
(void **) &pADs,
fFastBind
);
}
BAIL_ON_FAILURE(hr);
//
// InstantiateDerivedObject should add-ref this pointer for us.
//
hr = pADs->QueryInterface(
IID_IUnknown,
ppObject
);
BAIL_ON_FAILURE(hr);
break;
}
error:
if (pADs)
pADs->Release();
if ( aValues )
LdapValueFree( aValues );
if ( pszLDAPServer )
FreeADsStr( pszLDAPServer );
if (pszLDAPDn) {
FreeADsStr(pszLDAPDn);
}
if ( pszParent )
FreeADsStr( pszParent );
if ( pszCommonName )
FreeADsStr( pszCommonName );
// If ld is open, we need to close it, note that if the object
// was created successfuly, the Generic object created will have
// the outstanding reference, if not the connection will be torn
// down as should be expected.
if (ld) {
LdapCloseObject(ld);
}
RRETURN(hr);
}
HRESULT
GetObject(
LPTSTR szBuffer,
CCredentials& Credentials,
LPVOID * ppObject
)
{
HRESULT hr = S_OK;
OBJECTINFO ObjectInfo;
POBJECTINFO pObjectInfo = &ObjectInfo;
if (!szBuffer || !ppObject) {
hr = E_INVALIDARG;
RRETURN_EXP_IF_ERR(hr);
}
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
pObjectInfo->ObjectType = TOKEN_LDAPOBJECT;
hr = ADsObject(szBuffer, pObjectInfo);
BAIL_ON_FAILURE(hr);
switch (pObjectInfo->dwServerPresent) {
case TRUE:
hr = GetServerBasedObject(
szBuffer,
pObjectInfo,
Credentials,
ppObject
);
break;
case FALSE:
hr = GetServerLessBasedObject(
szBuffer,
pObjectInfo,
Credentials,
ppObject
);
}
BAIL_ON_FAILURE(hr);
error:
if (pObjectInfo) {
FreeObjectInfo(pObjectInfo);
}
RRETURN_EXP_IF_ERR(hr);
}