Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1257 lines
39 KiB

//
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
//
// ***************************************************************************
//
// Original Author: Rajesh Rao
//
// $Author: rajeshr $
// $Date: 6/11/98 4:43p $
// $Workfile:ldaphelp.cpp $
//
// $Modtime: 6/11/98 11:21a $
// $Revision: 1 $
// $Nokeywords: $
//
//
// Description: Contains the implementation the CLDAPHelper class. This is
// a class that has many static helper functions pertaining to ADSI LDAP Provider
//***************************************************************************
/////////////////////////////////////////////////////////////////////////
#include "precomp.h"
LPCWSTR CLDAPHelper :: LDAP_CN_EQUALS = L"LDAP://CN=";
LPCWSTR CLDAPHelper :: LDAP_DISP_NAME_EQUALS = L"(lDAPDisplayName=";
LPCWSTR CLDAPHelper :: OBJECT_CATEGORY_EQUALS_CLASS_SCHEMA = L"(objectCategory=classSchema)";
LPCWSTR CLDAPHelper :: SUB_CLASS_OF_EQUALS = L"(subclassOf=";
LPCWSTR CLDAPHelper :: NOT_LDAP_NAME_EQUALS = L"(!ldapDisplayName=";
LPCWSTR CLDAPHelper :: LEFT_BRACKET_AND = L"(&";
LPCWSTR CLDAPHelper :: GOVERNS_ID_EQUALS = L"(governsId=";
LPCWSTR CLDAPHelper :: CLASS_SCHEMA = L"classSchema";
LPCWSTR CLDAPHelper :: CN_EQUALS = L"cn=";
//***************************************************************************
//
// CLDAPHelper :: GetLDAPClassFromLDAPName
//
// Purpose : See Header
//***************************************************************************
HRESULT CLDAPHelper :: GetLDAPClassFromLDAPName(
IDirectorySearch *pDirectorySearchSchemaContainer,
LPCWSTR lpszSchemaContainerSuffix,
PADS_SEARCHPREF_INFO pSearchInfo,
DWORD dwSearchInfoCount,
CADSIClass *pADSIClass
)
{
// We map the object from the LDAP Display name
// Hence we cannot directly do an ADsOpenObject().
// We have to send an LDAP query for the instance of ClassSchema/AttributeSchema where the
// ldapdisplayname attribute is the lpszObjectName parameter.
HRESULT result = E_FAIL;
// For the search filter;
LPCWSTR lpszLDAPObjectName = pADSIClass->GetADSIClassName();
LPWSTR lpszSearchFilter = NULL;
if(lpszSearchFilter = new WCHAR[ wcslen(LDAP_DISP_NAME_EQUALS) + wcslen(lpszLDAPObjectName) + wcslen(RIGHT_BRACKET_STR) + 1])
{
try
{
wcscpy(lpszSearchFilter, LDAP_DISP_NAME_EQUALS);
wcscat(lpszSearchFilter, lpszLDAPObjectName);
wcscat(lpszSearchFilter, RIGHT_BRACKET_STR);
ADS_SEARCH_HANDLE hADSSearch;
if(SUCCEEDED(result = pDirectorySearchSchemaContainer->ExecuteSearch(lpszSearchFilter, NULL, -1, &hADSSearch)))
{
try
{
if(SUCCEEDED(result = pDirectorySearchSchemaContainer->GetNextRow(hADSSearch)) && result != S_ADS_NOMORE_ROWS)
{
// Get the column for the CN attribute
ADS_SEARCH_COLUMN adsColumn;
// Store each of the LDAP class attributes
// Reset the LDAP and WBEM names to take care of change in case
if(SUCCEEDED(result) && SUCCEEDED(result = pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)LDAP_DISPLAY_NAME_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
{
pADSIClass->SetADSIClassName(adsColumn.pADsValues->CaseIgnoreString);
LPWSTR lpszWBEMName = CLDAPHelper::MangleLDAPNameToWBEM(adsColumn.pADsValues->CaseIgnoreString);
try
{
pADSIClass->SetWBEMClassName(lpszWBEMName);
}
catch ( ... )
{
delete [] lpszWBEMName;
throw;
}
delete [] lpszWBEMName;
}
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
// Store each of the LDAP class attributes
if(SUCCEEDED(result) && SUCCEEDED(result = pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)COMMON_NAME_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetCommonName(adsColumn.pADsValues->CaseIgnoreString);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
// Special case for top since ADSI returns "top" as the parent class of "top" and we
// will go into an infinite loop later if we dont check this
if(pADSIClass->GetCommonName() && _wcsicmp(pADSIClass->GetCommonName(), TOP_CLASS) != 0)
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
{
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)SUB_CLASS_OF_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetSuperClassLDAPName(adsColumn.pADsValues->CaseIgnoreString);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
}
}
if(SUCCEEDED(result) && SUCCEEDED(result = pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)GOVERNS_ID_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetGovernsID(adsColumn.pADsValues->CaseIgnoreString);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(result = pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)SCHEMA_ID_GUID_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetSchemaIDGUID((adsColumn.pADsValues->OctetString).lpValue, (adsColumn.pADsValues->OctetString).dwLength);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)RDN_ATT_ID_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetRDNAttribute(adsColumn.pADsValues->CaseIgnoreString);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)DEFAULT_SECURITY_DESCRP_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetDefaultSecurityDescriptor(adsColumn.pADsValues->CaseIgnoreString);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(result = pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)OBJECT_CLASS_CATEGORY_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetObjectClassCategory(adsColumn.pADsValues->Integer);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
/*
if(SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)NT_SECURITY_DESCRIPTOR_ATTR, &adsColumn)))
{
pADSIClass->SetNTSecurityDescriptor((adsColumn.pADsValues->SecurityDescriptor).lpValue, (adsColumn.pADsValues->SecurityDescriptor).dwLength);
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
*/
if(SUCCEEDED(result) && SUCCEEDED(result = pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)DEFAULT_OBJECTCATEGORY_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
{
// Get the LDAPDIpslayName of the class
LPWSTR lpszLDAPName = NULL;
if(SUCCEEDED(result) && SUCCEEDED(result = GetLDAPClassNameFromCN(adsColumn.pADsValues->DNString, &lpszLDAPName)))
{
try
{
pADSIClass->SetDefaultObjectCategory(lpszLDAPName);
}
catch ( ... )
{
delete [] lpszLDAPName;
throw;
}
delete [] lpszLDAPName;
}
}
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)SYSTEM_ONLY_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetSystemOnly((BOOLEAN)adsColumn.pADsValues->Boolean);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)AUXILIARY_CLASS_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetAuxiliaryClasses(adsColumn.pADsValues, adsColumn.dwNumValues);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)SYSTEM_AUXILIARY_CLASS_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetSystemAuxiliaryClasses(adsColumn.pADsValues, adsColumn.dwNumValues);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)SYSTEM_MAY_CONTAIN_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetSystemMayContains(adsColumn.pADsValues, adsColumn.dwNumValues);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)MAY_CONTAIN_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetMayContains(adsColumn.pADsValues, adsColumn.dwNumValues);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)SYSTEM_MUST_CONTAIN_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetSystemMustContains(adsColumn.pADsValues, adsColumn.dwNumValues);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)MUST_CONTAIN_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetMustContains(adsColumn.pADsValues, adsColumn.dwNumValues);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)SYSTEM_POSS_SUPERIORS_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetSystemPossibleSuperiors(adsColumn.pADsValues, adsColumn.dwNumValues);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
if(SUCCEEDED(result) && SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearch, (LPWSTR)POSS_SUPERIORS_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
pADSIClass->SetPossibleSuperiors(adsColumn.pADsValues, adsColumn.dwNumValues);
}
catch ( ... )
{
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
throw;
}
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
}
else
result = E_FAIL;
}
catch ( ... )
{
// Close the search
pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearch);
throw;
}
// Close the search
pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearch);
}
}
catch ( ... )
{
if ( lpszSearchFilter )
{
// Delete the filter
delete [] lpszSearchFilter;
lpszSearchFilter = NULL;
}
throw;
}
if ( lpszSearchFilter )
{
// Delete the filter
delete [] lpszSearchFilter;
lpszSearchFilter = NULL;
}
}
else
result = E_OUTOFMEMORY;
return result;
}
//***************************************************************************
//
// CLDAPHelper :: GetLDAPSchemaObjectFromCommonName
//
// Purpose : To fetch the IDirectoryObject interface on a class/property provided by the LDAP Provider
// Parameters:
// lpszSchemaContainerSuffix : The suffix to be used. The actual object fetced will be:
// LDAP://CN=<lpszCommonName>,<lpszSchemaContainerSuffix>
// lpszCommonName : The 'cn' attribute of the LDAP class or property to be fetched.
// ppLDAPObject : The address where the pointer to IDirectoryObject will be stored
// It is the caller's responsibility to delete the object when done with it
//
// Return Value: The COM status value indicating the status of the request.
//***************************************************************************
HRESULT CLDAPHelper :: GetLDAPSchemaObjectFromCommonName(
LPCWSTR lpszSchemaContainerSuffix,
LPCWSTR lpszCommonName,
IDirectoryObject **ppLDAPObject)
{
HRESULT result = S_OK;
// Form the ADSI path to the LDAP object
LPWSTR lpszLDAPObjectPath = NULL;
if(lpszLDAPObjectPath = new WCHAR[wcslen(LDAP_CN_EQUALS) + wcslen(lpszCommonName) + wcslen(COMMA_STR) + wcslen(lpszSchemaContainerSuffix) + 1])
{
wcscpy(lpszLDAPObjectPath, LDAP_CN_EQUALS);
wcscat(lpszLDAPObjectPath, lpszCommonName);
wcscat(lpszLDAPObjectPath, COMMA_STR);
wcscat(lpszLDAPObjectPath, lpszSchemaContainerSuffix);
result = ADsOpenObject(lpszLDAPObjectPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject, (LPVOID *)ppLDAPObject);
delete[] lpszLDAPObjectPath;
}
else
result = E_OUTOFMEMORY;
return result;
}
//***************************************************************************
//
// CLDAPHelper :: GetLDAPClassNameFromCN
//
// Purpose : To fetch the LDAPDisplayNAme of a class from its path
// Parameters:
//
// lpszLDAPClassPath : The path to the class object without the LDAP prefix. Ex CN=user,CN=Schema, CN=COnfiguration ...
// Return Value: The COM status value indicating the status of the request. The user should delete the
// name returned, when done
//***************************************************************************
HRESULT CLDAPHelper :: GetLDAPClassNameFromCN(LPCWSTR lpszLDAPClassPath,
LPWSTR *lppszLDAPName)
{
IDirectoryObject *pLDAPClass = NULL;
// Prepend the LDAP:// perfix
LPWSTR lpszRealPath = NULL;
HRESULT result = S_OK;
if(lpszRealPath = new WCHAR[ wcslen(LDAP_PREFIX) + wcslen(lpszLDAPClassPath) + 1])
{
wcscpy(lpszRealPath, LDAP_PREFIX);
wcscat(lpszRealPath, lpszLDAPClassPath);
result = ADsOpenObject(lpszRealPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject, (LPVOID *)&pLDAPClass);
delete [] lpszRealPath;
}
else
result = E_OUTOFMEMORY;
// Get the attribute LDAPDisplayName
if(SUCCEEDED(result))
{
PADS_ATTR_INFO pAttributes = NULL;
DWORD dwReturnCount = 0;
if(SUCCEEDED(result = pLDAPClass->GetObjectAttributes((LPWSTR *)&LDAP_DISPLAY_NAME_ATTR, 1, &pAttributes, &dwReturnCount)) && dwReturnCount == 1)
{
if(pAttributes->pADsValues->dwType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
{
*lppszLDAPName = NULL;
if(*lppszLDAPName = new WCHAR[wcslen(pAttributes->pADsValues->DNString) + 1])
wcscpy(*lppszLDAPName, pAttributes->pADsValues->DNString);
else
result = E_OUTOFMEMORY;
}
FreeADsMem((LPVOID *)pAttributes);
}
pLDAPClass->Release();
}
return result;
}
//***************************************************************************
//
// CLDAPHelper :: EnumerateClasses
//
// Purpose : See Header
//***************************************************************************
HRESULT CLDAPHelper :: EnumerateClasses(
IDirectorySearch *pDirectorySearchSchemaContainer,
LPCWSTR lpszSchemaContainerSuffix,
PADS_SEARCHPREF_INFO pSearchInfo,
DWORD dwSearchInfoCount,
LPCWSTR lpszLDAPSuperClass,
BOOLEAN bDeep,
LPWSTR **pppszClassNames,
DWORD *pdwNumRows,
BOOLEAN bArtificialClass)
{
// Initialize the return values
HRESULT result = E_FAIL;
*pdwNumRows = 0;
// The search filter;
LPWSTR lpszSearchFilter = NULL;
// There's various cases to be considered here.
// if(lpszLDAPSuperClass is NULL)
// then
// if bDeep is false, then no objects is returned (since we do not provide the LDAP base class
// else all the classes are returned using the filter (objectCategory=classSchema)
// else
// if bDeep is false, then the filter (&(objectCategory=classSchema)(subClassOf=lpszLDAPSuperClass)) is used
// else a lot of work has to be done!
if(lpszLDAPSuperClass == NULL)
{
if(!bDeep)
{
*pppszClassNames = NULL;
*pdwNumRows = 0;
return S_OK;
}
else
{
if(!(lpszSearchFilter = new WCHAR[ wcslen(OBJECT_CATEGORY_EQUALS_CLASS_SCHEMA) + 1]))
return E_OUTOFMEMORY;
wcscpy(lpszSearchFilter, OBJECT_CATEGORY_EQUALS_CLASS_SCHEMA);
}
}
else
{
if(!bDeep)
{
// One would imagine that a filter of the kind
//(&(objectClass=classSchema)(subClassOf=<lpszLDAPSuperClass>))
// would be enough. Unfortunately it also gives the Top class
//in the results when the value of lpszLDAPSuperClass is Top
// we dont need that. Hnce we form the filter
//(&(objectClass=classSchema)(subClassOf=<lpszLDAPSuperClass>)(!ldapDisplayName=<lpszLDAPSuperClass>))
if(lpszSearchFilter = new WCHAR[ wcslen(LEFT_BRACKET_AND) // (&
+ wcslen(OBJECT_CATEGORY_EQUALS_CLASS_SCHEMA) // (objectCategory=classSchema)
+ wcslen(SUB_CLASS_OF_EQUALS) // (subClassOf=
+ wcslen(lpszLDAPSuperClass) // superClass
+ wcslen(RIGHT_BRACKET_STR) // )
+ wcslen(NOT_LDAP_NAME_EQUALS) // (!ldapDisplayName=
+ wcslen(lpszLDAPSuperClass) // superClass
+ 2*wcslen(RIGHT_BRACKET_STR) // ))
+1])
{
wcscpy(lpszSearchFilter, LEFT_BRACKET_AND);
wcscat(lpszSearchFilter, OBJECT_CATEGORY_EQUALS_CLASS_SCHEMA);
wcscat(lpszSearchFilter, SUB_CLASS_OF_EQUALS);
wcscat(lpszSearchFilter, lpszLDAPSuperClass);
wcscat(lpszSearchFilter, RIGHT_BRACKET_STR);
wcscat(lpszSearchFilter, NOT_LDAP_NAME_EQUALS); // (!ldapDisplayName=
wcscat(lpszSearchFilter, lpszLDAPSuperClass);
wcscat(lpszSearchFilter, RIGHT_BRACKET_STR);
wcscat(lpszSearchFilter, RIGHT_BRACKET_STR);
}
else
result = E_OUTOFMEMORY;
}
else
lpszSearchFilter = NULL; // THIS SPECIAL CASE IS TACKLED LATER
}
if(lpszSearchFilter)
{
ADS_SEARCH_HANDLE hADSSearchOuter;
if(SUCCEEDED(result = pDirectorySearchSchemaContainer->ExecuteSearch(lpszSearchFilter, (LPWSTR *)&LDAP_DISPLAY_NAME_ATTR, 1, &hADSSearchOuter)))
{
*pdwNumRows = 0;
DWORD dwFirstCount = 0; // Number of rows retreived on the first count
// Calculate the number of rows first.
while(SUCCEEDED(result = pDirectorySearchSchemaContainer->GetNextRow(hADSSearchOuter)) &&
result != S_ADS_NOMORE_ROWS)
dwFirstCount ++;
// Allocate enough memory for the classes and names
*pppszClassNames = NULL;
if(bArtificialClass)
{
dwFirstCount ++;
if(*pppszClassNames = new LPWSTR [dwFirstCount])
(*pppszClassNames)[0] = NULL;
else
result = E_OUTOFMEMORY;
}
else
{
if(!(*pppszClassNames = new LPWSTR [dwFirstCount]))
result = E_OUTOFMEMORY;
}
// The index of the attribute being processed
DWORD dwSecondCount = 0;
if(bArtificialClass)
dwSecondCount ++;
// Get the columns for the attributes
ADS_SEARCH_COLUMN adsColumn;
// Move to the beginning of the search
if(SUCCEEDED(result = pDirectorySearchSchemaContainer->GetFirstRow(hADSSearchOuter))
&& result != S_ADS_NOMORE_ROWS)
{
// Store each of the LDAP class attributes
if(SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearchOuter, (LPWSTR)LDAP_DISPLAY_NAME_ATTR, &adsColumn)))
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
{
result = E_FAIL;
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
else
{
// Create the CADSIClass
(*pppszClassNames)[dwSecondCount] = NULL;
if((*pppszClassNames)[dwSecondCount] = new WCHAR[wcslen(adsColumn.pADsValues->CaseIgnoreString) + 1])
wcscpy((*pppszClassNames)[dwSecondCount], adsColumn.pADsValues->CaseIgnoreString);
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
dwSecondCount++;
// Get the rest of the rows
while(SUCCEEDED(result = pDirectorySearchSchemaContainer->GetNextRow(hADSSearchOuter))&&
result != S_ADS_NOMORE_ROWS)
{
// Store each of the LDAP class attributes
if(SUCCEEDED(pDirectorySearchSchemaContainer->GetColumn(hADSSearchOuter, (LPWSTR)LDAP_DISPLAY_NAME_ATTR, &adsColumn)))
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
{
result = E_FAIL;
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
}
else
{
// Create the CADSIClass
(*pppszClassNames)[dwSecondCount] = NULL;
if((*pppszClassNames)[dwSecondCount] = new WCHAR[wcslen(adsColumn.pADsValues->CaseIgnoreString) + 1])
wcscpy((*pppszClassNames)[dwSecondCount], adsColumn.pADsValues->CaseIgnoreString);
pDirectorySearchSchemaContainer->FreeColumn( &adsColumn );
dwSecondCount++;
}
}
}
}
}
}
// Something went wrong? Release allocated resources
if(dwSecondCount != dwFirstCount)
{
// Delete the contents of the array
for(DWORD j=0; j<dwSecondCount; j++)
{
delete [] (*pppszClassNames)[j];
}
// Delete the array itself
delete [] (*pppszClassNames);
// Set return values to empty
*pppszClassNames = NULL;
*pdwNumRows = 0;
result = E_FAIL;
}
else
*pdwNumRows = dwFirstCount;
// Close the search
pDirectorySearchSchemaContainer->CloseSearchHandle(hADSSearchOuter);
} // ExecuteSearch() - Outer
delete [] lpszSearchFilter;
}
else // THIS IS THE SPECIAL CASE WHERE ALL SUBCLASSES (RECURSIVELY) OF A GIVEN CLASS ARE REQUIRED
{
// A lot of work has to be done. THis is handled by CLDAPClassProvider. Hence control shold never reach here
result = E_FAIL;
}
return result;
}
// Gets the IDIrectoryObject interface on an ADSI instance
HRESULT CLDAPHelper :: GetADSIInstance(LPCWSTR szADSIPath, CADSIInstance **ppADSIObject, ProvDebugLog *pLogObject)
{
HRESULT result;
IDirectoryObject *pDirectoryObject;
*ppADSIObject = NULL;
try
{
if(SUCCEEDED(result = ADsOpenObject((LPWSTR)szADSIPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject, (LPVOID *)&pDirectoryObject)))
{
if(*ppADSIObject = new CADSIInstance(szADSIPath, pDirectoryObject))
{
PADS_ATTR_INFO pAttributeEntries;
DWORD dwNumAttributes;
if(SUCCEEDED(result = pDirectoryObject->GetObjectAttributes(NULL, -1, &pAttributeEntries, &dwNumAttributes)))
{
(*ppADSIObject)->SetAttributes(pAttributeEntries, dwNumAttributes);
PADS_OBJECT_INFO pObjectInfo = NULL;
if(SUCCEEDED(result = pDirectoryObject->GetObjectInformation(&pObjectInfo)))
{
(*ppADSIObject)->SetObjectInfo(pObjectInfo);
}
else
pLogObject->WriteW( L"CLDAPHelper :: GetADSIInstance GetObjectInformation() FAILED on %s with %x\r\n", szADSIPath, result);
}
else
pLogObject->WriteW( L"CLDAPHelper :: GetADSIInstance GetObjectAttributes() FAILED on %s with %x\r\n", szADSIPath, result);
}
else
result = E_OUTOFMEMORY;
pDirectoryObject->Release();
}
else
pLogObject->WriteW( L"CLDAPHelper :: GetADSIInstance ADsOpenObject() FAILED on %s with %x\r\n", szADSIPath, result);
}
catch ( ... )
{
if ( *ppADSIObject )
{
delete *ppADSIObject;
*ppADSIObject = NULL;
}
throw;
}
if(!SUCCEEDED(result))
{
delete *ppADSIObject;
*ppADSIObject = NULL;
}
return result;
}
//***************************************************************************
//
// CLDAPHelper :: CreateADSIPath
//
// Purpose : Forms the ADSI path from a class or property name
//
// Parameters:
// lpszLDAPSchemaObjectName : The LDAP class or property name
// lpszSchemaContainerSuffix : The suffix to be used. The actual object fetced will be:
// LDAP://CN=<lpszLDAPSchemaObjectName>,<lpszSchemaContainerSuffix>
//
// Return Value: The ADSI path to the class or property object. This has to
// be deallocated by the user
//***************************************************************************
LPWSTR CLDAPHelper :: CreateADSIPath(LPCWSTR lpszLDAPSchemaObjectName,
LPCWSTR lpszSchemaContainerSuffix)
{
LPWSTR lpszADSIObjectPath = NULL;
if(lpszADSIObjectPath = new WCHAR[wcslen(LDAP_CN_EQUALS) + wcslen(lpszLDAPSchemaObjectName) + wcslen(COMMA_STR) + wcslen(lpszSchemaContainerSuffix) + 1])
{
wcscpy(lpszADSIObjectPath, LDAP_CN_EQUALS);
wcscat(lpszADSIObjectPath, lpszLDAPSchemaObjectName);
wcscat(lpszADSIObjectPath, COMMA_STR);
wcscat(lpszADSIObjectPath, lpszSchemaContainerSuffix);
}
return lpszADSIObjectPath;
}
//***************************************************************************
//
// CLDAPHelper :: UnmangleWBEMNameToLDAP
//
// Purpose : Converts a mangled WBEM name to LDAP
// An underscore in LDAP maps to two underscores in WBEM
// An hyphen in LDAP maps to one underscore in WBEM
//
// Parameters:
// lpszWBEMName : The WBEM class or property name
//
// Return Value: The LDAP name to the class or property object. This has to
// be deallocated by the user
//***************************************************************************
LPWSTR CLDAPHelper :: UnmangleWBEMNameToLDAP(LPCWSTR lpszWBEMName)
{
DWORD iPrefixLength = 0;
if(_wcsnicmp(lpszWBEMName, LDAP_ARTIFICIAL_CLASS_NAME_PREFIX, LDAP_ARTIFICIAL_CLASS_NAME_PREFIX_LENGTH) == 0)
{
iPrefixLength = LDAP_ARTIFICIAL_CLASS_NAME_PREFIX_LENGTH;
}
else if (_wcsnicmp(lpszWBEMName, LDAP_CLASS_NAME_PREFIX, LDAP_CLASS_NAME_PREFIX_LENGTH) == 0)
{
iPrefixLength = LDAP_CLASS_NAME_PREFIX_LENGTH;
}
else
return NULL;
// The length of the resulting string (LDAP Name) is bound to be less than of equal to the length of WBEM name
// So let's allocate the same as the wbem name length
DWORD dwWbemNameLength = wcslen(lpszWBEMName) - iPrefixLength;
LPWSTR lpszLDAPName = NULL;
if(lpszLDAPName = new WCHAR[dwWbemNameLength + 1])
{
LPCWSTR lpszWBEMNameWithoutPrefix = lpszWBEMName + iPrefixLength;
DWORD j=0;
for(DWORD i=0; i<dwWbemNameLength; )
{
switch(lpszWBEMNameWithoutPrefix[i])
{
case (L'_'):
if(lpszWBEMNameWithoutPrefix[i+1] == L'_')
{
i += 2;
lpszLDAPName[j++] = L'_';
}
else
{
i++;
lpszLDAPName[j++] = L'-';
}
break;
default:
lpszLDAPName[j++] = lpszWBEMNameWithoutPrefix[i++];
}
}
lpszLDAPName[j] = NULL;
}
return lpszLDAPName;
}
//***************************************************************************
//
// CLDAPHelper :: MangleLDAPNameToWBEM
//
// Purpose : Converts a LDAP name to WBEM by mangling it
// An underscore in LDAP maps to two underscores in WBEM
// An hyphen in LDAP maps to one underscore in WBEM
//
// Parameters:
// lpszLDAPName : The LDAP class or property name
//
// Return Value: The LDAP name to the class or property object. This has to
// be deallocated by the user
//***************************************************************************
LPWSTR CLDAPHelper :: MangleLDAPNameToWBEM(LPCWSTR lpszLDAPName, BOOLEAN bArtificalName)
{
if(!lpszLDAPName)
return NULL;
// The length of the resulting string (WBEM Name) is bound to be less than of equal to twice the length of LDAP name
// So let's allocate double the LDAP name length
DWORD dwLDAPNameLength = wcslen(lpszLDAPName);
DWORD dwPrefixLength = (bArtificalName)? LDAP_ARTIFICIAL_CLASS_NAME_PREFIX_LENGTH : LDAP_CLASS_NAME_PREFIX_LENGTH;
LPWSTR lpszWBEMName = NULL;
if(lpszWBEMName = new WCHAR[2*dwLDAPNameLength + dwPrefixLength + 1])
{
// Prefix "DS_" or "ADS_"
if(bArtificalName)
wcscpy(lpszWBEMName, LDAP_ARTIFICIAL_CLASS_NAME_PREFIX);
else
wcscpy(lpszWBEMName, LDAP_CLASS_NAME_PREFIX);
DWORD j=dwPrefixLength;
for(DWORD i=0; i<dwLDAPNameLength; i++)
{
switch(lpszLDAPName[i])
{
case (__TEXT('-')):
lpszWBEMName[j++] = L'_';
break;
case (__TEXT('_')):
lpszWBEMName[j++] = L'_';
lpszWBEMName[j++] = L'_';
break;
default:
lpszWBEMName[j++] = lpszLDAPName[i];
}
}
lpszWBEMName[j] = NULL;
}
return lpszWBEMName;
}
void CLDAPHelper :: DeleteAttributeContents(PADS_ATTR_INFO pAttribute)
{
// delete the name
delete [] pAttribute->pszAttrName;
// Delete each value
for(DWORD i=0; i<pAttribute->dwNumValues; i++)
DeleteADsValueContents(pAttribute->pADsValues + i);
// Delete the array of values
delete [] pAttribute->pADsValues;
}
void CLDAPHelper :: DeleteADsValueContents(PADSVALUE pValue)
{
switch(pValue->dwType)
{
// Nothing to delete
case ADSTYPE_BOOLEAN:
case ADSTYPE_INTEGER:
case ADSTYPE_LARGE_INTEGER:
break;
case ADSTYPE_UTC_TIME:
case ADSTYPE_DN_STRING:
case ADSTYPE_CASE_EXACT_STRING:
case ADSTYPE_CASE_IGNORE_STRING:
case ADSTYPE_PRINTABLE_STRING:
case ADSTYPE_NUMERIC_STRING:
delete [] pValue->DNString;
break;
case ADSTYPE_OCTET_STRING:
case ADSTYPE_NT_SECURITY_DESCRIPTOR:
delete [] (pValue->OctetString.lpValue);
break;
case ADSTYPE_DN_WITH_BINARY:
delete [] (pValue->pDNWithBinary->lpBinaryValue);
delete [] (pValue->pDNWithBinary->pszDNString);
delete pValue->pDNWithBinary;
break;
case ADSTYPE_DN_WITH_STRING:
delete [] (pValue->pDNWithString->pszStringValue);
delete [] (pValue->pDNWithString->pszDNString);
delete pValue->pDNWithString;
break;
default:
// Cause a Null Pointer violation intentionally
// Otherwise we leak memory
{
assert(0);
}
break;
}
}
//***************************************************************************
//
// CLDAPHelper :: ExecuteQuery
//
// Purpose : See Header
//***************************************************************************
HRESULT CLDAPHelper :: ExecuteQuery(
LPCWSTR pszPathToRoot,
PADS_SEARCHPREF_INFO pSearchInfo,
DWORD dwSearchInfoCount,
LPCWSTR pszLDAPQuery,
CADSIInstance ***pppADSIInstances,
DWORD *pdwNumRows,
ProvDebugLog *pLogObject)
{
// Initialize the return values
HRESULT result = E_FAIL;
*pdwNumRows = 0;
*pppADSIInstances = NULL;
// Bind to the node from which the search should start
IDirectorySearch *pDirectorySearchContainer = NULL;
if(SUCCEEDED(result = ADsOpenObject((LPWSTR)pszPathToRoot, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID *)&pDirectorySearchContainer)))
{
try
{
// Now perform a search for the attribute DISTINGUISHED_NAME_ATTR name
if(SUCCEEDED(result = pDirectorySearchContainer->SetSearchPreference(pSearchInfo, dwSearchInfoCount)))
{
ADS_SEARCH_HANDLE hADSSearchOuter;
if(SUCCEEDED(result = pDirectorySearchContainer->ExecuteSearch((LPWSTR) pszLDAPQuery, (LPWSTR *)&ADS_PATH_ATTR, 1, &hADSSearchOuter)))
{
*pdwNumRows = 0;
// Calculate the number of rows first.
while(SUCCEEDED(result = pDirectorySearchContainer->GetNextRow(hADSSearchOuter)) &&
result != S_ADS_NOMORE_ROWS)
(*pdwNumRows) ++;
try
{
// Do only if there were any rows
if(*pdwNumRows)
{
// The index of the attribute being processed
DWORD i = 0;
// Allocate enough memory for the classes and names
*pppADSIInstances = NULL;
if(*pppADSIInstances = new CADSIInstance * [*pdwNumRows])
{
try
{
// Get the columns for the attributes
ADS_SEARCH_COLUMN adsColumn;
CADSIInstance *pADSIInstance = NULL;
// Move to the first row
if (SUCCEEDED(result = pDirectorySearchContainer->GetFirstRow(hADSSearchOuter))&&
result != S_ADS_NOMORE_ROWS)
{
// Store each of the LDAP class attributes
if(SUCCEEDED(pDirectorySearchContainer->GetColumn(hADSSearchOuter, (LPWSTR)ADS_PATH_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
{
// Create the CADSIInstance
// Now get the attributes on this object
if(SUCCEEDED(result = GetADSIInstance(adsColumn.pADsValues->DNString, &pADSIInstance, pLogObject)))
{
(*pppADSIInstances)[i] = pADSIInstance;
i++;
}
else
pLogObject->WriteW( L"CLDAPHelper :: ExecuteQuery GetADSIInstance() FAILED on %s with %x\r\n", adsColumn.pADsValues->DNString, result);
}
}
catch ( ... )
{
pDirectorySearchContainer->FreeColumn( &adsColumn );
throw;
}
// Free resouces
pDirectorySearchContainer->FreeColumn( &adsColumn );
}
else
pLogObject->WriteW( L"CLDAPHelper :: ExecuteQuery GetColumn() FAILED on %s with %x\r\n", pszLDAPQuery, result);
// Get the other rows now
if(SUCCEEDED(result))
{
while(SUCCEEDED(result = pDirectorySearchContainer->GetNextRow(hADSSearchOuter))&&
result != S_ADS_NOMORE_ROWS)
{
// Store each of the LDAP class attributes
if(SUCCEEDED(pDirectorySearchContainer->GetColumn(hADSSearchOuter, (LPWSTR)ADS_PATH_ATTR, &adsColumn)))
{
try
{
if(adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC)
result = E_FAIL;
else
{
// Create the CADSIInstance
// Now get the attributes on this object
if(SUCCEEDED(result = GetADSIInstance(adsColumn.pADsValues->DNString, &pADSIInstance, pLogObject)))
{
(*pppADSIInstances)[i] = pADSIInstance;
i++;
}
else
pLogObject->WriteW( L"CLDAPHelper :: ExecuteQuery GetADSIInstance() FAILED on %s with %x\r\n", adsColumn.pADsValues->DNString, result);
}
}
catch ( ... )
{
pDirectorySearchContainer->FreeColumn( &adsColumn );
throw;
}
// Free resouces
pDirectorySearchContainer->FreeColumn( &adsColumn );
}
else
pLogObject->WriteW( L"CLDAPHelper :: ExecuteQuery GetColumn() FAILED on %s with %x\r\n", pszLDAPQuery, result);
}
}
}
else
pLogObject->WriteW( L"CLDAPHelper :: ExecuteQuery GetFirstRow() FAILED on %s with %x\r\n", pszLDAPQuery, result);
}
catch ( ... )
{
// Delete the contents of the array
for(DWORD j=0; j<i; j++)
delete (*pppADSIInstances)[j];
// Delete the array itself
delete [] (*pppADSIInstances);
// Set return values to empty
*pppADSIInstances = NULL;
*pdwNumRows = 0;
throw;
}
}
// Something went wrong? Release allocated resources
if(i != *pdwNumRows)
{
pLogObject->WriteW( L"CLDAPHelper :: ExecuteQuery() Difference between Number of rows in 2 searches %d %d on %s Am invalidating the search as FAILED\r\n", i, *pdwNumRows, pszLDAPQuery);
// Delete the contents of the array
for(DWORD j=0; j<i; j++)
delete (*pppADSIInstances)[j];
// Delete the array itself
delete [] (*pppADSIInstances);
// Set return values to empty
*pppADSIInstances = NULL;
*pdwNumRows = 0;
result = E_FAIL;
}
}
}
catch ( ... )
{
pDirectorySearchContainer->CloseSearchHandle(hADSSearchOuter);
throw;
}
// Close the search.
pDirectorySearchContainer->CloseSearchHandle(hADSSearchOuter);
} // ExecuteSearch()
else
pLogObject->WriteW( L"CLDAPHelper :: ExecuteQuery ExecuteSearch() %s FAILED with %x\r\n", pszLDAPQuery, result);
} // SetSearchPreference()
else
pLogObject->WriteW( L"CLDAPHelper :: ExecuteQuery SetSearchPreference() on %s FAILED with %x \r\n", pszPathToRoot, result);
}
catch ( ... )
{
pDirectorySearchContainer->Release();
throw;
}
pDirectorySearchContainer->Release();
} // ADsOpenObject
else
pLogObject->WriteW( L"CLDAPHelper :: ExecuteQuery ADsOpenObject() on %s FAILED with %x \r\n", pszPathToRoot, result);
return result;
}