//--------------------------------------------------------------------------- // // 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); }