|
|
//
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
//
// ***************************************************************************
//
// Original Author: Rajesh Rao
//
// $Author: rajeshr $
// $Date: 6/11/98 4:43p $
// $Workfile:ldapcach.cpp $
//
// $Modtime: 6/11/98 11:21a $
// $Revision: 1 $
// $Nokeywords: $
//
//
// Description: Cache for LDAP Schema objects.
//
//***************************************************************************
#include "precomp.h"
// Initialize the statics
LPCWSTR CLDAPCache :: ROOT_DSE_PATH = L"LDAP://RootDSE"; LPCWSTR CLDAPCache :: SCHEMA_NAMING_CONTEXT = L"schemaNamingContext"; LPCWSTR CLDAPCache :: LDAP_PREFIX = L"LDAP://"; LPCWSTR CLDAPCache :: LDAP_TOP_PREFIX = L"LDAP://CN=top,"; LPCWSTR CLDAPCache :: RIGHT_BRACKET = L")"; LPCWSTR CLDAPCache :: OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA = L"(objectCategory=attributeSchema)";
DWORD CLDAPCache::dwLDAPCacheCount = 0;
//***************************************************************************
//
// CLDAPCache::CLDAPCache
//
// Purpose : Constructor. Fills in the cache with all the properties in LDAP.
//
// Parameters:
// dsLog : The CDSLog object onto which logging will be done.
//***************************************************************************
CLDAPCache :: CLDAPCache() { dwLDAPCacheCount++; m_isInitialized = FALSE; m_pDirectorySearchSchemaContainer = NULL;
// Initialize the search preferences often used
m_pSearchInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; m_pSearchInfo[0].vValue.dwType = ADSTYPE_INTEGER; m_pSearchInfo[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
m_pSearchInfo[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; m_pSearchInfo[1].vValue.dwType = ADSTYPE_INTEGER; m_pSearchInfo[1].vValue.Integer = 64;
/*
m_pSearchInfo[2].dwSearchPref = ADS_SEARCHPREF_CACHE_RESULTS; m_pSearchInfo[2].vValue.dwType = ADSTYPE_BOOLEAN; m_pSearchInfo[2].vValue.Boolean = 0; */
m_lpszSchemaContainerSuffix = NULL; m_lpszSchemaContainerPath = NULL; // Get the ADSI path of the schema container and store it for future use
//========================================================================
IADs *pRootDSE = NULL; HRESULT result; if(SUCCEEDED(result = ADsOpenObject((LPWSTR)ROOT_DSE_PATH, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IADs, (LPVOID *) &pRootDSE))) { // Get the location of the schema container
BSTR strSchemaPropertyName = SysAllocString((LPWSTR) SCHEMA_NAMING_CONTEXT);
// Get the schemaNamingContext property. This property contains the ADSI path
// of the schema container
VARIANT variant; VariantInit(&variant); if(SUCCEEDED(result = pRootDSE->Get(strSchemaPropertyName, &variant))) { // Store the ADSI path to the schema container
m_lpszSchemaContainerSuffix = NULL; if(m_lpszSchemaContainerSuffix = new WCHAR[wcslen(variant.bstrVal) + 1]) { wcscpy(m_lpszSchemaContainerSuffix, variant.bstrVal ); g_pLogObject->WriteW( L"CLDAPCache :: Got Schema Container as : %s\r\n", m_lpszSchemaContainerSuffix); }
// Form the schema container path
//==================================
m_lpszSchemaContainerPath = NULL; if(m_lpszSchemaContainerPath = new WCHAR[wcslen(LDAP_PREFIX) + wcslen(m_lpszSchemaContainerSuffix) + 1]) { wcscpy(m_lpszSchemaContainerPath, LDAP_PREFIX); wcscat(m_lpszSchemaContainerPath, m_lpszSchemaContainerSuffix); m_isInitialized = TRUE; /*
if(SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer))) {
g_pLogObject->WriteW( L"CLDAPCache :: Got IDirectorySearch on Schema Container \r\n");
if(SUCCEEDED(result = InitializeObjectTree())) { m_isInitialized = TRUE; } else g_pLogObject->WriteW( L"CLDAPCache :: InitializeObjectTree() FAILED : %x \r\n", result); } else g_pLogObject->WriteW( L"CLDAPCache :: FAILED to get IDirectorySearch on Schema Container : %x\r\n", result); */ } } else g_pLogObject->WriteW( L"CLDAPCache :: Get on RootDSE FAILED : %x\r\n", result);
SysFreeString(strSchemaPropertyName); VariantClear(&variant); pRootDSE->Release();
} else g_pLogObject->WriteW( L"CLDAPClassProvider :: InitializeLDAPProvider ADsOpenObject on RootDSE FAILED : %x\r\n", result);
}
//***************************************************************************
//
// CLDAPCache::~CLDAPCache
//
// Purpose : Destructor
//
//***************************************************************************
CLDAPCache :: ~CLDAPCache() { dwLDAPCacheCount--; if(m_pDirectorySearchSchemaContainer) m_pDirectorySearchSchemaContainer->Release();
delete [] m_lpszSchemaContainerSuffix; delete [] m_lpszSchemaContainerPath; }
//***************************************************************************
//
// CLDAPCache::GetProperty
//
// Purpose : Retreives the IDirectory interface of an LDAP property
//
// Parameters:
// lpszPropertyName : The name of the LDAP Property to be retreived
// ppADSIProperty : The address of the pointer where the CADSIProperty object will be placed
// bWBEMName : True if the lpszPropertyName is the WBEM name. False, if it is the LDAP name
//
// Return value:
// The COM value representing the return status. The user should release the object when done.
//
//***************************************************************************
HRESULT CLDAPCache :: GetProperty(LPCWSTR lpszPropertyName, CADSIProperty **ppADSIProperty, BOOLEAN bWBEMName) { HRESULT result = E_FAIL;
// Get the LDAP property name from the WBEM class name
LPWSTR lpszLDAPPropertyName = NULL; if(bWBEMName) lpszLDAPPropertyName = CLDAPHelper::UnmangleWBEMNameToLDAP(lpszPropertyName); else lpszLDAPPropertyName = (LPWSTR)lpszPropertyName; // Save a copy by casting, be careful when deleting
try { // This is a cached implementation
// Check the object tree first
//===================================
if((*ppADSIProperty) = (CADSIProperty *) m_objectTree.GetElement(lpszLDAPPropertyName)) { // Found it in the tree. Nothing more to be done. It has already been 'addreff'ed
result = S_OK; } else // Get it from ADSI
{ if(!m_pDirectorySearchSchemaContainer) { if(!SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer))) result = E_FAIL; } else result = S_OK;
if(SUCCEEDED(result)) { // Search for the property
LPWSTR lpszQuery = NULL; if(lpszQuery = new WCHAR[ wcslen(OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA) + wcslen(LDAP_DISPLAY_NAME_ATTR) + wcslen(lpszLDAPPropertyName) + 20]) { try { wcscpy(lpszQuery, LEFT_BRACKET_STR); wcscat(lpszQuery, AMPERSAND_STR); wcscat(lpszQuery, OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA); wcscat(lpszQuery, LEFT_BRACKET_STR); wcscat(lpszQuery, LDAP_DISPLAY_NAME_ATTR); wcscat(lpszQuery, EQUALS_STR); wcscat(lpszQuery, lpszLDAPPropertyName); wcscat(lpszQuery, RIGHT_BRACKET_STR); wcscat(lpszQuery, RIGHT_BRACKET_STR);
ADS_SEARCH_HANDLE hADSSearchOuter; if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->ExecuteSearch(lpszQuery, NULL, -1, &hADSSearchOuter))) { try { if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetNextRow(hADSSearchOuter)) && result != S_ADS_NOMORE_ROWS) { *ppADSIProperty = NULL; if(*ppADSIProperty = new CADSIProperty()) { try { // Fill in the details of the property
if(SUCCEEDED(result = FillInAProperty(*ppADSIProperty, hADSSearchOuter))) { // Add the property to the tree
m_objectTree.AddElement((*ppADSIProperty)->GetADSIPropertyName(), *ppADSIProperty); // No need to release it since we're returning it
} else { delete *ppADSIProperty; *ppADSIProperty = NULL; } } catch ( ... ) { delete *ppADSIProperty; *ppADSIProperty = NULL;
throw; } } else result = E_OUTOFMEMORY; } } catch ( ... ) { m_pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter); throw; }
m_pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter); } } catch ( ... ) { delete [] lpszQuery; throw; }
delete [] lpszQuery; } else result = E_OUTOFMEMORY; } } } catch ( ... ) { if(bWBEMName) { delete[] lpszLDAPPropertyName; lpszLDAPPropertyName = NULL; } throw; }
// Delete only what was allocated in this function
//================================================
if(bWBEMName) { delete[] lpszLDAPPropertyName; lpszLDAPPropertyName = NULL; }
return result; }
//***************************************************************************
//
// CLDAPCache::GetClass
//
// Purpose : See Header File
//
//***************************************************************************
HRESULT CLDAPCache :: GetClass(LPCWSTR lpszWBEMClassName, LPCWSTR lpszLDAPClassName, CADSIClass **ppADSIClass) { /************************************************************
************************************************************* ***** NO Cache implementation for now. Always fetch everytime ************************************************************* *************************************************************/
*ppADSIClass = NULL; if(!(*ppADSIClass = new CADSIClass(lpszWBEMClassName, lpszLDAPClassName)) ) return E_OUTOFMEMORY;
HRESULT result = E_FAIL;
try { if(!m_pDirectorySearchSchemaContainer) { if(!SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer))) result = E_FAIL; } else result = S_OK;
if(SUCCEEDED(result)) { result = CLDAPHelper::GetLDAPClassFromLDAPName(m_pDirectorySearchSchemaContainer, m_lpszSchemaContainerSuffix, m_pSearchInfo, 2, *ppADSIClass ); } } catch ( ... ) { // at least GetLDAPClassFromLDAPName throws
delete *ppADSIClass; *ppADSIClass = NULL;
throw; }
if(!SUCCEEDED(result)) { delete *ppADSIClass; *ppADSIClass = NULL; }
return result; }
//***************************************************************************
//
// CLDAPCache::GetSchemaContainerSearch
//
// Purpose : To return the IDirectorySearch interface on the schema container
//
// Parameters:
// ppDirectorySearch : The address where the pointer to the required interface will
// be stored.
//
//
// Return Value: The COM result representing the status. The user should release
// the interface pointer when done with it.
//***************************************************************************
HRESULT CLDAPCache :: GetSchemaContainerSearch(IDirectorySearch ** ppDirectorySearch) { if(m_pDirectorySearchSchemaContainer) { *ppDirectorySearch = m_pDirectorySearchSchemaContainer; (*ppDirectorySearch)->AddRef(); return S_OK; } else return E_FAIL;
}
//***************************************************************************
//
// CLDAPCache::EnumerateClasses
//
// Purpose : See Header
//
//***************************************************************************
HRESULT CLDAPCache::EnumerateClasses(LPCWSTR lpszWBEMSuperclass, BOOLEAN bDeep, LPWSTR **pppADSIClasses, DWORD *pdwNumRows, BOOLEAN bArtificialClass) { // Get the LDAP name of the super class
// Do not mangle if it one of the classes that we know
//=====================================================
LPWSTR lpszLDAPSuperClassName = NULL; if(_wcsicmp(lpszWBEMSuperclass, LDAP_BASE_CLASS) != 0) { lpszLDAPSuperClassName = CLDAPHelper::UnmangleWBEMNameToLDAP(lpszWBEMSuperclass); if(!lpszLDAPSuperClassName) // We were returned a NULL by the Unmangler, so not a DS class
{ *pppADSIClasses = NULL; *pdwNumRows = 0; return S_OK; } }
HRESULT result = E_FAIL; if(!m_pDirectorySearchSchemaContainer) { if(!SUCCEEDED(result = ADsOpenObject(m_lpszSchemaContainerPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *) &m_pDirectorySearchSchemaContainer))) result = E_FAIL; } else result = S_OK;
if(SUCCEEDED(result)) { result = CLDAPHelper::EnumerateClasses(m_pDirectorySearchSchemaContainer, m_lpszSchemaContainerSuffix, m_pSearchInfo, 2, lpszLDAPSuperClassName, bDeep, pppADSIClasses, pdwNumRows, bArtificialClass); }
// If the superclass is an artificial class like "ADS_User", then a concrete sub-class "DS_User" exists.
// This is added manually here, to both the EnumInfoList as well as the structure being returned
// The above call to EnumerateClasses would have helpfully left an extra element unfilled at the beginning
// of the array
if(SUCCEEDED(result) && bArtificialClass) { (*pppADSIClasses)[0] = NULL; if((*pppADSIClasses)[0] = new WCHAR[wcslen(lpszWBEMSuperclass+1) + 1]) wcscpy((*pppADSIClasses)[0], lpszWBEMSuperclass+1); else result = E_OUTOFMEMORY; }
delete[] lpszLDAPSuperClassName; return result; }
//***************************************************************************
//
// CLDAPCache::IsInitialized
//
// Purpose : Indicates whether the cache was created and initialized succeddfully
//
// Parameters:
// None
//
// Return value:
// A boolean value indicating the status
//
//***************************************************************************
BOOLEAN CLDAPCache :: IsInitialized() { return m_isInitialized; }
//***************************************************************************
//
// CLDAPCache :: InitializeObjectTree
//
// Purpose : Initialize the lexically ordered binary tree with all the properties
// LDAP
//
// Parameters:
// None
//
// Return Value: The COM status representing the return value
//***************************************************************************
HRESULT CLDAPCache :: InitializeObjectTree() { // Get the attributes of all the instances of the
// class "AttributeSchema"
//=================================================
HRESULT result = E_FAIL;
/*
// Now perform a search for all the attributes
//============================================
if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->SetSearchPreference(m_pSearchInfo, 2))) { ADS_SEARCH_HANDLE hADSSearchOuter; // Count of attributes
DWORD dwCount = 0;
if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->ExecuteSearch((LPWSTR)OBJECT_CATEGORY_EQUALS_ATTRIBUTE_SCHEMA, NULL, -1, &hADSSearchOuter))) { CADSIProperty *pNextProperty; while(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetNextRow(hADSSearchOuter)) && result != S_ADS_NOMORE_ROWS) { pNextProperty = new CADSIProperty(); dwCount ++;
// Fill in the details of the property
FillInAProperty(pNextProperty, hADSSearchOuter);
// Add the property to the tree
m_objectTree.AddElement(pNextProperty->GetADSIPropertyName(), pNextProperty); pNextProperty->Release(); } m_pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter); }
g_pLogObject->WriteW( L"CLDAPCache :: InitializeObjectTree() Initialized with %d attributes\r\n", dwCount); } else g_pLogObject->WriteW( L"CLDAPCache :: InitializeObjectTree() SetSearchPreference() FAILED with %x\r\n", result);
*/ return result; }
HRESULT CLDAPCache :: FillInAProperty(CADSIProperty *pNextProperty, ADS_SEARCH_HANDLE hADSSearchOuter) { ADS_SEARCH_COLUMN adsNextColumn; HRESULT result = E_FAIL; LPWSTR lpszWBEMName = NULL; BOOLEAN bNeedToCheckForORName = FALSE; if(SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)ATTRIBUTE_SYNTAX_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else { pNextProperty->SetSyntaxOID(adsNextColumn.pADsValues->CaseIgnoreString); if(_wcsicmp(adsNextColumn.pADsValues->CaseIgnoreString, DN_WITH_BINARY_OID) == 0) bNeedToCheckForORName = TRUE; } m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)IS_SINGLE_VALUED_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else pNextProperty->SetMultiValued( (adsNextColumn.pADsValues->Boolean)? FALSE : TRUE); m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)ATTRIBUTE_ID_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else pNextProperty->SetAttributeID(adsNextColumn.pADsValues->CaseIgnoreString); m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)COMMON_NAME_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else pNextProperty->SetCommonName(adsNextColumn.pADsValues->CaseIgnoreString); m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)LDAP_DISPLAY_NAME_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else { pNextProperty->SetADSIPropertyName(adsNextColumn.pADsValues->CaseIgnoreString); lpszWBEMName = CLDAPHelper::MangleLDAPNameToWBEM(adsNextColumn.pADsValues->CaseIgnoreString); pNextProperty->SetWBEMPropertyName(lpszWBEMName); delete []lpszWBEMName; } m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
if(SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)MAPI_ID_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else pNextProperty->SetMAPI_ID(adsNextColumn.pADsValues->Integer); m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
if(SUCCEEDED(result) && SUCCEEDED(result = m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)OM_SYNTAX_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else pNextProperty->SetOMSyntax(adsNextColumn.pADsValues->Integer); m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
if(bNeedToCheckForORName && SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)OM_OBJECT_CLASS_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else { // Just the first octet in the LPBYTE array is enough for differntiating between ORName and DNWithBinary
if((adsNextColumn.pADsValues->OctetString).lpValue[0] == 0x56) pNextProperty->SetORName(TRUE); } m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
if(SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)SEARCH_FLAGS_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else pNextProperty->SetSearchFlags(adsNextColumn.pADsValues->Integer); m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
if(SUCCEEDED(result) && SUCCEEDED(m_pDirectorySearchSchemaContainer->GetColumn( hADSSearchOuter, (LPWSTR)SYSTEM_ONLY_ATTR, &adsNextColumn ))) { if(adsNextColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) result = E_FAIL; else pNextProperty->SetSystemOnly(TRUE); m_pDirectorySearchSchemaContainer->FreeColumn( &adsNextColumn ); }
return result; }
|