821 lines
18 KiB
C++
821 lines
18 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996
|
|
//
|
|
// File: util.cxx
|
|
//
|
|
// Contents: Some misc helper functions
|
|
//
|
|
// History:
|
|
//----------------------------------------------------------------------------
|
|
#include "ldapc.hxx"
|
|
#pragma hdrstop
|
|
|
|
BOOL
|
|
IsContainer(
|
|
LPTSTR pszClassName,
|
|
LDAP_SCHEMA_HANDLE hSchema
|
|
);
|
|
|
|
/******************************************************************/
|
|
/* Class SCHEMAINFO
|
|
/******************************************************************/
|
|
SCHEMAINFO::SCHEMAINFO()
|
|
: _cRef( 0 ),
|
|
_fObsolete( FALSE ),
|
|
fDefaultSchema( FALSE ),
|
|
fAppearsV3(TRUE),
|
|
pszServerName( NULL ),
|
|
pszSubSchemaSubEntry( NULL ),
|
|
pszTime( NULL ),
|
|
Next( NULL ),
|
|
aClasses( NULL ),
|
|
nNumOfClasses( 0 ),
|
|
aClassesSearchTable( NULL ),
|
|
aProperties( NULL ),
|
|
nNumOfProperties( 0 ),
|
|
aPropertiesSearchTable( NULL ),
|
|
pszUserName( NULL )
|
|
{
|
|
}
|
|
|
|
SCHEMAINFO::~SCHEMAINFO()
|
|
{
|
|
if ( pszServerName )
|
|
FreeADsStr( pszServerName );
|
|
|
|
if ( pszUserName )
|
|
FreeADsStr( pszUserName );
|
|
|
|
if ( pszSubSchemaSubEntry )
|
|
FreeADsStr( pszSubSchemaSubEntry );
|
|
|
|
if ( pszTime )
|
|
FreeADsStr( pszTime );
|
|
|
|
if ( !fDefaultSchema )
|
|
{
|
|
if ( aClasses )
|
|
FreeClassInfoArray( aClasses, nNumOfClasses );
|
|
|
|
if ( aClassesSearchTable )
|
|
FreeADsMem( aClassesSearchTable );
|
|
|
|
if ( aProperties )
|
|
FreePropertyInfoArray( aProperties, nNumOfProperties );
|
|
|
|
if ( aPropertiesSearchTable )
|
|
FreeADsMem( aPropertiesSearchTable );
|
|
}
|
|
}
|
|
|
|
DWORD SCHEMAINFO::AddRef()
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
DWORD SCHEMAINFO::Release()
|
|
{
|
|
if ( _cRef > 0 )
|
|
return --_cRef;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Helper routine that looks up the syntax tables (oid and name oid)
|
|
// and returns the correct syntax corresponding to the string name.
|
|
//
|
|
DWORD
|
|
LdapGetSyntaxIdOfAttribute(
|
|
LPWSTR pszStringSyntax
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSyntaxId = -1;
|
|
|
|
dwSyntaxId = FindEntryInSearchTable(
|
|
pszStringSyntax,
|
|
g_aSyntaxSearchTable,
|
|
g_nSyntaxSearchTableSize
|
|
);
|
|
|
|
if (dwSyntaxId == -1) {
|
|
//
|
|
// We also need to search in the OID based syntax table.
|
|
//
|
|
dwSyntaxId = FindEntryInSearchTable(
|
|
pszStringSyntax,
|
|
g_aOidSyntaxSearchTable,
|
|
g_nOidSyntaxSearchTableSize
|
|
);
|
|
}
|
|
|
|
return dwSyntaxId;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
LdapGetSyntaxOfAttributeOnServerHelper(
|
|
LPTSTR pszServerPath,
|
|
LPTSTR pszAttrName,
|
|
DWORD *pdwSyntaxId,
|
|
CCredentials& Credentials,
|
|
DWORD dwPort
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = NULL;
|
|
DWORD dwEntry;
|
|
LPWSTR pszTemp = NULL;
|
|
|
|
*pdwSyntaxId = LDAPTYPE_UNKNOWN;
|
|
|
|
hr = LdapGetSchema( pszServerPath,
|
|
&pSchemaInfo,
|
|
Credentials,
|
|
dwPort
|
|
);
|
|
|
|
BAIL_IF_ERROR(hr);
|
|
|
|
// Support for range attributes; for eg., objectClass=Range=0-1 We should
|
|
// ignore everything after ';' inclusive.
|
|
//
|
|
|
|
if ((pszTemp = wcschr(pszAttrName, L';')) != NULL ) {
|
|
*pszTemp = L'\0';
|
|
}
|
|
|
|
dwEntry = FindEntryInSearchTable(
|
|
pszAttrName,
|
|
pSchemaInfo->aPropertiesSearchTable,
|
|
pSchemaInfo->nNumOfProperties * 2 );
|
|
|
|
//
|
|
// Put back the ; if we had replaced it.
|
|
//
|
|
|
|
if (pszTemp)
|
|
*pszTemp = L';';
|
|
|
|
if ( dwEntry != -1 )
|
|
{
|
|
//
|
|
// This helper routine will lookup both the oid table and the
|
|
// name based syntax table and return -1 if unsuccesful.
|
|
//
|
|
*pdwSyntaxId = LdapGetSyntaxIdOfAttribute(
|
|
pSchemaInfo->aProperties[dwEntry].pszSyntax
|
|
);
|
|
|
|
if ( *pdwSyntaxId == -1 ) {
|
|
*pdwSyntaxId = LDAPTYPE_UNKNOWN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_ADS_PROPERTY_NOT_FOUND;
|
|
BAIL_IF_ERROR(hr);
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if ( pSchemaInfo )
|
|
pSchemaInfo->Release();
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//
|
|
// This routine calls the helper and if the flag FromServer is TRUE,
|
|
// then if we cannot find the syntax on the server then we will
|
|
// mark as obsolete and retry. This will fix some not so obvious
|
|
// cases of problems with the schema across mutliple DC's. The
|
|
// underlying assumption is that if the server sent the info, then
|
|
// it should have the schema information to match.
|
|
//
|
|
HRESULT
|
|
LdapGetSyntaxOfAttributeOnServer(
|
|
LPTSTR pszServerPath,
|
|
LPTSTR pszAttrName,
|
|
DWORD *pdwSyntaxId,
|
|
CCredentials& Credentials,
|
|
DWORD dwPort,
|
|
BOOL fFromServer // defaulted to FALSE
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = LdapGetSyntaxOfAttributeOnServerHelper(
|
|
pszServerPath,
|
|
pszAttrName,
|
|
pdwSyntaxId,
|
|
Credentials,
|
|
dwPort
|
|
);
|
|
|
|
//
|
|
// Reset and retry only if fFromServer is true, and
|
|
// the failure was E_ADS_PROPERTY_NOT_FOUND. If this is
|
|
// a v2 server then there will be no significant perf hit
|
|
// as we do not refresh the default schema.
|
|
//
|
|
|
|
if (FAILED(hr)
|
|
&& (hr == E_ADS_PROPERTY_NOT_FOUND)
|
|
&& fFromServer) {
|
|
//
|
|
// Mark schema as old.
|
|
//
|
|
hr = LdapRemoveSchemaInfoOnServer(
|
|
pszServerPath,
|
|
Credentials,
|
|
dwPort,
|
|
TRUE // force update.
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = LdapGetSyntaxOfAttributeOnServerHelper(
|
|
pszServerPath,
|
|
pszAttrName,
|
|
pdwSyntaxId,
|
|
Credentials,
|
|
dwPort
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
else {
|
|
//
|
|
// This is the normal exit path.
|
|
//
|
|
RRETURN(hr);
|
|
}
|
|
|
|
error :
|
|
|
|
//
|
|
// If we get here we need to return prop not found
|
|
// other code may depend on that. Note that we will come
|
|
// here only if we the first try failed and something went
|
|
// wrong while trying to force a reload of the schema.
|
|
//
|
|
if (FAILED(hr)) {
|
|
RRETURN(hr = E_ADS_PROPERTY_NOT_FOUND);
|
|
}
|
|
else {
|
|
RRETURN(hr);
|
|
}
|
|
|
|
}
|
|
|
|
HRESULT
|
|
LdapIsClassNameValidOnServer(
|
|
LPTSTR pszServerPath,
|
|
LPTSTR pszClassName,
|
|
BOOL *pfValid,
|
|
CCredentials& Credentials,
|
|
DWORD dwPort
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = NULL;
|
|
|
|
*pfValid = FALSE;
|
|
|
|
hr = LdapGetSchema( pszServerPath,
|
|
&pSchemaInfo,
|
|
Credentials,
|
|
dwPort
|
|
);
|
|
|
|
BAIL_IF_ERROR(hr);
|
|
|
|
if ( FindEntryInSearchTable(
|
|
pszClassName,
|
|
pSchemaInfo->aClassesSearchTable,
|
|
pSchemaInfo->nNumOfClasses * 2 ) != -1 )
|
|
{
|
|
*pfValid = TRUE;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if ( pSchemaInfo )
|
|
pSchemaInfo->Release();
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
LdapGetSchemaObjectCount(
|
|
LPTSTR pszServerPath,
|
|
DWORD *pnNumOfClasses,
|
|
DWORD *pnNumOfProperties,
|
|
CCredentials& Credentials,
|
|
DWORD dwPort
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = NULL;
|
|
|
|
hr = LdapGetSchema( pszServerPath,
|
|
&pSchemaInfo,
|
|
Credentials,
|
|
dwPort
|
|
);
|
|
|
|
BAIL_IF_ERROR(hr);
|
|
|
|
*pnNumOfClasses = pSchemaInfo->nNumOfClasses;
|
|
*pnNumOfProperties = pSchemaInfo->nNumOfProperties;
|
|
|
|
cleanup:
|
|
|
|
if ( pSchemaInfo )
|
|
pSchemaInfo->Release();
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
LdapGetSubSchemaSubEntryPath(
|
|
LPTSTR pszServerPath,
|
|
LPTSTR *ppszSubSchemaSubEntryPath,
|
|
CCredentials& Credentials,
|
|
DWORD dwPort
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = NULL;
|
|
|
|
*ppszSubSchemaSubEntryPath = NULL;
|
|
|
|
hr = LdapGetSchema( pszServerPath,
|
|
&pSchemaInfo,
|
|
Credentials,
|
|
dwPort
|
|
);
|
|
BAIL_IF_ERROR(hr);
|
|
|
|
if ( pSchemaInfo->pszSubSchemaSubEntry )
|
|
{
|
|
*ppszSubSchemaSubEntryPath =
|
|
AllocADsStr( pSchemaInfo->pszSubSchemaSubEntry );
|
|
|
|
if ( *ppszSubSchemaSubEntryPath == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_IF_ERROR(hr);
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if ( pSchemaInfo )
|
|
pSchemaInfo->Release();
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
LdapMakeSchemaCacheObsolete(
|
|
LPTSTR pszServerPath,
|
|
CCredentials& Credentials,
|
|
DWORD dwPort
|
|
)
|
|
{
|
|
RRETURN( LdapRemoveSchemaInfoOnServer(
|
|
pszServerPath,
|
|
Credentials,
|
|
dwPort
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SchemaOpen(
|
|
IN LPTSTR pszServerPath,
|
|
OUT LDAP_SCHEMA_HANDLE *phSchema,
|
|
IN CCredentials& Credentials,
|
|
DWORD dwPort
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = NULL;
|
|
|
|
*phSchema = NULL;
|
|
|
|
hr = LdapGetSchema( pszServerPath,
|
|
&pSchemaInfo,
|
|
Credentials,
|
|
dwPort
|
|
);
|
|
|
|
if ( FAILED(hr))
|
|
RRETURN(hr);
|
|
|
|
*phSchema = (HANDLE) pSchemaInfo;
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaClose(
|
|
IN OUT LDAP_SCHEMA_HANDLE *phSchema
|
|
)
|
|
{
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) *phSchema;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
if ( pSchemaInfo->Release() == 0 )
|
|
*phSchema = NULL;
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaAddRef(
|
|
IN LDAP_SCHEMA_HANDLE hSchema
|
|
)
|
|
{
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
pSchemaInfo->AddRef();
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaGetObjectCount(
|
|
LDAP_SCHEMA_HANDLE hSchema,
|
|
DWORD *pnNumOfClasses,
|
|
DWORD *pnNumOfProperties
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
*pnNumOfClasses = pSchemaInfo->nNumOfClasses;
|
|
*pnNumOfProperties = pSchemaInfo->nNumOfProperties;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaGetClassInfoByIndex(
|
|
LDAP_SCHEMA_HANDLE hSchema,
|
|
DWORD dwIndex,
|
|
CLASSINFO **ppClassInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
*ppClassInfo = &(pSchemaInfo->aClasses[dwIndex]);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaGetPropertyInfoByIndex(
|
|
LDAP_SCHEMA_HANDLE hSchema,
|
|
DWORD dwIndex,
|
|
PROPERTYINFO **ppPropertyInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
*ppPropertyInfo = &(pSchemaInfo->aProperties[dwIndex]);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaGetClassInfo(
|
|
LDAP_SCHEMA_HANDLE hSchema,
|
|
LPTSTR pszClassName,
|
|
CLASSINFO **ppClassInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
DWORD dwIndex = (DWORD) -1;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
dwIndex = FindEntryInSearchTable(
|
|
pszClassName,
|
|
pSchemaInfo->aClassesSearchTable,
|
|
pSchemaInfo->nNumOfClasses * 2 );
|
|
|
|
if ( dwIndex == -1 )
|
|
{
|
|
*ppClassInfo = NULL;
|
|
}
|
|
else
|
|
{
|
|
*ppClassInfo = &(pSchemaInfo->aClasses[dwIndex]);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaGetPropertyInfo(
|
|
LDAP_SCHEMA_HANDLE hSchema,
|
|
LPTSTR pszPropertyName,
|
|
PROPERTYINFO **ppPropertyInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
DWORD dwIndex = (DWORD) -1;
|
|
LPWSTR pszTemp = NULL;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
// Support for range attributes; for eg., objectClass=Range=0-1 We should
|
|
// ignore everything after ';' inclusive.
|
|
//
|
|
|
|
if ((pszTemp = wcschr(pszPropertyName, L';')) != NULL ) {
|
|
*pszTemp = L'\0';
|
|
}
|
|
|
|
dwIndex = FindEntryInSearchTable(
|
|
pszPropertyName,
|
|
pSchemaInfo->aPropertiesSearchTable,
|
|
pSchemaInfo->nNumOfProperties * 2 );
|
|
|
|
//
|
|
// Put back the ; if we had replaced it.
|
|
//
|
|
|
|
if (pszTemp)
|
|
*pszTemp = L';';
|
|
|
|
if ( dwIndex == -1 )
|
|
{
|
|
*ppPropertyInfo = NULL;
|
|
}
|
|
else
|
|
{
|
|
*ppPropertyInfo = &(pSchemaInfo->aProperties[dwIndex]);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaGetSyntaxOfAttribute(
|
|
LDAP_SCHEMA_HANDLE hSchema,
|
|
LPTSTR pszAttrName,
|
|
DWORD *pdwSyntaxId
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
LPWSTR pszTemp = NULL;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
*pdwSyntaxId = LDAPTYPE_UNKNOWN;
|
|
|
|
// Support for range attributes; for eg., objectClass=Range=0-1 We should
|
|
// ignore everything after ';' inclusive.
|
|
//
|
|
|
|
if ((pszTemp = wcschr(pszAttrName, L';')) != NULL ) {
|
|
*pszTemp = L'\0';
|
|
}
|
|
|
|
DWORD dwEntry = FindEntryInSearchTable(
|
|
pszAttrName,
|
|
pSchemaInfo->aPropertiesSearchTable,
|
|
pSchemaInfo->nNumOfProperties * 2 );
|
|
|
|
//
|
|
// Put back the ; if we had replaced it.
|
|
//
|
|
|
|
if (pszTemp)
|
|
*pszTemp = L';';
|
|
|
|
if ( dwEntry != -1 )
|
|
{
|
|
*pdwSyntaxId = FindEntryInSearchTable(
|
|
pSchemaInfo->aProperties[dwEntry].pszSyntax,
|
|
g_aSyntaxSearchTable,
|
|
g_nSyntaxSearchTableSize );
|
|
|
|
|
|
if ( *pdwSyntaxId == -1 ) {
|
|
|
|
//
|
|
// We also need to search in the OID based syntax table.
|
|
//
|
|
*pdwSyntaxId = FindEntryInSearchTable(
|
|
pSchemaInfo->aProperties[dwEntry].pszSyntax,
|
|
g_aOidSyntaxSearchTable,
|
|
g_nOidSyntaxSearchTableSize
|
|
);
|
|
|
|
if ( *pdwSyntaxId == -1 ) {
|
|
*pdwSyntaxId = LDAPTYPE_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = E_ADS_PROPERTY_NOT_FOUND;
|
|
BAIL_IF_ERROR(hr);
|
|
}
|
|
|
|
cleanup:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaIsClassAContainer(
|
|
LDAP_SCHEMA_HANDLE hSchema,
|
|
LPTSTR pszClassName,
|
|
BOOL *pfContainer
|
|
)
|
|
{
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
if ( ( _tcsicmp( pszClassName, TEXT("Container")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("organizationalUnit")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("organization")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("country")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("locality")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("device")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("DMD")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("mSFTDSA")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("Domain")) == 0 )
|
|
)
|
|
{
|
|
*pfContainer = TRUE;
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
*pfContainer = IsContainer( pszClassName, hSchema );
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
HRESULT
|
|
SchemaGetStringsFromStringTable(
|
|
LDAP_SCHEMA_HANDLE hSchema,
|
|
int *propList,
|
|
DWORD nCount,
|
|
LPWSTR **paStrings
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
long i = 0;
|
|
|
|
if ( !pSchemaInfo )
|
|
RRETURN(E_ADS_BAD_PARAMETER);
|
|
|
|
if ( (propList != NULL) && (*propList != -1) )
|
|
{
|
|
|
|
*paStrings = (LPWSTR *) AllocADsMem( (nCount+1)*sizeof(LPWSTR));
|
|
if ( *paStrings == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
i = 0;
|
|
while ( propList[i] != -1 )
|
|
{
|
|
(*paStrings)[i] = AllocADsStr(
|
|
pSchemaInfo->aProperties[pSchemaInfo->aPropertiesSearchTable[propList[i]].nIndex].pszPropertyName );
|
|
|
|
if ( (*paStrings)[i] == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
(*paStrings)[i] = NULL;
|
|
}
|
|
else
|
|
{
|
|
*paStrings = NULL;
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
error:
|
|
|
|
if ( *paStrings )
|
|
{
|
|
i = 0;
|
|
while ( (*paStrings)[i] )
|
|
{
|
|
FreeADsStr( (*paStrings)[i] );
|
|
i++;
|
|
}
|
|
FreeADsMem( *paStrings );
|
|
}
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
BOOL
|
|
IsContainer(
|
|
LPTSTR pszClassName,
|
|
LDAP_SCHEMA_HANDLE hSchema
|
|
)
|
|
{
|
|
int i = 0;
|
|
CLASSINFO *pClassInfo;
|
|
LPTSTR pszName;
|
|
DWORD index;
|
|
SCHEMAINFO *pSchemaInfo = (SCHEMAINFO *) hSchema;
|
|
|
|
if ( ( _tcsicmp( pszClassName, TEXT("Container")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("organizationalUnit")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("organization")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("country")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("locality")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("device")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("DMD")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("mSFTDSA")) == 0 )
|
|
|| ( _tcsicmp( pszClassName, TEXT("Domain")) == 0 )
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
index = (DWORD) FindEntryInSearchTable(
|
|
pszClassName,
|
|
pSchemaInfo->aClassesSearchTable,
|
|
2 * pSchemaInfo->nNumOfClasses );
|
|
|
|
if ( i == ((DWORD) -1) )
|
|
return FALSE;
|
|
|
|
pClassInfo = &(pSchemaInfo->aClasses[index]);
|
|
|
|
if ( pClassInfo->pOIDsSuperiorClasses )
|
|
{
|
|
for ( i = 0;
|
|
(pszName = pClassInfo->pOIDsSuperiorClasses[i]);
|
|
i++ )
|
|
{
|
|
if ( IsContainer( pszName, hSchema ))
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if ( pClassInfo->pOIDsAuxClasses )
|
|
{
|
|
for ( i = 0;
|
|
(pszName = pClassInfo->pOIDsAuxClasses[i]);
|
|
i++ )
|
|
{
|
|
if ( IsContainer( pszName, hSchema ))
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|