// // 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 : 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=)) // 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=)(!ldapDisplayName=)) 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; jCloseSearchHandle(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=, // // 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; ipszAttrName; // Delete each value for(DWORD i=0; idwNumValues; 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; jWriteW( 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; jCloseSearchHandle(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; }