819 lines
15 KiB
C++
819 lines
15 KiB
C++
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1998
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
dsinterf.hxx
|
|
|
|
Abstract:
|
|
|
|
Directory service interface
|
|
|
|
Author:
|
|
|
|
Steve Kiraly (SteveKi) 09-Sept-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "dsinterf.hxx"
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TDirectoryService constructor.
|
|
|
|
Description:
|
|
|
|
TDirectoryService is a helper class for encapsulating DS
|
|
related functions.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Nothing, use bValid for class state check.
|
|
|
|
--*/
|
|
TDirectoryService::
|
|
TDirectoryService(
|
|
VOID
|
|
) : _bValid( FALSE )
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TDirectoryService::ctor\n" ) );
|
|
|
|
//
|
|
// We must initialize OLE for in each thread. In this
|
|
// case we assume the user of this class only creates
|
|
// one per thread.
|
|
//
|
|
HRESULT hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
|
|
|
|
|
|
if( hr == S_OK || hr == S_FALSE )
|
|
{
|
|
_bValid = TRUE;
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
~TDirectoryService destructor
|
|
|
|
Description:
|
|
|
|
Destructs this class, all clean up code should be placed here.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Nothing.
|
|
|
|
--*/
|
|
TDirectoryService::
|
|
~TDirectoryService(
|
|
VOID
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TDirectoryService::dtor.\n" ) );
|
|
|
|
//
|
|
// Coinitlize was only called if we had
|
|
// a valid object.
|
|
//
|
|
if( _bValid )
|
|
{
|
|
//
|
|
// Balance the CoInitialize.
|
|
//
|
|
CoUninitialize();
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
bValid
|
|
|
|
Description:
|
|
|
|
Indicates if the class is valid.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE class is valid, FALSE class is in an invalid state.
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
bValid(
|
|
VOID
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TDirectoryService::bValid.\n" ) );
|
|
|
|
//
|
|
// This class is always valid.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
bGetDirectoryName
|
|
|
|
Description:
|
|
|
|
Retrives the directory display name from the shell, i.e. ds folder.
|
|
|
|
Arguments:
|
|
|
|
strName - refrence to string object where to return
|
|
directory display name.
|
|
|
|
Return Value:
|
|
|
|
TRUE name returne, FALSE error occurred.
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
bGetDirectoryName(
|
|
IN TString &strName
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
|
|
if( _strDirectoryName.bEmpty() )
|
|
{
|
|
TLibrary Lib( TEXT("dsuiext.dll") );
|
|
|
|
if( VALID_OBJ( Lib ) )
|
|
{
|
|
typedef HRESULT (WINAPI *PF_FORMATDIRECTORYNAME)( LPTSTR *, PVOID, UINT );
|
|
typedef VOID (WINAPI *PF_LOCALFREESTRING)( LPTSTR * );
|
|
|
|
PF_FORMATDIRECTORYNAME pfFormatDirectoryName = (PF_FORMATDIRECTORYNAME)Lib.pfnGetProc( 578 );
|
|
PF_LOCALFREESTRING pfLocalFreeString = (PF_LOCALFREESTRING)Lib.pfnGetProc( 542 );
|
|
|
|
if( pfFormatDirectoryName && pfLocalFreeString )
|
|
{
|
|
HRESULT hr;
|
|
LPTSTR pName = NULL;
|
|
|
|
hr = pfFormatDirectoryName( &pName, NULL, 0 );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
bStatus DBGCHK = _strDirectoryName.bUpdate( pName );
|
|
pfLocalFreeString(&pName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the directory name is empty indicate we cannot
|
|
// get the directory name.
|
|
//
|
|
if( _strDirectoryName.bEmpty() )
|
|
{
|
|
bStatus DBGNOCHK = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Return the directory name.
|
|
//
|
|
bStatus DBGCHK = strName.bUpdate( _strDirectoryName );
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
bIsDsAvailable
|
|
|
|
Description:
|
|
|
|
Indicates if the directory service is available either for the
|
|
user or from the machines perspective.
|
|
|
|
Arguments:
|
|
|
|
pName - pointer to a machine name, i.e. this call is remoteable.
|
|
bForUser - TRUE indicate it is a user check, FALSE for machine.
|
|
|
|
Return Value:
|
|
|
|
TRUE if directory is available, otherwize false.
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
bIsDsAvailable(
|
|
IN LPCTSTR pName,
|
|
IN BOOL bForUser
|
|
)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
DWORD dwAccess = SERVER_READ;
|
|
DWORD dwDsStatus = 0;
|
|
HANDLE hServer = NULL;
|
|
|
|
//
|
|
// Open the server for read access.
|
|
//
|
|
dwStatus = TPrinter::sOpenPrinter( pName, &dwAccess, &hServer );
|
|
|
|
//
|
|
// If server handle opened.
|
|
//
|
|
if( dwStatus == ERROR_SUCCESS )
|
|
{
|
|
DWORD dwNeeded = 0;
|
|
DWORD dwDsStatusType = REG_DWORD;
|
|
|
|
if( dwStatus == ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// If the request for user or for machine.
|
|
//
|
|
LPTSTR pszKey = bForUser ? SPLREG_DS_PRESENT_FOR_USER : SPLREG_DS_PRESENT;
|
|
|
|
//
|
|
// Get the printer data key which indicates the DS is available.
|
|
//
|
|
dwStatus = GetPrinterData( hServer,
|
|
pszKey,
|
|
&dwDsStatusType,
|
|
(PBYTE)&dwDsStatus,
|
|
sizeof( dwDsStatus ),
|
|
&dwNeeded );
|
|
}
|
|
|
|
if( dwStatus == ERROR_SUCCESS )
|
|
{
|
|
bReturn = dwDsStatus;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close the server handle.
|
|
//
|
|
if( hServer )
|
|
{
|
|
ClosePrinter( hServer );
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
bIsDsAvailable
|
|
|
|
Description:
|
|
|
|
Indicates if the directory service is available either for the
|
|
using the same check the shell uses.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if directory is available, otherwize false.
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
bIsDsAvailable(
|
|
VOID
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TDirectoryService::bIsDsAvailble - ShowDirectoryUI.\n" ) );
|
|
|
|
BOOL bStatus = FALSE;
|
|
|
|
TLibrary Lib( TEXT("dsuiext.dll") );
|
|
|
|
if( VALID_OBJ( Lib ) )
|
|
{
|
|
typedef BOOL (WINAPI *PF_SHOWDIRECTORYUI)( VOID );
|
|
|
|
PF_SHOWDIRECTORYUI pfShowDirectoryUI = (PF_SHOWDIRECTORYUI)Lib.pfnGetProc( 577 );
|
|
|
|
if( pfShowDirectoryUI )
|
|
{
|
|
bStatus = pfShowDirectoryUI();
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
HRESULT
|
|
TDirectoryService::
|
|
ADsGetObject(
|
|
IN LPWSTR lpszPathName,
|
|
IN REFIID riid,
|
|
IN OUT VOID **ppObject
|
|
)
|
|
{
|
|
return ::ADsGetObject( lpszPathName, riid, ppObject );
|
|
}
|
|
|
|
HRESULT
|
|
TDirectoryService::
|
|
ADsBuildEnumerator(
|
|
IADsContainer *pADsContainer,
|
|
IEnumVARIANT **ppEnumVariant
|
|
)
|
|
{
|
|
return ::ADsBuildEnumerator( pADsContainer, ppEnumVariant);
|
|
}
|
|
|
|
HRESULT
|
|
TDirectoryService::
|
|
ADsFreeEnumerator(
|
|
IEnumVARIANT *pEnumVariant
|
|
)
|
|
{
|
|
return ::ADsFreeEnumerator( pEnumVariant );
|
|
}
|
|
|
|
HRESULT
|
|
TDirectoryService::
|
|
ADsEnumerateNext(
|
|
IEnumVARIANT *pEnumVariant,
|
|
ULONG cElements,
|
|
VARIANT FAR *pvar,
|
|
ULONG FAR *pcElementsFetched
|
|
)
|
|
{
|
|
return ::ADsEnumerateNext( pEnumVariant, cElements, pvar, pcElementsFetched);
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
Get
|
|
|
|
Description:
|
|
|
|
This routine gets a string value from the specified DS object using
|
|
the specified property. A copy of the string is made and placed into
|
|
the provided string object.
|
|
|
|
Arguments:
|
|
|
|
pDsObject - pointer to the DS object interface
|
|
pszPropertyName - DS object property name
|
|
strString - refrence to string object where to return string
|
|
|
|
Return Value:
|
|
|
|
TRUE string put successfully, FALSE error occurred.
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
Get(
|
|
IN IADs *pDsObject,
|
|
IN LPCTSTR pszPropertyName,
|
|
IN TString &strString
|
|
)
|
|
{
|
|
SPLASSERT( pDsObject );
|
|
SPLASSERT( pszPropertyName );
|
|
|
|
VARIANT var;
|
|
|
|
VariantInit( &var );
|
|
|
|
HRESULT hr = pDsObject->Get( const_cast<LPTSTR>( pszPropertyName ), &var );
|
|
|
|
if( SUCCEEDED( hr ) && ( var.vt == VT_BSTR ) )
|
|
{
|
|
hr = strString.bUpdate( V_BSTR(&var) ) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
VariantClear (&var);
|
|
|
|
return SUCCEEDED( hr );
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
Put
|
|
|
|
Description:
|
|
|
|
This routine puts a string value on the specified DS object
|
|
for the specified property. This routine does not make a copy
|
|
of the string but places it into a variant that is inturn passed
|
|
to Ads::Put method.
|
|
|
|
Arguments:
|
|
|
|
pDsObject - pointer to the DS object interface
|
|
pszPropertyName - DS object property name
|
|
pszString - string value to put
|
|
|
|
Return Value:
|
|
|
|
TRUE string put successfully, FALSE error occurred.
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
Put(
|
|
IN IADs *pDsObject,
|
|
IN LPCTSTR pszPropertyName,
|
|
IN LPCTSTR pszString
|
|
)
|
|
{
|
|
SPLASSERT( pDsObject );
|
|
SPLASSERT( pszPropertyName );
|
|
|
|
VARIANT var;
|
|
HRESULT hr;
|
|
VariantInit (&var);
|
|
|
|
if( !pszString || !*pszString )
|
|
{
|
|
hr = pDsObject->PutEx( ADS_PROPERTY_CLEAR, const_cast<LPTSTR>( pszPropertyName ), var );
|
|
}
|
|
else
|
|
{
|
|
var.vt = VT_BSTR;
|
|
var.bstrVal = const_cast<LPTSTR>( pszString );
|
|
hr = pDsObject->Put( const_cast<LPTSTR>( pszPropertyName ), var );
|
|
}
|
|
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
hr = pDsObject->SetInfo();
|
|
|
|
if( FAILED(hr) && ( !pszString || !*pszString ) )
|
|
{
|
|
//
|
|
// From our perspective if we fail to delete a property because it does not exist
|
|
// the operation actually succeeded.
|
|
//
|
|
if( HRESULT_CODE(hr) == ERROR_DS_NO_ATTRIBUTE_OR_VALUE )
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
var.bstrVal = NULL;
|
|
VariantClear (&var);
|
|
|
|
return SUCCEEDED(hr);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TReadStringProperty
|
|
|
|
Description:
|
|
|
|
This routine reads the specified string using the specified path
|
|
and property name from the DS.
|
|
|
|
Arguments:
|
|
|
|
strString - refrence to class where to returned read string.
|
|
|
|
Return Value:
|
|
|
|
TRUE string was read, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
ReadStringProperty(
|
|
IN LPCTSTR pszPath,
|
|
IN LPCTSTR pszProperty,
|
|
IN OUT TString &strString
|
|
)
|
|
{
|
|
IADs *pADs;
|
|
HRESULT hStatus;
|
|
|
|
hStatus = ADsGetObject( const_cast<LPTSTR>( pszPath ), IID_IADs, (void **)&pADs);
|
|
|
|
if (SUCCEEDED(hStatus))
|
|
{
|
|
VARIANT var;
|
|
|
|
VariantInit(&var);
|
|
|
|
hStatus = pADs->Get( const_cast<LPTSTR>( pszProperty ), &var);
|
|
|
|
if (SUCCEEDED(hStatus))
|
|
{
|
|
hStatus = strString.bUpdate( V_BSTR(&var) ) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
VariantClear (&var);
|
|
|
|
pADs->Release();
|
|
}
|
|
|
|
if (FAILED(hStatus))
|
|
{
|
|
DBGMSG( DBG_TRACE, ("ReadStringProperty Path " TSTR " Property " TSTR " failed %x\n", pszPath, pszProperty, hStatus ) );
|
|
}
|
|
|
|
return SUCCEEDED(hStatus);
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetConfigurationContainer
|
|
|
|
Description:
|
|
|
|
This routine figures out the and returnes the path of the
|
|
longged on DS's configuration containter.
|
|
|
|
Arguments:
|
|
|
|
strConfig - Refrence to a string where to return the configuration string.
|
|
|
|
Return Value:
|
|
|
|
TRUE configuration containter returned. FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
GetConfigurationContainer(
|
|
IN OUT TString &strConfig
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
|
|
//
|
|
// If we have not already read the configuration container
|
|
// then read it now.
|
|
//
|
|
if (_strConfigurationContainer.bEmpty())
|
|
{
|
|
TString strRootDSE;
|
|
TString strLDAPPrefix;
|
|
|
|
bStatus DBGCHK = GetLDAPPrefix( strLDAPPrefix ) &&
|
|
strRootDSE.bCat( strLDAPPrefix ) &&
|
|
strRootDSE.bCat( gszRootDSE );
|
|
|
|
if (bStatus)
|
|
{
|
|
bStatus DBGCHK = ReadStringProperty( strRootDSE, gszConfigurationNameingContext, _strConfigurationContainer );
|
|
}
|
|
}
|
|
|
|
bStatus DBGCHK = strConfig.bUpdate( _strConfigurationContainer );
|
|
|
|
DBGMSG( DBG_TRACE, ( "Configuration Container " TSTR ".\n", (LPCTSTR)strConfig ) );
|
|
|
|
return bStatus;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetDsName
|
|
|
|
Description:
|
|
|
|
Returns a the DS UNC name that can be used in the call to
|
|
AddressToSiteNames.
|
|
|
|
Arguments:
|
|
|
|
strDsName - refrence to string where to return the Ds name.
|
|
|
|
Return Value:
|
|
|
|
TRUE success, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
GetDsName(
|
|
IN TString &strDsName
|
|
)
|
|
{
|
|
TString strDomainName;
|
|
TStatusB bStatus;
|
|
|
|
bStatus DBGCHK = GetDomainName( strDomainName );
|
|
|
|
if (bStatus)
|
|
{
|
|
bStatus DBGCHK = strDsName.bUpdate( gszLeadingSlashes ) && strDsName.bCat( strDomainName );
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetLDAPPrefix
|
|
|
|
Description:
|
|
|
|
Returns the correct LDAP prefix using fully qualified machine account
|
|
domain name (example "LDAP://ntdev.microsoft.com/"
|
|
|
|
Arguments:
|
|
|
|
strLDAPPrefix - where to return The LDAP prefix (domain relative or
|
|
fully qualified)
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE othewise
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
GetLDAPPrefix(
|
|
OUT TString &strLDAPPrefix
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
bStatus DBGNOCHK = TRUE;
|
|
|
|
if( !_strLDAPPrefix.uLen( ) )
|
|
{
|
|
TString strRootDSE;
|
|
TString strConfig;
|
|
|
|
bStatus DBGCHK = strRootDSE.bCat( gszLdapPrefix ) &&
|
|
strRootDSE.bCat( gszRootDSE );
|
|
|
|
if( bStatus )
|
|
{
|
|
//
|
|
// We need to use fully qualified domain LDAP address
|
|
//
|
|
TString strDomainName;
|
|
bStatus DBGCHK = GetDomainName( strDomainName );
|
|
|
|
if( bStatus )
|
|
{
|
|
bStatus DBGCHK = _strLDAPPrefix.bUpdate( NULL ) &&
|
|
_strLDAPPrefix.bCat( gszLdapPrefix ) &&
|
|
_strLDAPPrefix.bCat( strDomainName ) &&
|
|
_strLDAPPrefix.bCat( gszSlash );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !_strLDAPPrefix.uLen( ) || !bStatus )
|
|
{
|
|
bStatus DBGCHK = _strLDAPPrefix.bUpdate( gszLdapPrefix );
|
|
}
|
|
|
|
if( bStatus )
|
|
{
|
|
bStatus DBGCHK = strLDAPPrefix.bUpdate( _strLDAPPrefix );
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetLDAPPrefixPerUser
|
|
|
|
Description:
|
|
|
|
Returns the correct LDAP prefix using fully qualified machine account
|
|
domain name (example "LDAP://ntdev.microsoft.com/" if the user domain
|
|
(the domain in which the user is logged on) doesn't have a DS, if the
|
|
user domain has a DS then we are using domain relative prefix (i.e.
|
|
"LDAP://").
|
|
|
|
Arguments:
|
|
|
|
strLDAPPrefix - where to return The LDAP prefix (domain relative or
|
|
fully qualified)
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE othewise
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TDirectoryService::
|
|
GetLDAPPrefixPerUser(
|
|
OUT TString &strLDAPPrefix
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
bStatus DBGNOCHK = TRUE;
|
|
|
|
if( !_strLDAPPrefixPerUser.uLen( ) )
|
|
{
|
|
TString strRootDSE;
|
|
TString strConfig;
|
|
|
|
bStatus DBGCHK = strRootDSE.bCat( gszLdapPrefix ) &&
|
|
strRootDSE.bCat( gszRootDSE );
|
|
|
|
if( bStatus )
|
|
{
|
|
bStatus DBGCHK = ReadStringProperty( strRootDSE, gszConfigurationNameingContext, strConfig );
|
|
|
|
if( bStatus )
|
|
{
|
|
//
|
|
// We can use domain relative LDAP address
|
|
//
|
|
bStatus DBGCHK = _strLDAPPrefixPerUser.bUpdate( gszLdapPrefix );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We need to use fully qualified domain LDAP address
|
|
//
|
|
|
|
bStatus DBGCHK = GetLDAPPrefix (_strLDAPPrefixPerUser);
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !_strLDAPPrefixPerUser.uLen( ) || !bStatus )
|
|
{
|
|
bStatus DBGCHK = _strLDAPPrefixPerUser.bUpdate( gszLdapPrefix );
|
|
}
|
|
|
|
if( bStatus )
|
|
{
|
|
bStatus DBGCHK = strLDAPPrefix.bUpdate( _strLDAPPrefixPerUser );
|
|
}
|
|
|
|
return bStatus;
|
|
}
|