1651 lines
33 KiB
C++
1651 lines
33 KiB
C++
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
|
|
Module Name:
|
|
|
|
location.cxx
|
|
|
|
Abstract:
|
|
|
|
This module provides all the functions for determining the
|
|
machines current physical location.
|
|
|
|
Author:
|
|
|
|
Steve Kiraly (SteveKi) 13-July-1998
|
|
|
|
Revision History:
|
|
|
|
Steve Kiraly (SteveKi) 13-July-1998 Genesis
|
|
|
|
--*/
|
|
|
|
#include <precomp.hxx>
|
|
#pragma hdrstop
|
|
|
|
#include "dsinterf.hxx"
|
|
#include "persist.hxx"
|
|
#include "physloc.hxx"
|
|
|
|
const IN_ADDR c_LoopBackAddress = { 127,0,0,1 };
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TPhysicalLocation
|
|
|
|
Description:
|
|
|
|
TPhysicalLocation constructor.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Nothing.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
TPhysicalLocation::
|
|
TPhysicalLocation(
|
|
VOID
|
|
) : m_fInitalized( FALSE ),
|
|
m_eDiscoveryType( kDiscoveryTypeUnknown ),
|
|
m_IpHlpApi( gszIpHlpApiLibrary ),
|
|
m_GetIpAddrTable( NULL ),
|
|
m_SecExt( gszSecurityLibrary ),
|
|
m_GetComputerObjectName( NULL ),
|
|
m_GetUserNameEx( NULL ),
|
|
m_NetApi( gszNetApiLibrary ),
|
|
m_DsAddressToSiteNames( NULL ),
|
|
m_NetApiBufferFree( NULL ),
|
|
m_WinSock( gszWinSockLibrary ),
|
|
m_inet_ntoa( NULL )
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ctor.\n" ) );
|
|
|
|
//
|
|
// Check if the Ip helper library was loaded.
|
|
//
|
|
if (m_IpHlpApi.bValid())
|
|
{
|
|
m_GetIpAddrTable = reinterpret_cast<pfGetIpAddrTable>( m_IpHlpApi.pfnGetProc( "GetIpAddrTable" ) );
|
|
}
|
|
|
|
//
|
|
// Check if the security library was loaded.
|
|
//
|
|
if (m_SecExt.bValid())
|
|
{
|
|
m_GetComputerObjectName = reinterpret_cast<pfGetComputerObjectName>( m_SecExt.pfnGetProc( "GetComputerObjectNameW" ) );
|
|
m_GetUserNameEx = reinterpret_cast<pfGetUserNameEx>( m_SecExt.pfnGetProc( "GetUserNameExW" ) );
|
|
}
|
|
|
|
//
|
|
// Check if the netapi library was loaded.
|
|
//
|
|
if (m_NetApi.bValid())
|
|
{
|
|
m_DsAddressToSiteNames = reinterpret_cast<pfDsAddressToSiteNames>( m_NetApi.pfnGetProc( "DsAddressToSiteNamesExW" ) );
|
|
m_NetApiBufferFree = reinterpret_cast<pfNetApiBufferFree>( m_NetApi.pfnGetProc( "NetApiBufferFree" ) );
|
|
}
|
|
|
|
//
|
|
// Check if the winsock library was loaded.
|
|
//
|
|
if (m_WinSock.bValid())
|
|
{
|
|
m_inet_ntoa = reinterpret_cast<LPFN_INET_NTOA>( m_WinSock.pfnGetProc( "inet_ntoa" ) );
|
|
}
|
|
|
|
//
|
|
// All the function pointers must be valid for this class to be in
|
|
// the initialized state.
|
|
//
|
|
if (m_GetIpAddrTable && m_GetComputerObjectName && m_GetUserNameEx && m_DsAddressToSiteNames && m_NetApiBufferFree && m_inet_ntoa)
|
|
{
|
|
m_fInitalized = TRUE;
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TPhysicalLocation
|
|
|
|
Description:
|
|
|
|
TPhysicalLocation destructor.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Nothing.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
TPhysicalLocation::
|
|
~TPhysicalLocation(
|
|
VOID
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::dtor.\n" ) );
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
bValid
|
|
|
|
Description:
|
|
|
|
This routine indicates if the TPhysicalLocation class is
|
|
in a consistent state, i.e. usable.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE usable state, FALSE not usable.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
bValid(
|
|
VOID
|
|
) const
|
|
{
|
|
return m_fInitalized;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
Discover
|
|
|
|
Description:
|
|
|
|
The discover routine is where all the work is done. We attempt
|
|
to fetch the physical location string from various sources in a
|
|
pre defined order. If any of the steps completes the search is
|
|
terminated. The current order is to look in the HKLM policy key,
|
|
this machines location property in the DS
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE usable state, FALSE not usable.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
Discover(
|
|
VOID
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::Discover.\n" ) );
|
|
|
|
//
|
|
// Invalidate the current location information.
|
|
//
|
|
Invalidate();
|
|
|
|
//
|
|
// Read the group policy setting if it exists.
|
|
//
|
|
if (ReadGroupPolicyLocationSetting( m_strLocation ))
|
|
{
|
|
m_eDiscoveryType = kDiscoveryTypePolicy;
|
|
}
|
|
|
|
//
|
|
// If a DS is available and the group policy did not have any
|
|
// location information then continue looking for location information.
|
|
//
|
|
if (m_Ds.bIsDsAvailable() && m_eDiscoveryType == kDiscoveryTypeUnknown)
|
|
{
|
|
if (ReadMachinesLocationProperty( m_strLocation ))
|
|
{
|
|
m_eDiscoveryType = kDiscoveryTypeMachine;
|
|
}
|
|
else if (ReadSubnetLocationProperty( m_strLocation ))
|
|
{
|
|
m_eDiscoveryType = kDiscoveryTypeSubnet;
|
|
}
|
|
else if (ReadSiteLocationProperty( m_strLocation ))
|
|
{
|
|
m_eDiscoveryType = kDiscoveryTypeSite;
|
|
}
|
|
}
|
|
|
|
return m_eDiscoveryType != kDiscoveryTypeUnknown;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetExact
|
|
|
|
Description:
|
|
|
|
Returns the excact location string found by a call to the discover method.
|
|
|
|
Arguments:
|
|
|
|
strLocation - reference to a string object where to return the string.
|
|
|
|
Return Value:
|
|
|
|
TRUE search string returned, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
GetExact(
|
|
IN TString &strLocation
|
|
) const
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::GetExact.\n" ) );
|
|
|
|
return strLocation.bUpdate( m_strLocation );
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetSearch
|
|
|
|
Description:
|
|
|
|
Returns a string that is valid for a search. It widens the scope if the
|
|
current location string is one fetched for this machine.
|
|
|
|
Arguments:
|
|
|
|
strLocation - reference to a string object where to return the search string.
|
|
|
|
Return Value:
|
|
|
|
TRUE search string returned, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
GetSearch(
|
|
IN TString &strLocation
|
|
) const
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::GetSearch.\n" ) );
|
|
|
|
TStatusB bStatus;
|
|
|
|
if (m_eDiscoveryType == kDiscoveryTypeMachine || m_eDiscoveryType == kDiscoveryTypePolicy)
|
|
{
|
|
bStatus DBGCHK = WidenScope( m_strLocation, 1, strLocation );
|
|
|
|
//
|
|
// If the scope could not be widen then use the current location string.
|
|
//
|
|
if (!bStatus)
|
|
{
|
|
bStatus DBGCHK = strLocation.bUpdate( m_strLocation );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bStatus DBGCHK = strLocation.bUpdate( m_strLocation );
|
|
}
|
|
|
|
if( bStatus )
|
|
{
|
|
UINT uLen = strLocation.uLen();
|
|
if( uLen && gchSeparator != static_cast<LPCTSTR>(strLocation)[uLen-1] )
|
|
{
|
|
//
|
|
// Put the final slash after successfully
|
|
// widening the location scope
|
|
//
|
|
static const TCHAR szSepStr[] = { gchSeparator };
|
|
bStatus DBGCHK = strLocation.bCat( szSepStr );
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
Invalidate
|
|
|
|
Description:
|
|
|
|
Invalidates the location string. After this call the location string
|
|
is not valid until the disover method is called.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Nothing.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
VOID
|
|
TPhysicalLocation::
|
|
Invalidate(
|
|
VOID
|
|
)
|
|
{
|
|
m_eDiscoveryType = kDiscoveryTypeUnknown;
|
|
m_strLocation.bUpdate( NULL );
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
ReadGroupPolicyLocationSetting
|
|
|
|
Description:
|
|
|
|
Reads the location string from the local registry that was written
|
|
by the group policy editor.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE the location string was read, FALSE error occured or string not available.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
ReadGroupPolicyLocationSetting(
|
|
IN OUT TString &strLocationX
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadGroupPolicyLocationSetting.\n" ) );
|
|
|
|
//
|
|
// Open the registry key where the physical location is stored
|
|
// by the group policy code.
|
|
//
|
|
TPersist Reg( gszGroupPolicyPhysicalLocationPath, TPersist::kOpen|TPersist::kRead, HKEY_LOCAL_MACHINE );
|
|
|
|
TStatusB bStatus;
|
|
|
|
//
|
|
// Was the key opened, i.e. does it exist?
|
|
//
|
|
bStatus DBGCHK = Reg.bValid();
|
|
|
|
if (bStatus)
|
|
{
|
|
TString strLocation;
|
|
|
|
//
|
|
// Read the location string from the registry.
|
|
//
|
|
bStatus DBGCHK = Reg.bRead( gszGroupPolicyPhysicalLocationKey, strLocation );
|
|
|
|
//
|
|
// If the string was read and it is not blank then make a local copy of the
|
|
// location string and we are done.
|
|
//
|
|
if (bStatus && !strLocation.bEmpty())
|
|
{
|
|
bStatus DBGCHK = strLocationX.bUpdate( strLocation );
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
ReadUserLocationProperty
|
|
|
|
Description:
|
|
|
|
Reads the location string from the current users object in the
|
|
DS.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE success, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
ReadUserLocationProperty(
|
|
IN OUT TString &strLocation
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadUserLocationProperty.\n" ) );
|
|
|
|
TCHAR szName[INTERNET_MAX_HOST_NAME_LENGTH+1];
|
|
DWORD dwSize = COUNTOF( szName );
|
|
TStatusB bStatus;
|
|
|
|
bStatus DBGCHK = m_GetUserNameEx(NameFullyQualifiedDN, szName, &dwSize);
|
|
|
|
if (bStatus)
|
|
{
|
|
TString strUserPath;
|
|
TString strLDAPPrefix;
|
|
|
|
bStatus DBGCHK = m_Ds.GetLDAPPrefixPerUser( strLDAPPrefix ) &&
|
|
strUserPath.bCat( strLDAPPrefix ) &&
|
|
strUserPath.bCat( szName );
|
|
|
|
if (bStatus)
|
|
{
|
|
bStatus DBGCHK = m_Ds.ReadStringProperty( strUserPath, gszUserLocationPropertyName, strLocation );
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
ReadMachinesLocationProperty
|
|
|
|
Description:
|
|
|
|
Reads the location string from the machine object in the DS.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE success, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
ReadMachinesLocationProperty(
|
|
IN OUT TString &strLocation
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadMachinesLocationProperty.\n" ) );
|
|
|
|
LPTSTR pszName = NULL;
|
|
DWORD dwSize = 0;
|
|
TStatusB bStatus;
|
|
|
|
bStatus DBGCHK = m_GetComputerObjectName(NameFullyQualifiedDN, NULL, &dwSize);
|
|
|
|
if( bStatus && dwSize )
|
|
{
|
|
pszName = new TCHAR[dwSize+1];
|
|
|
|
if( pszName )
|
|
{
|
|
bStatus DBGCHK = m_GetComputerObjectName(NameFullyQualifiedDN, pszName, &dwSize);
|
|
|
|
if (bStatus)
|
|
{
|
|
TString strComputerPath;
|
|
TString strLDAPPrefix;
|
|
|
|
bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
|
|
strComputerPath.bCat( strLDAPPrefix ) &&
|
|
strComputerPath.bCat( pszName );
|
|
|
|
if (bStatus)
|
|
{
|
|
bStatus DBGCHK = m_Ds.ReadStringProperty( strComputerPath, gszMachineLocationPropertyName, strLocation );
|
|
}
|
|
}
|
|
|
|
delete [] pszName;
|
|
}
|
|
}
|
|
|
|
if( bStatus )
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadMachinesLocationProperty " TSTR ".\n", pszName ) );
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
ReadSubnetLocationProperty
|
|
|
|
Description:
|
|
|
|
Reads the location string from the subnet objet for this
|
|
machine. This routine searches the list of IP address IP masks
|
|
and finds a subnet object in the DS that closly matches this
|
|
machine.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE success, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
ReadSubnetLocationProperty(
|
|
IN OUT TString &strLocation
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadSubnetLocationProperty.\n" ) );
|
|
|
|
TString strSubnetPath;
|
|
TString strLDAPPrefix;
|
|
TSubnets Subnets;
|
|
TStatusB bStatus;
|
|
|
|
bStatus DBGCHK = GetSubnetObjectNames( Subnets );
|
|
|
|
if (bStatus)
|
|
{
|
|
for( UINT i = 0; i < Subnets.NumEntries(); i++ )
|
|
{
|
|
bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
|
|
strSubnetPath.bUpdate( strLDAPPrefix ) &&
|
|
strSubnetPath.bCat( Subnets.Table(i) );
|
|
|
|
if (bStatus)
|
|
{
|
|
bStatus DBGCHK = m_Ds.ReadStringProperty( strSubnetPath, gszSubnetLocationPropertyName, strLocation );
|
|
|
|
if (bStatus && !strLocation.bEmpty())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
ReadSiteLocationProperty
|
|
|
|
Description:
|
|
|
|
Reads the location string from the site object. This routine
|
|
searches the list of IP address and finds a site nearest this
|
|
machines ip adress. All of the searching code actually occurrs
|
|
in the DSAddressToSiteNames api.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE success, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
ReadSiteLocationProperty(
|
|
IN OUT TString &strLocation
|
|
)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadSiteLocationProperty.\n" ) );
|
|
|
|
PMIB_IPADDRTABLE pAddrTable = NULL;
|
|
TStatusB bStatus;
|
|
TString strSiteName;
|
|
TString strSubnetName;
|
|
TString strSubnetPath;
|
|
IN_ADDR IpNetAddr;
|
|
|
|
//
|
|
// Get the DS name.
|
|
//
|
|
bStatus DBGCHK = GetIpAddressTable( &pAddrTable );
|
|
|
|
if (bStatus)
|
|
{
|
|
bStatus DBGNOCHK = FALSE;
|
|
|
|
//
|
|
// Look for a site that has a location string that corresponds
|
|
// to the the first ipaddress in the list of ip addresses.
|
|
//
|
|
for (UINT i = 0; i < pAddrTable->dwNumEntries; i++)
|
|
{
|
|
//
|
|
// Skip the loopback or unassigned interfaces
|
|
//
|
|
if ((pAddrTable->table[i].dwAddr != 0) && (pAddrTable->table[i].dwAddr != c_LoopBackAddress.s_addr))
|
|
{
|
|
IpNetAddr.s_addr = pAddrTable->table[i].dwAddr;
|
|
|
|
DBGMSG( DBG_TRACE, ( "IP Address %s\n", m_inet_ntoa( IpNetAddr ) ) );
|
|
|
|
//
|
|
// Attempt to translate this ip address to either a site path or subnet path.
|
|
//
|
|
bStatus DBGNOCHK = AddrToSite( pAddrTable->table[i].dwAddr, strSiteName, strSubnetName );
|
|
|
|
if (bStatus)
|
|
{
|
|
//
|
|
// If a near match subnet was found use this first.
|
|
//
|
|
if (!strSubnetName.bEmpty())
|
|
{
|
|
bStatus DBGCHK = GetSubnetLocationString( strSubnetName, strLocation );
|
|
}
|
|
|
|
//
|
|
// If the location string was not found on the subnet then attempt to
|
|
// get the location on the site object.
|
|
//
|
|
if (!strSiteName.bEmpty() && strLocation.bEmpty())
|
|
{
|
|
bStatus DBGCHK = GetSiteLocationString( strSiteName, strLocation );
|
|
}
|
|
|
|
//
|
|
// If a location string was found exit the loop, the first ipaddress wins.
|
|
//
|
|
if (strLocation.bEmpty())
|
|
{
|
|
bStatus DBGNOCHK = FALSE;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete [] pAddrTable;
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetSubnetLocationString
|
|
|
|
Description:
|
|
|
|
Reads the location string from the subnet object. This routine
|
|
converts the subnet name to an adsi path then reads the location
|
|
property fron this subnet object.
|
|
|
|
Arguments:
|
|
|
|
pszSubnetName - pointer string which contains the subnet name.
|
|
strSiteLocation - reference to string object where to return the subnet
|
|
location string.
|
|
|
|
Return Value:
|
|
|
|
TRUE success, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
GetSubnetLocationString(
|
|
IN LPCTSTR pszSubnetName,
|
|
IN OUT TString &strSubnetLocation
|
|
)
|
|
{
|
|
TString strSubnetPath;
|
|
TString strConfig;
|
|
TString strLDAPPrefix;
|
|
TStatusB bStatus;
|
|
TCHAR szSubnetName[MAX_PATH];
|
|
|
|
//
|
|
// Sites are located in the configuration container.
|
|
//
|
|
bStatus DBGCHK = m_Ds.GetConfigurationContainer( strConfig );
|
|
|
|
if (bStatus)
|
|
{
|
|
//
|
|
// Escape the / in the subnet name.
|
|
//
|
|
for ( LPTSTR p = szSubnetName; pszSubnetName && *pszSubnetName; )
|
|
{
|
|
if (*pszSubnetName == _T('/'))
|
|
{
|
|
*p++ = _T('\\');
|
|
}
|
|
|
|
*p++ = *pszSubnetName++;
|
|
}
|
|
|
|
*p = NULL;
|
|
|
|
//
|
|
// Build the site adsi object path.
|
|
//
|
|
bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
|
|
strSubnetPath.bCat( strLDAPPrefix ) &&
|
|
strSubnetPath.bCat( gszCNEquals ) &&
|
|
strSubnetPath.bCat( szSubnetName ) &&
|
|
strSubnetPath.bCat( gszComma ) &&
|
|
strSubnetPath.bCat( gszSubnetContainter) &&
|
|
strSubnetPath.bCat( gszComma ) &&
|
|
strSubnetPath.bCat( strConfig );
|
|
|
|
DBGMSG( DBG_TRACE, ( "Subnet Path " TSTR ".\n", (LPCTSTR)strSubnetPath ) );
|
|
|
|
if (bStatus)
|
|
{
|
|
//
|
|
// Read the site location property.
|
|
//
|
|
bStatus DBGCHK = m_Ds.ReadStringProperty( strSubnetPath, gszSubnetLocationPropertyName, strSubnetLocation );
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetSiteLocationString
|
|
|
|
Description:
|
|
|
|
Reads the location string from the site object. This routine
|
|
converts the site name to an adsi path then reads the location
|
|
property fron this site object.
|
|
|
|
Arguments:
|
|
|
|
pszSiteName - pointer string which contains the site name.
|
|
strSiteLocation - reference to string object where to return the site
|
|
location string.
|
|
|
|
Return Value:
|
|
|
|
TRUE success, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
GetSiteLocationString(
|
|
IN LPCTSTR pszSiteName,
|
|
IN OUT TString &strSiteLocation
|
|
)
|
|
{
|
|
TString strConfig;
|
|
TString strSitePath;
|
|
TString strLDAPPrefix;
|
|
TStatusB bStatus;
|
|
|
|
//
|
|
// Sites are located in the configuration container.
|
|
//
|
|
bStatus DBGCHK = m_Ds.GetConfigurationContainer( strConfig );
|
|
|
|
if (bStatus)
|
|
{
|
|
//
|
|
// Build the site adsi object path.
|
|
//
|
|
bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
|
|
strSitePath.bCat( strLDAPPrefix ) &&
|
|
strSitePath.bCat( gszCNEquals ) &&
|
|
strSitePath.bCat( pszSiteName ) &&
|
|
strSitePath.bCat( gszComma ) &&
|
|
strSitePath.bCat( gszSitesContainter) &&
|
|
strSitePath.bCat( gszComma ) &&
|
|
strSitePath.bCat( strConfig );
|
|
|
|
DBGMSG( DBG_TRACE, ( "Site Path " TSTR ".\n", (LPCTSTR)strSitePath ) );
|
|
|
|
if (bStatus)
|
|
{
|
|
//
|
|
// Read the site location property.
|
|
//
|
|
bStatus DBGCHK = m_Ds.ReadStringProperty( strSitePath, gszSiteLocationPropertyName, strSiteLocation );
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TPhysicalLocation::vTrimSlash
|
|
|
|
Description:
|
|
|
|
Removes trailing slashes from the given string
|
|
|
|
Arguments:
|
|
|
|
strLocation - string to shorten
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
VOID
|
|
TPhysicalLocation::
|
|
vTrimSlash (
|
|
IN OUT TString &strLocation
|
|
)
|
|
{
|
|
UINT uLen;
|
|
LPTSTR szTrimSlash;
|
|
|
|
uLen = strLocation.uLen();
|
|
|
|
while (uLen && *(static_cast<LPCTSTR>(strLocation)+uLen-1) == gchSeparator)
|
|
{
|
|
uLen--;
|
|
};
|
|
|
|
if (uLen)
|
|
{
|
|
szTrimSlash = new TCHAR[uLen+1];
|
|
|
|
if (szTrimSlash)
|
|
{
|
|
_tcsncpy (szTrimSlash, strLocation, uLen);
|
|
|
|
*(szTrimSlash+uLen) = 0;
|
|
|
|
strLocation.bUpdate (szTrimSlash);
|
|
|
|
delete [] szTrimSlash;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strLocation.bUpdate (gszNULL);
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
AddrToSite
|
|
|
|
Description:
|
|
|
|
Converts a single ip address to a site name.
|
|
|
|
Arguments:
|
|
|
|
dwAddr - the IP address.
|
|
strSiteName - return the site name here.
|
|
strSubnetName - return the subnet name here.
|
|
|
|
Return Value:
|
|
|
|
TRUE success, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
DsAddressToSiteNamesEx only returns the nearest subnet when there are multiple
|
|
sites defined in the DS.
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
AddrToSite(
|
|
IN DWORD dwAddr,
|
|
IN TString &strSiteName,
|
|
IN TString &strSubnetName
|
|
)
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
SOCKET_ADDRESS SockAddr = {0};
|
|
SOCKADDR_IN SockAddrIn = {0};
|
|
PWSTR *ppSiteNames = NULL;
|
|
PWSTR *ppSubnetNames = NULL;
|
|
TStatusB bStatus;
|
|
|
|
//
|
|
// Create a socket from an IP address.
|
|
//
|
|
SockAddr.iSockaddrLength = sizeof(SOCKADDR_IN);
|
|
SockAddr.lpSockaddr = (LPSOCKADDR)&SockAddrIn;
|
|
|
|
SockAddrIn.sin_family = AF_INET;
|
|
SockAddrIn.sin_port = 0;
|
|
|
|
memcpy( &SockAddrIn.sin_addr, &dwAddr, sizeof(dwAddr) );
|
|
|
|
//
|
|
// If a no zero address was given then attempt to find a site
|
|
// that this address belongs to.
|
|
//
|
|
if (dwAddr)
|
|
{
|
|
dwStatus = m_DsAddressToSiteNames( NULL, 1, &SockAddr, &ppSiteNames, &ppSubnetNames );
|
|
|
|
if (dwStatus == ERROR_SUCCESS)
|
|
{
|
|
if (ppSiteNames)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "SiteName " TSTR "\n", DBGSTR( ppSiteNames[0] ) ) );
|
|
|
|
bStatus DBGCHK = strSiteName.bUpdate( ppSiteNames[0] );
|
|
|
|
m_NetApiBufferFree( ppSiteNames );
|
|
}
|
|
|
|
if (ppSubnetNames)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "SubnetName " TSTR "\n", DBGSTR( ppSubnetNames[0] ) ) );
|
|
|
|
bStatus DBGCHK = strSubnetName.bUpdate( ppSubnetNames[0] );
|
|
|
|
m_NetApiBufferFree( ppSubnetNames );
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwStatus == ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetIpAddressTable
|
|
|
|
Description:
|
|
|
|
Returns an array of Ip address for this machine. The caller
|
|
must free the array using the delete operator.
|
|
|
|
Arguments:
|
|
|
|
ppAddrTable - Pointer were to return a pointer to the array of
|
|
ip addresses.
|
|
|
|
Return Value:
|
|
|
|
TRUE success, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
GetIpAddressTable(
|
|
PMIB_IPADDRTABLE *ppAddrTable
|
|
)
|
|
{
|
|
SPLASSERT( ppAddrTable );
|
|
|
|
DWORD dwTableSize = 0;
|
|
PMIB_IPADDRTABLE pAddrTable = NULL;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
BOOL bRet = FALSE;
|
|
|
|
dwStatus = m_GetIpAddrTable(NULL, &dwTableSize, FALSE);
|
|
|
|
if (dwStatus == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
pAddrTable = (PMIB_IPADDRTABLE)new BYTE[dwTableSize];
|
|
|
|
if (pAddrTable)
|
|
{
|
|
dwStatus = m_GetIpAddrTable(pAddrTable, &dwTableSize, FALSE);
|
|
|
|
if (dwStatus == ERROR_SUCCESS)
|
|
{
|
|
*ppAddrTable = pAddrTable;
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
delete [] pAddrTable;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// new has failed
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetSubnetObjectNames
|
|
|
|
Description:
|
|
|
|
Returns a list of subnet objects for this machine. Since the machine
|
|
may have multiple ip address the same goes for the subnets.
|
|
|
|
Arguments:
|
|
|
|
Subnets - Refrence to subnet Class that will contain on return a
|
|
list of subnet objects.
|
|
|
|
Return Value:
|
|
|
|
TRUE subnet object returned, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
GetSubnetObjectNames(
|
|
IN TSubnets &Subnets
|
|
)
|
|
{
|
|
TString strConfig;
|
|
TStatusB bStatus;
|
|
|
|
//
|
|
// Get the path to the configuration container.
|
|
//
|
|
bStatus DBGCHK = m_Ds.GetConfigurationContainer( strConfig );
|
|
|
|
if (bStatus)
|
|
{
|
|
TSubnets Subnets2;
|
|
TString strSubnetObject;
|
|
|
|
//
|
|
// Get the subnet names.
|
|
//
|
|
bStatus DBGCHK = GetSubnetNames( Subnets2 );
|
|
|
|
//
|
|
// Transform the subnet names into subnet object names.
|
|
//
|
|
for( UINT i = 0; i < Subnets2.NumEntries(); i++ )
|
|
{
|
|
bStatus DBGCHK = strSubnetObject.bUpdate( gszCNEquals ) &&
|
|
strSubnetObject.bCat( Subnets2.Table(i) ) &&
|
|
strSubnetObject.bCat( gszComma ) &&
|
|
strSubnetObject.bCat( gszSubnetContainter ) &&
|
|
strSubnetObject.bCat( gszComma ) &&
|
|
strSubnetObject.bCat( strConfig );
|
|
if (bStatus)
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "SubnetObject " TSTR ".\n", (LPCTSTR)strSubnetObject ) );
|
|
|
|
//
|
|
// Add the subnet object entry.
|
|
//
|
|
if (!(bStatus DBGCHK = Subnets.AddEntry( strSubnetObject )))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
GetSubnetNames
|
|
|
|
Description:
|
|
|
|
Return a list of subnet strings for this machine, a machine may
|
|
be on multiple subnet since they may have multiple ip addresses.
|
|
|
|
Arguments:
|
|
|
|
TSubnet & - refrence to class of Subnets.
|
|
|
|
Return Value:
|
|
|
|
TRUE subnets were returned, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
GetSubnetNames(
|
|
IN TSubnets &Subnets
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
PMIB_IPADDRTABLE pAddrTable = NULL;
|
|
TString strSubnet;
|
|
|
|
Subnets.ClearAll();
|
|
|
|
bStatus DBGCHK = GetIpAddressTable( &pAddrTable );
|
|
|
|
if (bStatus && pAddrTable )
|
|
{
|
|
for (UINT i = 0; i < pAddrTable->dwNumEntries; i++)
|
|
{
|
|
//
|
|
// Skip the loopback or unassigned interfaces
|
|
//
|
|
if((pAddrTable->table[i].dwAddr != 0) && (pAddrTable->table[i].dwAddr != c_LoopBackAddress.s_addr))
|
|
{
|
|
IN_ADDR IpSubnetAddr;
|
|
|
|
IpSubnetAddr.s_addr = pAddrTable->table[i].dwAddr & pAddrTable->table[i].dwMask;
|
|
|
|
LPSTR pszIpAddress = m_inet_ntoa( IpSubnetAddr );
|
|
|
|
//
|
|
// Format the subnet mask to match the way subnet objects are
|
|
// in the DS. XX.XX.XX.XX/SS where SS are the number of significant
|
|
// bit in the subnet mask.
|
|
//
|
|
bStatus DBGCHK = strSubnet.bFormat( _T("%S\\/%d"),
|
|
pszIpAddress ? pszIpAddress : "",
|
|
NumSetBits( pAddrTable->table[i].dwMask ) );
|
|
|
|
if (bStatus)
|
|
{
|
|
//
|
|
// Add the subnet entry to the list of subnets.
|
|
//
|
|
bStatus DBGCHK = Subnets.AddEntry( strSubnet );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete [] pAddrTable;
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
WidenScope
|
|
|
|
Description:
|
|
|
|
This routine expands the scope of the specified physical location string.
|
|
The physical location string uses / as scope separators. For example
|
|
if the physical location string on a computer object is
|
|
"/Redmond/Main Campus/Building 26 North/Floor 1/Office 1438"
|
|
after calling this routine with a count of 1 the new physical location
|
|
string will be "/Redmond/Main Campus/Building 26 North/Floor 1"
|
|
Thus it has expanded the scope this computer object is in.
|
|
|
|
Arguments:
|
|
|
|
pszString - pointer to physical location string to widen
|
|
uCount - number of scopes to widen the scope by, must be 1 or greater
|
|
strString - refrence to string object where to return the new widened scope.
|
|
|
|
Return Value:
|
|
|
|
TRUE the scope was widened, FALSE error occurred.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::
|
|
WidenScope(
|
|
IN LPCTSTR pszString,
|
|
IN UINT uCount,
|
|
IN OUT TString &strString
|
|
) const
|
|
{
|
|
TStatusB bStatus;
|
|
bStatus DBGNOCHK = FALSE;
|
|
|
|
if (uCount && pszString && *pszString)
|
|
{
|
|
UINT uLen = _tcslen( pszString );
|
|
|
|
LPTSTR pszTemp = new TCHAR [uLen+1];
|
|
|
|
if (pszTemp)
|
|
{
|
|
_tcscpy( pszTemp, pszString );
|
|
|
|
//
|
|
// Search from the end of the string to the beginning
|
|
// counting the number of separators, terminate when the
|
|
// desired count is reached.
|
|
//
|
|
for( LPTSTR p = pszTemp + uLen - 1; p != pszTemp; p-- )
|
|
{
|
|
if (*p == gchSeparator)
|
|
{
|
|
if (!--uCount)
|
|
{
|
|
*p = NULL;
|
|
bStatus DBGCHK = strString.bUpdate( pszTemp );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete [] pszTemp;
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
NumSetBits
|
|
|
|
Description:
|
|
|
|
Determines the number of set bits in the specified value.
|
|
|
|
Arguments:
|
|
|
|
DWORD Value - Value to count set bits.
|
|
|
|
Return Value:
|
|
|
|
Number of set bits in the value.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
UINT
|
|
TPhysicalLocation::
|
|
NumSetBits(
|
|
IN DWORD Value
|
|
)
|
|
{
|
|
UINT Count = 0;
|
|
|
|
//
|
|
// Start with the high order bit set and shift the bit
|
|
// to the right. This routine could be made very generic
|
|
// if a pointer to the value and the size in bytes of the
|
|
// value was accepted.
|
|
//
|
|
for( DWORD i = 1 << ( sizeof(Value) * 8 - 1 ); i; i >>= 1 )
|
|
{
|
|
Count += (Value & i) ? 1 : 0;
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TSubnets
|
|
|
|
Description:
|
|
|
|
Constructor.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Nothing.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
TPhysicalLocation::TSubnets::
|
|
TSubnets(
|
|
VOID
|
|
) : m_uNumEntries( 0 ),
|
|
m_pstrTable( NULL )
|
|
{
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TSubnets
|
|
|
|
Description:
|
|
|
|
Destructor.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Nothing.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
TPhysicalLocation::TSubnets::
|
|
~TSubnets(
|
|
VOID
|
|
)
|
|
{
|
|
delete [] m_pstrTable;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
ClearAll
|
|
|
|
Description:
|
|
|
|
Release the all the subnet entries.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Nothing.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
VOID
|
|
TPhysicalLocation::TSubnets::
|
|
ClearAll(
|
|
VOID
|
|
)
|
|
{
|
|
m_uNumEntries = 0;
|
|
delete [] m_pstrTable;
|
|
m_pstrTable = NULL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
NumEntries
|
|
|
|
Description:
|
|
|
|
Return the total number of valid entries.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Number of subnet entries.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
UINT
|
|
TPhysicalLocation::TSubnets::
|
|
NumEntries(
|
|
VOID
|
|
)
|
|
{
|
|
return m_uNumEntries;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
Table
|
|
|
|
Description:
|
|
|
|
Return the string using the speified index.
|
|
|
|
Arguments:
|
|
|
|
Index - Zero based index of which string to return.
|
|
|
|
Return Value:
|
|
|
|
Refrence to string.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
TString &
|
|
TPhysicalLocation::TSubnets::
|
|
Table(
|
|
UINT Index
|
|
)
|
|
{
|
|
SPLASSERT( m_pstrTable || Index < m_uNumEntries);
|
|
return m_pstrTable[Index];
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
AddEntry
|
|
|
|
Description:
|
|
|
|
Add a new subnet entry into the array of subnet strings.
|
|
|
|
Arguments:
|
|
|
|
pszNew - pointer to new subnet string to add.
|
|
|
|
Return Value:
|
|
|
|
TRUE new subnet string was added, FALSE error.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
BOOL
|
|
TPhysicalLocation::TSubnets::
|
|
AddEntry(
|
|
IN LPCTSTR pszNew
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
|
|
//
|
|
// Assume failure.
|
|
//
|
|
bStatus DBGNOCHK = FALSE;
|
|
|
|
//
|
|
// Allocate the new array of strings. Yes this
|
|
// is not the most efficent code but it works.
|
|
// Maybe a string list would be a better
|
|
// choice if I had one or the time to implement one.
|
|
//
|
|
TString *pTemp = new TString [m_uNumEntries+1];
|
|
|
|
if (pTemp)
|
|
{
|
|
//
|
|
// Assume success this is needed when the first
|
|
// string is added.
|
|
//
|
|
bStatus DBGNOCHK = TRUE;
|
|
|
|
//
|
|
// Copy the strings to the new array of strings.
|
|
//
|
|
for( UINT i = 0; i < m_uNumEntries; i++ )
|
|
{
|
|
if (!(bStatus DBGCHK = pTemp[i].bUpdate( m_pstrTable[i] )))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the new string.
|
|
//
|
|
if (bStatus)
|
|
{
|
|
bStatus DBGCHK = pTemp[i].bUpdate( pszNew );
|
|
|
|
if( bStatus )
|
|
{
|
|
delete [] m_pstrTable;
|
|
m_pstrTable = pTemp;
|
|
m_uNumEntries++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If something failed free the temp string array.
|
|
//
|
|
if( !bStatus )
|
|
{
|
|
delete [] pTemp;
|
|
}
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
TPhysicalLocation::bLocationEnabled
|
|
|
|
Description:
|
|
Checks policy bit to determine if physical location support is enabled
|
|
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
TRUE if enabled, FALSE otherwise
|
|
|
|
Notes:
|
|
Support is disabled by default
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
TPhysicalLocation::
|
|
bLocationEnabled(
|
|
VOID
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
BOOL bRet = FALSE;
|
|
|
|
TPersist PersistPolicy( gszSpoolerPolicy, TPersist::kOpen|TPersist::kRead, HKEY_LOCAL_MACHINE );
|
|
|
|
if( VALID_OBJ( PersistPolicy ) )
|
|
{
|
|
bStatus DBGNOCHK = PersistPolicy.bRead( gszUsePhysicalLocation, bRet );
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|