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