Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1650 lines
33 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. location.cxx
  5. Abstract:
  6. This module provides all the functions for determining the
  7. machines current physical location.
  8. Author:
  9. Steve Kiraly (SteveKi) 13-July-1998
  10. Revision History:
  11. Steve Kiraly (SteveKi) 13-July-1998 Genesis
  12. --*/
  13. #include <precomp.hxx>
  14. #pragma hdrstop
  15. #include "dsinterf.hxx"
  16. #include "persist.hxx"
  17. #include "physloc.hxx"
  18. const IN_ADDR c_LoopBackAddress = { 127,0,0,1 };
  19. /*++
  20. Name:
  21. TPhysicalLocation
  22. Description:
  23. TPhysicalLocation constructor.
  24. Arguments:
  25. None.
  26. Return Value:
  27. Nothing.
  28. Notes:
  29. --*/
  30. TPhysicalLocation::
  31. TPhysicalLocation(
  32. VOID
  33. ) : m_fInitalized( FALSE ),
  34. m_eDiscoveryType( kDiscoveryTypeUnknown ),
  35. m_IpHlpApi( gszIpHlpApiLibrary ),
  36. m_GetIpAddrTable( NULL ),
  37. m_SecExt( gszSecurityLibrary ),
  38. m_GetComputerObjectName( NULL ),
  39. m_GetUserNameEx( NULL ),
  40. m_NetApi( gszNetApiLibrary ),
  41. m_DsAddressToSiteNames( NULL ),
  42. m_NetApiBufferFree( NULL ),
  43. m_WinSock( gszWinSockLibrary ),
  44. m_inet_ntoa( NULL )
  45. {
  46. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ctor.\n" ) );
  47. //
  48. // Check if the Ip helper library was loaded.
  49. //
  50. if (m_IpHlpApi.bValid())
  51. {
  52. m_GetIpAddrTable = reinterpret_cast<pfGetIpAddrTable>( m_IpHlpApi.pfnGetProc( "GetIpAddrTable" ) );
  53. }
  54. //
  55. // Check if the security library was loaded.
  56. //
  57. if (m_SecExt.bValid())
  58. {
  59. m_GetComputerObjectName = reinterpret_cast<pfGetComputerObjectName>( m_SecExt.pfnGetProc( "GetComputerObjectNameW" ) );
  60. m_GetUserNameEx = reinterpret_cast<pfGetUserNameEx>( m_SecExt.pfnGetProc( "GetUserNameExW" ) );
  61. }
  62. //
  63. // Check if the netapi library was loaded.
  64. //
  65. if (m_NetApi.bValid())
  66. {
  67. m_DsAddressToSiteNames = reinterpret_cast<pfDsAddressToSiteNames>( m_NetApi.pfnGetProc( "DsAddressToSiteNamesExW" ) );
  68. m_NetApiBufferFree = reinterpret_cast<pfNetApiBufferFree>( m_NetApi.pfnGetProc( "NetApiBufferFree" ) );
  69. }
  70. //
  71. // Check if the winsock library was loaded.
  72. //
  73. if (m_WinSock.bValid())
  74. {
  75. m_inet_ntoa = reinterpret_cast<LPFN_INET_NTOA>( m_WinSock.pfnGetProc( "inet_ntoa" ) );
  76. }
  77. //
  78. // All the function pointers must be valid for this class to be in
  79. // the initialized state.
  80. //
  81. if (m_GetIpAddrTable && m_GetComputerObjectName && m_GetUserNameEx && m_DsAddressToSiteNames && m_NetApiBufferFree && m_inet_ntoa)
  82. {
  83. m_fInitalized = TRUE;
  84. }
  85. }
  86. /*++
  87. Name:
  88. TPhysicalLocation
  89. Description:
  90. TPhysicalLocation destructor.
  91. Arguments:
  92. None.
  93. Return Value:
  94. Nothing.
  95. Notes:
  96. --*/
  97. TPhysicalLocation::
  98. ~TPhysicalLocation(
  99. VOID
  100. )
  101. {
  102. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::dtor.\n" ) );
  103. }
  104. /*++
  105. Name:
  106. bValid
  107. Description:
  108. This routine indicates if the TPhysicalLocation class is
  109. in a consistent state, i.e. usable.
  110. Arguments:
  111. None.
  112. Return Value:
  113. TRUE usable state, FALSE not usable.
  114. Notes:
  115. --*/
  116. BOOL
  117. TPhysicalLocation::
  118. bValid(
  119. VOID
  120. ) const
  121. {
  122. return m_fInitalized;
  123. }
  124. /*++
  125. Name:
  126. Discover
  127. Description:
  128. The discover routine is where all the work is done. We attempt
  129. to fetch the physical location string from various sources in a
  130. pre defined order. If any of the steps completes the search is
  131. terminated. The current order is to look in the HKLM policy key,
  132. this machines location property in the DS
  133. Arguments:
  134. None.
  135. Return Value:
  136. TRUE usable state, FALSE not usable.
  137. Notes:
  138. --*/
  139. BOOL
  140. TPhysicalLocation::
  141. Discover(
  142. VOID
  143. )
  144. {
  145. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::Discover.\n" ) );
  146. //
  147. // Invalidate the current location information.
  148. //
  149. Invalidate();
  150. //
  151. // Read the group policy setting if it exists.
  152. //
  153. if (ReadGroupPolicyLocationSetting( m_strLocation ))
  154. {
  155. m_eDiscoveryType = kDiscoveryTypePolicy;
  156. }
  157. //
  158. // If a DS is available and the group policy did not have any
  159. // location information then continue looking for location information.
  160. //
  161. if (m_Ds.bIsDsAvailable() && m_eDiscoveryType == kDiscoveryTypeUnknown)
  162. {
  163. if (ReadMachinesLocationProperty( m_strLocation ))
  164. {
  165. m_eDiscoveryType = kDiscoveryTypeMachine;
  166. }
  167. else if (ReadSubnetLocationProperty( m_strLocation ))
  168. {
  169. m_eDiscoveryType = kDiscoveryTypeSubnet;
  170. }
  171. else if (ReadSiteLocationProperty( m_strLocation ))
  172. {
  173. m_eDiscoveryType = kDiscoveryTypeSite;
  174. }
  175. }
  176. return m_eDiscoveryType != kDiscoveryTypeUnknown;
  177. }
  178. /*++
  179. Name:
  180. GetExact
  181. Description:
  182. Returns the excact location string found by a call to the discover method.
  183. Arguments:
  184. strLocation - reference to a string object where to return the string.
  185. Return Value:
  186. TRUE search string returned, FALSE error occurred.
  187. Notes:
  188. --*/
  189. BOOL
  190. TPhysicalLocation::
  191. GetExact(
  192. IN TString &strLocation
  193. ) const
  194. {
  195. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::GetExact.\n" ) );
  196. return strLocation.bUpdate( m_strLocation );
  197. }
  198. /*++
  199. Name:
  200. GetSearch
  201. Description:
  202. Returns a string that is valid for a search. It widens the scope if the
  203. current location string is one fetched for this machine.
  204. Arguments:
  205. strLocation - reference to a string object where to return the search string.
  206. Return Value:
  207. TRUE search string returned, FALSE error occurred.
  208. Notes:
  209. --*/
  210. BOOL
  211. TPhysicalLocation::
  212. GetSearch(
  213. IN TString &strLocation
  214. ) const
  215. {
  216. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::GetSearch.\n" ) );
  217. TStatusB bStatus;
  218. if (m_eDiscoveryType == kDiscoveryTypeMachine || m_eDiscoveryType == kDiscoveryTypePolicy)
  219. {
  220. bStatus DBGCHK = WidenScope( m_strLocation, 1, strLocation );
  221. //
  222. // If the scope could not be widen then use the current location string.
  223. //
  224. if (!bStatus)
  225. {
  226. bStatus DBGCHK = strLocation.bUpdate( m_strLocation );
  227. }
  228. }
  229. else
  230. {
  231. bStatus DBGCHK = strLocation.bUpdate( m_strLocation );
  232. }
  233. if( bStatus )
  234. {
  235. UINT uLen = strLocation.uLen();
  236. if( uLen && gchSeparator != static_cast<LPCTSTR>(strLocation)[uLen-1] )
  237. {
  238. //
  239. // Put the final slash after successfully
  240. // widening the location scope
  241. //
  242. static const TCHAR szSepStr[] = { gchSeparator };
  243. bStatus DBGCHK = strLocation.bCat( szSepStr );
  244. }
  245. }
  246. return bStatus;
  247. }
  248. /*++
  249. Name:
  250. Invalidate
  251. Description:
  252. Invalidates the location string. After this call the location string
  253. is not valid until the disover method is called.
  254. Arguments:
  255. None.
  256. Return Value:
  257. Nothing.
  258. Notes:
  259. --*/
  260. VOID
  261. TPhysicalLocation::
  262. Invalidate(
  263. VOID
  264. )
  265. {
  266. m_eDiscoveryType = kDiscoveryTypeUnknown;
  267. m_strLocation.bUpdate( NULL );
  268. }
  269. /*++
  270. Name:
  271. ReadGroupPolicyLocationSetting
  272. Description:
  273. Reads the location string from the local registry that was written
  274. by the group policy editor.
  275. Arguments:
  276. None.
  277. Return Value:
  278. TRUE the location string was read, FALSE error occured or string not available.
  279. Notes:
  280. --*/
  281. BOOL
  282. TPhysicalLocation::
  283. ReadGroupPolicyLocationSetting(
  284. IN OUT TString &strLocationX
  285. )
  286. {
  287. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadGroupPolicyLocationSetting.\n" ) );
  288. //
  289. // Open the registry key where the physical location is stored
  290. // by the group policy code.
  291. //
  292. TPersist Reg( gszGroupPolicyPhysicalLocationPath, TPersist::kOpen|TPersist::kRead, HKEY_LOCAL_MACHINE );
  293. TStatusB bStatus;
  294. //
  295. // Was the key opened, i.e. does it exist?
  296. //
  297. bStatus DBGCHK = Reg.bValid();
  298. if (bStatus)
  299. {
  300. TString strLocation;
  301. //
  302. // Read the location string from the registry.
  303. //
  304. bStatus DBGCHK = Reg.bRead( gszGroupPolicyPhysicalLocationKey, strLocation );
  305. //
  306. // If the string was read and it is not blank then make a local copy of the
  307. // location string and we are done.
  308. //
  309. if (bStatus && !strLocation.bEmpty())
  310. {
  311. bStatus DBGCHK = strLocationX.bUpdate( strLocation );
  312. }
  313. }
  314. return bStatus;
  315. }
  316. /*++
  317. Name:
  318. ReadUserLocationProperty
  319. Description:
  320. Reads the location string from the current users object in the
  321. DS.
  322. Arguments:
  323. None.
  324. Return Value:
  325. TRUE success, FALSE error occurred.
  326. Notes:
  327. --*/
  328. BOOL
  329. TPhysicalLocation::
  330. ReadUserLocationProperty(
  331. IN OUT TString &strLocation
  332. )
  333. {
  334. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadUserLocationProperty.\n" ) );
  335. TCHAR szName[INTERNET_MAX_HOST_NAME_LENGTH+1];
  336. DWORD dwSize = COUNTOF( szName );
  337. TStatusB bStatus;
  338. bStatus DBGCHK = m_GetUserNameEx(NameFullyQualifiedDN, szName, &dwSize);
  339. if (bStatus)
  340. {
  341. TString strUserPath;
  342. TString strLDAPPrefix;
  343. bStatus DBGCHK = m_Ds.GetLDAPPrefixPerUser( strLDAPPrefix ) &&
  344. strUserPath.bCat( strLDAPPrefix ) &&
  345. strUserPath.bCat( szName );
  346. if (bStatus)
  347. {
  348. bStatus DBGCHK = m_Ds.ReadStringProperty( strUserPath, gszUserLocationPropertyName, strLocation );
  349. }
  350. }
  351. return bStatus;
  352. }
  353. /*++
  354. Name:
  355. ReadMachinesLocationProperty
  356. Description:
  357. Reads the location string from the machine object in the DS.
  358. Arguments:
  359. None.
  360. Return Value:
  361. TRUE success, FALSE error occurred.
  362. Notes:
  363. --*/
  364. BOOL
  365. TPhysicalLocation::
  366. ReadMachinesLocationProperty(
  367. IN OUT TString &strLocation
  368. )
  369. {
  370. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadMachinesLocationProperty.\n" ) );
  371. LPTSTR pszName = NULL;
  372. DWORD dwSize = 0;
  373. TStatusB bStatus;
  374. bStatus DBGCHK = m_GetComputerObjectName(NameFullyQualifiedDN, NULL, &dwSize);
  375. if( bStatus && dwSize )
  376. {
  377. pszName = new TCHAR[dwSize+1];
  378. if( pszName )
  379. {
  380. bStatus DBGCHK = m_GetComputerObjectName(NameFullyQualifiedDN, pszName, &dwSize);
  381. if (bStatus)
  382. {
  383. TString strComputerPath;
  384. TString strLDAPPrefix;
  385. bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
  386. strComputerPath.bCat( strLDAPPrefix ) &&
  387. strComputerPath.bCat( pszName );
  388. if (bStatus)
  389. {
  390. bStatus DBGCHK = m_Ds.ReadStringProperty( strComputerPath, gszMachineLocationPropertyName, strLocation );
  391. }
  392. }
  393. delete [] pszName;
  394. }
  395. }
  396. if( bStatus )
  397. {
  398. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadMachinesLocationProperty " TSTR ".\n", pszName ) );
  399. }
  400. return bStatus;
  401. }
  402. /*++
  403. Name:
  404. ReadSubnetLocationProperty
  405. Description:
  406. Reads the location string from the subnet objet for this
  407. machine. This routine searches the list of IP address IP masks
  408. and finds a subnet object in the DS that closly matches this
  409. machine.
  410. Arguments:
  411. None.
  412. Return Value:
  413. TRUE success, FALSE error occurred.
  414. Notes:
  415. --*/
  416. BOOL
  417. TPhysicalLocation::
  418. ReadSubnetLocationProperty(
  419. IN OUT TString &strLocation
  420. )
  421. {
  422. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadSubnetLocationProperty.\n" ) );
  423. TString strSubnetPath;
  424. TString strLDAPPrefix;
  425. TSubnets Subnets;
  426. TStatusB bStatus;
  427. bStatus DBGCHK = GetSubnetObjectNames( Subnets );
  428. if (bStatus)
  429. {
  430. for( UINT i = 0; i < Subnets.NumEntries(); i++ )
  431. {
  432. bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
  433. strSubnetPath.bUpdate( strLDAPPrefix ) &&
  434. strSubnetPath.bCat( Subnets.Table(i) );
  435. if (bStatus)
  436. {
  437. bStatus DBGCHK = m_Ds.ReadStringProperty( strSubnetPath, gszSubnetLocationPropertyName, strLocation );
  438. if (bStatus && !strLocation.bEmpty())
  439. {
  440. break;
  441. }
  442. }
  443. }
  444. }
  445. return bStatus;
  446. }
  447. /*++
  448. Name:
  449. ReadSiteLocationProperty
  450. Description:
  451. Reads the location string from the site object. This routine
  452. searches the list of IP address and finds a site nearest this
  453. machines ip adress. All of the searching code actually occurrs
  454. in the DSAddressToSiteNames api.
  455. Arguments:
  456. None.
  457. Return Value:
  458. TRUE success, FALSE error occurred.
  459. Notes:
  460. --*/
  461. BOOL
  462. TPhysicalLocation::
  463. ReadSiteLocationProperty(
  464. IN OUT TString &strLocation
  465. )
  466. {
  467. DBGMSG( DBG_TRACE, ( "TPhysicalLocation::ReadSiteLocationProperty.\n" ) );
  468. PMIB_IPADDRTABLE pAddrTable = NULL;
  469. TStatusB bStatus;
  470. TString strSiteName;
  471. TString strSubnetName;
  472. TString strSubnetPath;
  473. IN_ADDR IpNetAddr;
  474. //
  475. // Get the DS name.
  476. //
  477. bStatus DBGCHK = GetIpAddressTable( &pAddrTable );
  478. if (bStatus)
  479. {
  480. bStatus DBGNOCHK = FALSE;
  481. //
  482. // Look for a site that has a location string that corresponds
  483. // to the the first ipaddress in the list of ip addresses.
  484. //
  485. for (UINT i = 0; i < pAddrTable->dwNumEntries; i++)
  486. {
  487. //
  488. // Skip the loopback or unassigned interfaces
  489. //
  490. if ((pAddrTable->table[i].dwAddr != 0) && (pAddrTable->table[i].dwAddr != c_LoopBackAddress.s_addr))
  491. {
  492. IpNetAddr.s_addr = pAddrTable->table[i].dwAddr;
  493. DBGMSG( DBG_TRACE, ( "IP Address %s\n", m_inet_ntoa( IpNetAddr ) ) );
  494. //
  495. // Attempt to translate this ip address to either a site path or subnet path.
  496. //
  497. bStatus DBGNOCHK = AddrToSite( pAddrTable->table[i].dwAddr, strSiteName, strSubnetName );
  498. if (bStatus)
  499. {
  500. //
  501. // If a near match subnet was found use this first.
  502. //
  503. if (!strSubnetName.bEmpty())
  504. {
  505. bStatus DBGCHK = GetSubnetLocationString( strSubnetName, strLocation );
  506. }
  507. //
  508. // If the location string was not found on the subnet then attempt to
  509. // get the location on the site object.
  510. //
  511. if (!strSiteName.bEmpty() && strLocation.bEmpty())
  512. {
  513. bStatus DBGCHK = GetSiteLocationString( strSiteName, strLocation );
  514. }
  515. //
  516. // If a location string was found exit the loop, the first ipaddress wins.
  517. //
  518. if (strLocation.bEmpty())
  519. {
  520. bStatus DBGNOCHK = FALSE;
  521. }
  522. else
  523. {
  524. break;
  525. }
  526. }
  527. }
  528. }
  529. }
  530. delete [] pAddrTable;
  531. return bStatus;
  532. }
  533. /*++
  534. Name:
  535. GetSubnetLocationString
  536. Description:
  537. Reads the location string from the subnet object. This routine
  538. converts the subnet name to an adsi path then reads the location
  539. property fron this subnet object.
  540. Arguments:
  541. pszSubnetName - pointer string which contains the subnet name.
  542. strSiteLocation - reference to string object where to return the subnet
  543. location string.
  544. Return Value:
  545. TRUE success, FALSE error occurred.
  546. Notes:
  547. --*/
  548. BOOL
  549. TPhysicalLocation::
  550. GetSubnetLocationString(
  551. IN LPCTSTR pszSubnetName,
  552. IN OUT TString &strSubnetLocation
  553. )
  554. {
  555. TString strSubnetPath;
  556. TString strConfig;
  557. TString strLDAPPrefix;
  558. TStatusB bStatus;
  559. TCHAR szSubnetName[MAX_PATH];
  560. //
  561. // Sites are located in the configuration container.
  562. //
  563. bStatus DBGCHK = m_Ds.GetConfigurationContainer( strConfig );
  564. if (bStatus)
  565. {
  566. //
  567. // Escape the / in the subnet name.
  568. //
  569. for ( LPTSTR p = szSubnetName; pszSubnetName && *pszSubnetName; )
  570. {
  571. if (*pszSubnetName == _T('/'))
  572. {
  573. *p++ = _T('\\');
  574. }
  575. *p++ = *pszSubnetName++;
  576. }
  577. *p = NULL;
  578. //
  579. // Build the site adsi object path.
  580. //
  581. bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
  582. strSubnetPath.bCat( strLDAPPrefix ) &&
  583. strSubnetPath.bCat( gszCNEquals ) &&
  584. strSubnetPath.bCat( szSubnetName ) &&
  585. strSubnetPath.bCat( gszComma ) &&
  586. strSubnetPath.bCat( gszSubnetContainter) &&
  587. strSubnetPath.bCat( gszComma ) &&
  588. strSubnetPath.bCat( strConfig );
  589. DBGMSG( DBG_TRACE, ( "Subnet Path " TSTR ".\n", (LPCTSTR)strSubnetPath ) );
  590. if (bStatus)
  591. {
  592. //
  593. // Read the site location property.
  594. //
  595. bStatus DBGCHK = m_Ds.ReadStringProperty( strSubnetPath, gszSubnetLocationPropertyName, strSubnetLocation );
  596. }
  597. }
  598. return bStatus;
  599. }
  600. /*++
  601. Name:
  602. GetSiteLocationString
  603. Description:
  604. Reads the location string from the site object. This routine
  605. converts the site name to an adsi path then reads the location
  606. property fron this site object.
  607. Arguments:
  608. pszSiteName - pointer string which contains the site name.
  609. strSiteLocation - reference to string object where to return the site
  610. location string.
  611. Return Value:
  612. TRUE success, FALSE error occurred.
  613. Notes:
  614. --*/
  615. BOOL
  616. TPhysicalLocation::
  617. GetSiteLocationString(
  618. IN LPCTSTR pszSiteName,
  619. IN OUT TString &strSiteLocation
  620. )
  621. {
  622. TString strConfig;
  623. TString strSitePath;
  624. TString strLDAPPrefix;
  625. TStatusB bStatus;
  626. //
  627. // Sites are located in the configuration container.
  628. //
  629. bStatus DBGCHK = m_Ds.GetConfigurationContainer( strConfig );
  630. if (bStatus)
  631. {
  632. //
  633. // Build the site adsi object path.
  634. //
  635. bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
  636. strSitePath.bCat( strLDAPPrefix ) &&
  637. strSitePath.bCat( gszCNEquals ) &&
  638. strSitePath.bCat( pszSiteName ) &&
  639. strSitePath.bCat( gszComma ) &&
  640. strSitePath.bCat( gszSitesContainter) &&
  641. strSitePath.bCat( gszComma ) &&
  642. strSitePath.bCat( strConfig );
  643. DBGMSG( DBG_TRACE, ( "Site Path " TSTR ".\n", (LPCTSTR)strSitePath ) );
  644. if (bStatus)
  645. {
  646. //
  647. // Read the site location property.
  648. //
  649. bStatus DBGCHK = m_Ds.ReadStringProperty( strSitePath, gszSiteLocationPropertyName, strSiteLocation );
  650. }
  651. }
  652. return bStatus;
  653. }
  654. /*++
  655. Name:
  656. TPhysicalLocation::vTrimSlash
  657. Description:
  658. Removes trailing slashes from the given string
  659. Arguments:
  660. strLocation - string to shorten
  661. Return Value:
  662. None
  663. Notes:
  664. --*/
  665. VOID
  666. TPhysicalLocation::
  667. vTrimSlash (
  668. IN OUT TString &strLocation
  669. )
  670. {
  671. UINT uLen;
  672. LPTSTR szTrimSlash;
  673. uLen = strLocation.uLen();
  674. while (uLen && *(static_cast<LPCTSTR>(strLocation)+uLen-1) == gchSeparator)
  675. {
  676. uLen--;
  677. };
  678. if (uLen)
  679. {
  680. szTrimSlash = new TCHAR[uLen+1];
  681. if (szTrimSlash)
  682. {
  683. _tcsncpy (szTrimSlash, strLocation, uLen);
  684. *(szTrimSlash+uLen) = 0;
  685. strLocation.bUpdate (szTrimSlash);
  686. delete [] szTrimSlash;
  687. }
  688. }
  689. else
  690. {
  691. strLocation.bUpdate (gszNULL);
  692. }
  693. }
  694. /*++
  695. Name:
  696. AddrToSite
  697. Description:
  698. Converts a single ip address to a site name.
  699. Arguments:
  700. dwAddr - the IP address.
  701. strSiteName - return the site name here.
  702. strSubnetName - return the subnet name here.
  703. Return Value:
  704. TRUE success, FALSE error occurred.
  705. Notes:
  706. DsAddressToSiteNamesEx only returns the nearest subnet when there are multiple
  707. sites defined in the DS.
  708. --*/
  709. BOOL
  710. TPhysicalLocation::
  711. AddrToSite(
  712. IN DWORD dwAddr,
  713. IN TString &strSiteName,
  714. IN TString &strSubnetName
  715. )
  716. {
  717. DWORD dwStatus = ERROR_SUCCESS;
  718. SOCKET_ADDRESS SockAddr = {0};
  719. SOCKADDR_IN SockAddrIn = {0};
  720. PWSTR *ppSiteNames = NULL;
  721. PWSTR *ppSubnetNames = NULL;
  722. TStatusB bStatus;
  723. //
  724. // Create a socket from an IP address.
  725. //
  726. SockAddr.iSockaddrLength = sizeof(SOCKADDR_IN);
  727. SockAddr.lpSockaddr = (LPSOCKADDR)&SockAddrIn;
  728. SockAddrIn.sin_family = AF_INET;
  729. SockAddrIn.sin_port = 0;
  730. memcpy( &SockAddrIn.sin_addr, &dwAddr, sizeof(dwAddr) );
  731. //
  732. // If a no zero address was given then attempt to find a site
  733. // that this address belongs to.
  734. //
  735. if (dwAddr)
  736. {
  737. dwStatus = m_DsAddressToSiteNames( NULL, 1, &SockAddr, &ppSiteNames, &ppSubnetNames );
  738. if (dwStatus == ERROR_SUCCESS)
  739. {
  740. if (ppSiteNames)
  741. {
  742. DBGMSG( DBG_TRACE, ( "SiteName " TSTR "\n", DBGSTR( ppSiteNames[0] ) ) );
  743. bStatus DBGCHK = strSiteName.bUpdate( ppSiteNames[0] );
  744. m_NetApiBufferFree( ppSiteNames );
  745. }
  746. if (ppSubnetNames)
  747. {
  748. DBGMSG( DBG_TRACE, ( "SubnetName " TSTR "\n", DBGSTR( ppSubnetNames[0] ) ) );
  749. bStatus DBGCHK = strSubnetName.bUpdate( ppSubnetNames[0] );
  750. m_NetApiBufferFree( ppSubnetNames );
  751. }
  752. }
  753. }
  754. return dwStatus == ERROR_SUCCESS;
  755. }
  756. /*++
  757. Name:
  758. GetIpAddressTable
  759. Description:
  760. Returns an array of Ip address for this machine. The caller
  761. must free the array using the delete operator.
  762. Arguments:
  763. ppAddrTable - Pointer were to return a pointer to the array of
  764. ip addresses.
  765. Return Value:
  766. TRUE success, FALSE error occurred.
  767. Notes:
  768. --*/
  769. BOOL
  770. TPhysicalLocation::
  771. GetIpAddressTable(
  772. PMIB_IPADDRTABLE *ppAddrTable
  773. )
  774. {
  775. SPLASSERT( ppAddrTable );
  776. DWORD dwTableSize = 0;
  777. PMIB_IPADDRTABLE pAddrTable = NULL;
  778. DWORD dwStatus = ERROR_SUCCESS;
  779. BOOL bRet = FALSE;
  780. dwStatus = m_GetIpAddrTable(NULL, &dwTableSize, FALSE);
  781. if (dwStatus == ERROR_INSUFFICIENT_BUFFER)
  782. {
  783. pAddrTable = (PMIB_IPADDRTABLE)new BYTE[dwTableSize];
  784. if (pAddrTable)
  785. {
  786. dwStatus = m_GetIpAddrTable(pAddrTable, &dwTableSize, FALSE);
  787. if (dwStatus == ERROR_SUCCESS)
  788. {
  789. *ppAddrTable = pAddrTable;
  790. bRet = TRUE;
  791. }
  792. else
  793. {
  794. delete [] pAddrTable;
  795. }
  796. }
  797. else
  798. {
  799. // new has failed
  800. SetLastError(ERROR_OUTOFMEMORY);
  801. }
  802. }
  803. return bRet;
  804. }
  805. /*++
  806. Name:
  807. GetSubnetObjectNames
  808. Description:
  809. Returns a list of subnet objects for this machine. Since the machine
  810. may have multiple ip address the same goes for the subnets.
  811. Arguments:
  812. Subnets - Refrence to subnet Class that will contain on return a
  813. list of subnet objects.
  814. Return Value:
  815. TRUE subnet object returned, FALSE error occurred.
  816. Notes:
  817. --*/
  818. BOOL
  819. TPhysicalLocation::
  820. GetSubnetObjectNames(
  821. IN TSubnets &Subnets
  822. )
  823. {
  824. TString strConfig;
  825. TStatusB bStatus;
  826. //
  827. // Get the path to the configuration container.
  828. //
  829. bStatus DBGCHK = m_Ds.GetConfigurationContainer( strConfig );
  830. if (bStatus)
  831. {
  832. TSubnets Subnets2;
  833. TString strSubnetObject;
  834. //
  835. // Get the subnet names.
  836. //
  837. bStatus DBGCHK = GetSubnetNames( Subnets2 );
  838. //
  839. // Transform the subnet names into subnet object names.
  840. //
  841. for( UINT i = 0; i < Subnets2.NumEntries(); i++ )
  842. {
  843. bStatus DBGCHK = strSubnetObject.bUpdate( gszCNEquals ) &&
  844. strSubnetObject.bCat( Subnets2.Table(i) ) &&
  845. strSubnetObject.bCat( gszComma ) &&
  846. strSubnetObject.bCat( gszSubnetContainter ) &&
  847. strSubnetObject.bCat( gszComma ) &&
  848. strSubnetObject.bCat( strConfig );
  849. if (bStatus)
  850. {
  851. DBGMSG( DBG_TRACE, ( "SubnetObject " TSTR ".\n", (LPCTSTR)strSubnetObject ) );
  852. //
  853. // Add the subnet object entry.
  854. //
  855. if (!(bStatus DBGCHK = Subnets.AddEntry( strSubnetObject )))
  856. {
  857. break;
  858. }
  859. }
  860. }
  861. }
  862. return bStatus;
  863. }
  864. /*++
  865. Name:
  866. GetSubnetNames
  867. Description:
  868. Return a list of subnet strings for this machine, a machine may
  869. be on multiple subnet since they may have multiple ip addresses.
  870. Arguments:
  871. TSubnet & - refrence to class of Subnets.
  872. Return Value:
  873. TRUE subnets were returned, FALSE error occurred.
  874. Notes:
  875. --*/
  876. BOOL
  877. TPhysicalLocation::
  878. GetSubnetNames(
  879. IN TSubnets &Subnets
  880. )
  881. {
  882. TStatusB bStatus;
  883. PMIB_IPADDRTABLE pAddrTable = NULL;
  884. TString strSubnet;
  885. Subnets.ClearAll();
  886. bStatus DBGCHK = GetIpAddressTable( &pAddrTable );
  887. if (bStatus && pAddrTable )
  888. {
  889. for (UINT i = 0; i < pAddrTable->dwNumEntries; i++)
  890. {
  891. //
  892. // Skip the loopback or unassigned interfaces
  893. //
  894. if((pAddrTable->table[i].dwAddr != 0) && (pAddrTable->table[i].dwAddr != c_LoopBackAddress.s_addr))
  895. {
  896. IN_ADDR IpSubnetAddr;
  897. IpSubnetAddr.s_addr = pAddrTable->table[i].dwAddr & pAddrTable->table[i].dwMask;
  898. LPSTR pszIpAddress = m_inet_ntoa( IpSubnetAddr );
  899. //
  900. // Format the subnet mask to match the way subnet objects are
  901. // in the DS. XX.XX.XX.XX/SS where SS are the number of significant
  902. // bit in the subnet mask.
  903. //
  904. bStatus DBGCHK = strSubnet.bFormat( _T("%S\\/%d"),
  905. pszIpAddress ? pszIpAddress : "",
  906. NumSetBits( pAddrTable->table[i].dwMask ) );
  907. if (bStatus)
  908. {
  909. //
  910. // Add the subnet entry to the list of subnets.
  911. //
  912. bStatus DBGCHK = Subnets.AddEntry( strSubnet );
  913. }
  914. }
  915. }
  916. }
  917. delete [] pAddrTable;
  918. return bStatus;
  919. }
  920. /*++
  921. Name:
  922. WidenScope
  923. Description:
  924. This routine expands the scope of the specified physical location string.
  925. The physical location string uses / as scope separators. For example
  926. if the physical location string on a computer object is
  927. "/Redmond/Main Campus/Building 26 North/Floor 1/Office 1438"
  928. after calling this routine with a count of 1 the new physical location
  929. string will be "/Redmond/Main Campus/Building 26 North/Floor 1"
  930. Thus it has expanded the scope this computer object is in.
  931. Arguments:
  932. pszString - pointer to physical location string to widen
  933. uCount - number of scopes to widen the scope by, must be 1 or greater
  934. strString - refrence to string object where to return the new widened scope.
  935. Return Value:
  936. TRUE the scope was widened, FALSE error occurred.
  937. Notes:
  938. --*/
  939. BOOL
  940. TPhysicalLocation::
  941. WidenScope(
  942. IN LPCTSTR pszString,
  943. IN UINT uCount,
  944. IN OUT TString &strString
  945. ) const
  946. {
  947. TStatusB bStatus;
  948. bStatus DBGNOCHK = FALSE;
  949. if (uCount && pszString && *pszString)
  950. {
  951. UINT uLen = _tcslen( pszString );
  952. LPTSTR pszTemp = new TCHAR [uLen+1];
  953. if (pszTemp)
  954. {
  955. _tcscpy( pszTemp, pszString );
  956. //
  957. // Search from the end of the string to the beginning
  958. // counting the number of separators, terminate when the
  959. // desired count is reached.
  960. //
  961. for( LPTSTR p = pszTemp + uLen - 1; p != pszTemp; p-- )
  962. {
  963. if (*p == gchSeparator)
  964. {
  965. if (!--uCount)
  966. {
  967. *p = NULL;
  968. bStatus DBGCHK = strString.bUpdate( pszTemp );
  969. break;
  970. }
  971. }
  972. }
  973. }
  974. delete [] pszTemp;
  975. }
  976. return bStatus;
  977. }
  978. /*++
  979. Name:
  980. NumSetBits
  981. Description:
  982. Determines the number of set bits in the specified value.
  983. Arguments:
  984. DWORD Value - Value to count set bits.
  985. Return Value:
  986. Number of set bits in the value.
  987. Notes:
  988. --*/
  989. UINT
  990. TPhysicalLocation::
  991. NumSetBits(
  992. IN DWORD Value
  993. )
  994. {
  995. UINT Count = 0;
  996. //
  997. // Start with the high order bit set and shift the bit
  998. // to the right. This routine could be made very generic
  999. // if a pointer to the value and the size in bytes of the
  1000. // value was accepted.
  1001. //
  1002. for( DWORD i = 1 << ( sizeof(Value) * 8 - 1 ); i; i >>= 1 )
  1003. {
  1004. Count += (Value & i) ? 1 : 0;
  1005. }
  1006. return Count;
  1007. }
  1008. /*++
  1009. Name:
  1010. TSubnets
  1011. Description:
  1012. Constructor.
  1013. Arguments:
  1014. None.
  1015. Return Value:
  1016. Nothing.
  1017. Notes:
  1018. --*/
  1019. TPhysicalLocation::TSubnets::
  1020. TSubnets(
  1021. VOID
  1022. ) : m_uNumEntries( 0 ),
  1023. m_pstrTable( NULL )
  1024. {
  1025. }
  1026. /*++
  1027. Name:
  1028. TSubnets
  1029. Description:
  1030. Destructor.
  1031. Arguments:
  1032. None.
  1033. Return Value:
  1034. Nothing.
  1035. Notes:
  1036. --*/
  1037. TPhysicalLocation::TSubnets::
  1038. ~TSubnets(
  1039. VOID
  1040. )
  1041. {
  1042. delete [] m_pstrTable;
  1043. }
  1044. /*++
  1045. Name:
  1046. ClearAll
  1047. Description:
  1048. Release the all the subnet entries.
  1049. Arguments:
  1050. None.
  1051. Return Value:
  1052. Nothing.
  1053. Notes:
  1054. --*/
  1055. VOID
  1056. TPhysicalLocation::TSubnets::
  1057. ClearAll(
  1058. VOID
  1059. )
  1060. {
  1061. m_uNumEntries = 0;
  1062. delete [] m_pstrTable;
  1063. m_pstrTable = NULL;
  1064. }
  1065. /*++
  1066. Name:
  1067. NumEntries
  1068. Description:
  1069. Return the total number of valid entries.
  1070. Arguments:
  1071. None.
  1072. Return Value:
  1073. Number of subnet entries.
  1074. Notes:
  1075. --*/
  1076. UINT
  1077. TPhysicalLocation::TSubnets::
  1078. NumEntries(
  1079. VOID
  1080. )
  1081. {
  1082. return m_uNumEntries;
  1083. }
  1084. /*++
  1085. Name:
  1086. Table
  1087. Description:
  1088. Return the string using the speified index.
  1089. Arguments:
  1090. Index - Zero based index of which string to return.
  1091. Return Value:
  1092. Refrence to string.
  1093. Notes:
  1094. --*/
  1095. TString &
  1096. TPhysicalLocation::TSubnets::
  1097. Table(
  1098. UINT Index
  1099. )
  1100. {
  1101. SPLASSERT( m_pstrTable || Index < m_uNumEntries);
  1102. return m_pstrTable[Index];
  1103. }
  1104. /*++
  1105. Name:
  1106. AddEntry
  1107. Description:
  1108. Add a new subnet entry into the array of subnet strings.
  1109. Arguments:
  1110. pszNew - pointer to new subnet string to add.
  1111. Return Value:
  1112. TRUE new subnet string was added, FALSE error.
  1113. Notes:
  1114. --*/
  1115. BOOL
  1116. TPhysicalLocation::TSubnets::
  1117. AddEntry(
  1118. IN LPCTSTR pszNew
  1119. )
  1120. {
  1121. TStatusB bStatus;
  1122. //
  1123. // Assume failure.
  1124. //
  1125. bStatus DBGNOCHK = FALSE;
  1126. //
  1127. // Allocate the new array of strings. Yes this
  1128. // is not the most efficent code but it works.
  1129. // Maybe a string list would be a better
  1130. // choice if I had one or the time to implement one.
  1131. //
  1132. TString *pTemp = new TString [m_uNumEntries+1];
  1133. if (pTemp)
  1134. {
  1135. //
  1136. // Assume success this is needed when the first
  1137. // string is added.
  1138. //
  1139. bStatus DBGNOCHK = TRUE;
  1140. //
  1141. // Copy the strings to the new array of strings.
  1142. //
  1143. for( UINT i = 0; i < m_uNumEntries; i++ )
  1144. {
  1145. if (!(bStatus DBGCHK = pTemp[i].bUpdate( m_pstrTable[i] )))
  1146. {
  1147. break;
  1148. }
  1149. }
  1150. //
  1151. // Add the new string.
  1152. //
  1153. if (bStatus)
  1154. {
  1155. bStatus DBGCHK = pTemp[i].bUpdate( pszNew );
  1156. if( bStatus )
  1157. {
  1158. delete [] m_pstrTable;
  1159. m_pstrTable = pTemp;
  1160. m_uNumEntries++;
  1161. }
  1162. }
  1163. //
  1164. // If something failed free the temp string array.
  1165. //
  1166. if( !bStatus )
  1167. {
  1168. delete [] pTemp;
  1169. }
  1170. }
  1171. return bStatus;
  1172. }
  1173. /*++
  1174. Name:
  1175. TPhysicalLocation::bLocationEnabled
  1176. Description:
  1177. Checks policy bit to determine if physical location support is enabled
  1178. Arguments:
  1179. None
  1180. Return Value:
  1181. TRUE if enabled, FALSE otherwise
  1182. Notes:
  1183. Support is disabled by default
  1184. --*/
  1185. BOOL
  1186. TPhysicalLocation::
  1187. bLocationEnabled(
  1188. VOID
  1189. )
  1190. {
  1191. TStatusB bStatus;
  1192. BOOL bRet = FALSE;
  1193. TPersist PersistPolicy( gszSpoolerPolicy, TPersist::kOpen|TPersist::kRead, HKEY_LOCAL_MACHINE );
  1194. if( VALID_OBJ( PersistPolicy ) )
  1195. {
  1196. bStatus DBGNOCHK = PersistPolicy.bRead( gszUsePhysicalLocation, bRet );
  1197. }
  1198. return bRet;
  1199. }