Leaked source code of windows server 2003
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.

1673 lines
35 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. //
  574. // Validate that szSubnetName still has enough
  575. // empty slots for this character and '\0'.
  576. //
  577. if (p - szSubnetName + 1 >= ARRAYSIZE(szSubnetName))
  578. {
  579. bStatus DBGCHK = FALSE;
  580. break;
  581. }
  582. *p++ = _T('\\');
  583. }
  584. //
  585. // Validate that szSubnetName still has enough
  586. // empty slots for this character and '\0'.
  587. //
  588. if (p - szSubnetName + 1 >= ARRAYSIZE(szSubnetName))
  589. {
  590. bStatus DBGCHK = FALSE;
  591. break;
  592. }
  593. *p++ = *pszSubnetName++;
  594. }
  595. *p = NULL;
  596. //
  597. // Build the site adsi object path.
  598. //
  599. if (bStatus)
  600. {
  601. bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
  602. strSubnetPath.bCat( strLDAPPrefix ) &&
  603. strSubnetPath.bCat( gszCNEquals ) &&
  604. strSubnetPath.bCat( szSubnetName ) &&
  605. strSubnetPath.bCat( gszComma ) &&
  606. strSubnetPath.bCat( gszSubnetContainter) &&
  607. strSubnetPath.bCat( gszComma ) &&
  608. strSubnetPath.bCat( strConfig );
  609. DBGMSG( DBG_TRACE, ( "Subnet Path " TSTR ".\n", (LPCTSTR)strSubnetPath ) );
  610. }
  611. if (bStatus)
  612. {
  613. //
  614. // Read the site location property.
  615. //
  616. bStatus DBGCHK = m_Ds.ReadStringProperty( strSubnetPath, gszSubnetLocationPropertyName, strSubnetLocation );
  617. }
  618. }
  619. return bStatus;
  620. }
  621. /*++
  622. Name:
  623. GetSiteLocationString
  624. Description:
  625. Reads the location string from the site object. This routine
  626. converts the site name to an adsi path then reads the location
  627. property fron this site object.
  628. Arguments:
  629. pszSiteName - pointer string which contains the site name.
  630. strSiteLocation - reference to string object where to return the site
  631. location string.
  632. Return Value:
  633. TRUE success, FALSE error occurred.
  634. Notes:
  635. --*/
  636. BOOL
  637. TPhysicalLocation::
  638. GetSiteLocationString(
  639. IN LPCTSTR pszSiteName,
  640. IN OUT TString &strSiteLocation
  641. )
  642. {
  643. TString strConfig;
  644. TString strSitePath;
  645. TString strLDAPPrefix;
  646. TStatusB bStatus;
  647. //
  648. // Sites are located in the configuration container.
  649. //
  650. bStatus DBGCHK = m_Ds.GetConfigurationContainer( strConfig );
  651. if (bStatus)
  652. {
  653. //
  654. // Build the site adsi object path.
  655. //
  656. bStatus DBGCHK = m_Ds.GetLDAPPrefix( strLDAPPrefix ) &&
  657. strSitePath.bCat( strLDAPPrefix ) &&
  658. strSitePath.bCat( gszCNEquals ) &&
  659. strSitePath.bCat( pszSiteName ) &&
  660. strSitePath.bCat( gszComma ) &&
  661. strSitePath.bCat( gszSitesContainter) &&
  662. strSitePath.bCat( gszComma ) &&
  663. strSitePath.bCat( strConfig );
  664. DBGMSG( DBG_TRACE, ( "Site Path " TSTR ".\n", (LPCTSTR)strSitePath ) );
  665. if (bStatus)
  666. {
  667. //
  668. // Read the site location property.
  669. //
  670. bStatus DBGCHK = m_Ds.ReadStringProperty( strSitePath, gszSiteLocationPropertyName, strSiteLocation );
  671. }
  672. }
  673. return bStatus;
  674. }
  675. /*++
  676. Name:
  677. TPhysicalLocation::vTrimSlash
  678. Description:
  679. Removes trailing slashes from the given string
  680. Arguments:
  681. strLocation - string to shorten
  682. Return Value:
  683. None
  684. Notes:
  685. --*/
  686. VOID
  687. TPhysicalLocation::
  688. vTrimSlash (
  689. IN OUT TString &strLocation
  690. )
  691. {
  692. UINT uLen;
  693. LPTSTR szTrimSlash;
  694. uLen = strLocation.uLen();
  695. while (uLen && *(static_cast<LPCTSTR>(strLocation)+uLen-1) == gchSeparator)
  696. {
  697. uLen--;
  698. };
  699. if (uLen)
  700. {
  701. szTrimSlash = new TCHAR[uLen+1];
  702. if (szTrimSlash)
  703. {
  704. _tcsncpy (szTrimSlash, strLocation, uLen);
  705. *(szTrimSlash+uLen) = 0;
  706. strLocation.bUpdate (szTrimSlash);
  707. delete [] szTrimSlash;
  708. }
  709. }
  710. else
  711. {
  712. strLocation.bUpdate (gszNULL);
  713. }
  714. }
  715. /*++
  716. Name:
  717. AddrToSite
  718. Description:
  719. Converts a single ip address to a site name.
  720. Arguments:
  721. dwAddr - the IP address.
  722. strSiteName - return the site name here.
  723. strSubnetName - return the subnet name here.
  724. Return Value:
  725. TRUE success, FALSE error occurred.
  726. Notes:
  727. DsAddressToSiteNamesEx only returns the nearest subnet when there are multiple
  728. sites defined in the DS.
  729. --*/
  730. BOOL
  731. TPhysicalLocation::
  732. AddrToSite(
  733. IN DWORD dwAddr,
  734. IN TString &strSiteName,
  735. IN TString &strSubnetName
  736. )
  737. {
  738. DWORD dwStatus = ERROR_SUCCESS;
  739. SOCKET_ADDRESS SockAddr = {0};
  740. SOCKADDR_IN SockAddrIn = {0};
  741. PWSTR *ppSiteNames = NULL;
  742. PWSTR *ppSubnetNames = NULL;
  743. TStatusB bStatus;
  744. //
  745. // Create a socket from an IP address.
  746. //
  747. SockAddr.iSockaddrLength = sizeof(SOCKADDR_IN);
  748. SockAddr.lpSockaddr = (LPSOCKADDR)&SockAddrIn;
  749. SockAddrIn.sin_family = AF_INET;
  750. SockAddrIn.sin_port = 0;
  751. memcpy( &SockAddrIn.sin_addr, &dwAddr, sizeof(dwAddr) );
  752. //
  753. // If a no zero address was given then attempt to find a site
  754. // that this address belongs to.
  755. //
  756. if (dwAddr)
  757. {
  758. dwStatus = m_DsAddressToSiteNames( NULL, 1, &SockAddr, &ppSiteNames, &ppSubnetNames );
  759. if (dwStatus == ERROR_SUCCESS)
  760. {
  761. if (ppSiteNames)
  762. {
  763. DBGMSG( DBG_TRACE, ( "SiteName " TSTR "\n", DBGSTR( ppSiteNames[0] ) ) );
  764. bStatus DBGCHK = strSiteName.bUpdate( ppSiteNames[0] );
  765. m_NetApiBufferFree( ppSiteNames );
  766. }
  767. if (ppSubnetNames)
  768. {
  769. DBGMSG( DBG_TRACE, ( "SubnetName " TSTR "\n", DBGSTR( ppSubnetNames[0] ) ) );
  770. bStatus DBGCHK = strSubnetName.bUpdate( ppSubnetNames[0] );
  771. m_NetApiBufferFree( ppSubnetNames );
  772. }
  773. }
  774. }
  775. return dwStatus == ERROR_SUCCESS;
  776. }
  777. /*++
  778. Name:
  779. GetIpAddressTable
  780. Description:
  781. Returns an array of Ip address for this machine. The caller
  782. must free the array using the delete operator.
  783. Arguments:
  784. ppAddrTable - Pointer were to return a pointer to the array of
  785. ip addresses.
  786. Return Value:
  787. TRUE success, FALSE error occurred.
  788. Notes:
  789. --*/
  790. BOOL
  791. TPhysicalLocation::
  792. GetIpAddressTable(
  793. PMIB_IPADDRTABLE *ppAddrTable
  794. )
  795. {
  796. SPLASSERT( ppAddrTable );
  797. DWORD dwTableSize = 0;
  798. PMIB_IPADDRTABLE pAddrTable = NULL;
  799. DWORD dwStatus = ERROR_SUCCESS;
  800. BOOL bRet = FALSE;
  801. dwStatus = m_GetIpAddrTable(NULL, &dwTableSize, FALSE);
  802. if (dwStatus == ERROR_INSUFFICIENT_BUFFER)
  803. {
  804. pAddrTable = (PMIB_IPADDRTABLE)new BYTE[dwTableSize];
  805. if (pAddrTable)
  806. {
  807. dwStatus = m_GetIpAddrTable(pAddrTable, &dwTableSize, FALSE);
  808. if (dwStatus == ERROR_SUCCESS)
  809. {
  810. *ppAddrTable = pAddrTable;
  811. bRet = TRUE;
  812. }
  813. else
  814. {
  815. delete [] pAddrTable;
  816. }
  817. }
  818. else
  819. {
  820. // new has failed
  821. SetLastError(ERROR_OUTOFMEMORY);
  822. }
  823. }
  824. return bRet;
  825. }
  826. /*++
  827. Name:
  828. GetSubnetObjectNames
  829. Description:
  830. Returns a list of subnet objects for this machine. Since the machine
  831. may have multiple ip address the same goes for the subnets.
  832. Arguments:
  833. Subnets - Refrence to subnet Class that will contain on return a
  834. list of subnet objects.
  835. Return Value:
  836. TRUE subnet object returned, FALSE error occurred.
  837. Notes:
  838. --*/
  839. BOOL
  840. TPhysicalLocation::
  841. GetSubnetObjectNames(
  842. IN TSubnets &Subnets
  843. )
  844. {
  845. TString strConfig;
  846. TStatusB bStatus;
  847. //
  848. // Get the path to the configuration container.
  849. //
  850. bStatus DBGCHK = m_Ds.GetConfigurationContainer( strConfig );
  851. if (bStatus)
  852. {
  853. TSubnets Subnets2;
  854. TString strSubnetObject;
  855. //
  856. // Get the subnet names.
  857. //
  858. bStatus DBGCHK = GetSubnetNames( Subnets2 );
  859. //
  860. // Transform the subnet names into subnet object names.
  861. //
  862. for( UINT i = 0; i < Subnets2.NumEntries(); i++ )
  863. {
  864. bStatus DBGCHK = strSubnetObject.bUpdate( gszCNEquals ) &&
  865. strSubnetObject.bCat( Subnets2.Table(i) ) &&
  866. strSubnetObject.bCat( gszComma ) &&
  867. strSubnetObject.bCat( gszSubnetContainter ) &&
  868. strSubnetObject.bCat( gszComma ) &&
  869. strSubnetObject.bCat( strConfig );
  870. if (bStatus)
  871. {
  872. DBGMSG( DBG_TRACE, ( "SubnetObject " TSTR ".\n", (LPCTSTR)strSubnetObject ) );
  873. //
  874. // Add the subnet object entry.
  875. //
  876. if (!(bStatus DBGCHK = Subnets.AddEntry( strSubnetObject )))
  877. {
  878. break;
  879. }
  880. }
  881. }
  882. }
  883. return bStatus;
  884. }
  885. /*++
  886. Name:
  887. GetSubnetNames
  888. Description:
  889. Return a list of subnet strings for this machine, a machine may
  890. be on multiple subnet since they may have multiple ip addresses.
  891. Arguments:
  892. TSubnet & - refrence to class of Subnets.
  893. Return Value:
  894. TRUE subnets were returned, FALSE error occurred.
  895. Notes:
  896. --*/
  897. BOOL
  898. TPhysicalLocation::
  899. GetSubnetNames(
  900. IN TSubnets &Subnets
  901. )
  902. {
  903. TStatusB bStatus;
  904. PMIB_IPADDRTABLE pAddrTable = NULL;
  905. TString strSubnet;
  906. Subnets.ClearAll();
  907. bStatus DBGCHK = GetIpAddressTable( &pAddrTable );
  908. if (bStatus && pAddrTable )
  909. {
  910. for (UINT i = 0; i < pAddrTable->dwNumEntries; i++)
  911. {
  912. //
  913. // Skip the loopback or unassigned interfaces
  914. //
  915. if((pAddrTable->table[i].dwAddr != 0) && (pAddrTable->table[i].dwAddr != c_LoopBackAddress.s_addr))
  916. {
  917. IN_ADDR IpSubnetAddr;
  918. IpSubnetAddr.s_addr = pAddrTable->table[i].dwAddr & pAddrTable->table[i].dwMask;
  919. LPSTR pszIpAddress = m_inet_ntoa( IpSubnetAddr );
  920. //
  921. // Format the subnet mask to match the way subnet objects are
  922. // in the DS. XX.XX.XX.XX/SS where SS are the number of significant
  923. // bit in the subnet mask.
  924. //
  925. bStatus DBGCHK = strSubnet.bFormat( _T("%S\\/%d"),
  926. pszIpAddress ? pszIpAddress : "",
  927. NumSetBits( pAddrTable->table[i].dwMask ) );
  928. if (bStatus)
  929. {
  930. //
  931. // Add the subnet entry to the list of subnets.
  932. //
  933. bStatus DBGCHK = Subnets.AddEntry( strSubnet );
  934. }
  935. }
  936. }
  937. }
  938. delete [] pAddrTable;
  939. return bStatus;
  940. }
  941. /*++
  942. Name:
  943. WidenScope
  944. Description:
  945. This routine expands the scope of the specified physical location string.
  946. The physical location string uses / as scope separators. For example
  947. if the physical location string on a computer object is
  948. "/Redmond/Main Campus/Building 26 North/Floor 1/Office 1438"
  949. after calling this routine with a count of 1 the new physical location
  950. string will be "/Redmond/Main Campus/Building 26 North/Floor 1"
  951. Thus it has expanded the scope this computer object is in.
  952. Arguments:
  953. pszString - pointer to physical location string to widen
  954. uCount - number of scopes to widen the scope by, must be 1 or greater
  955. strString - refrence to string object where to return the new widened scope.
  956. Return Value:
  957. TRUE the scope was widened, FALSE error occurred.
  958. Notes:
  959. --*/
  960. BOOL
  961. TPhysicalLocation::
  962. WidenScope(
  963. IN LPCTSTR pszString,
  964. IN UINT uCount,
  965. IN OUT TString &strString
  966. ) const
  967. {
  968. TStatusB bStatus;
  969. bStatus DBGNOCHK = FALSE;
  970. if (uCount && pszString && *pszString)
  971. {
  972. UINT uLen = _tcslen( pszString );
  973. LPTSTR pszTemp = new TCHAR [uLen+1];
  974. if (pszTemp)
  975. {
  976. StringCchCopy( pszTemp, uLen+1, pszString );
  977. //
  978. // Search from the end of the string to the beginning
  979. // counting the number of separators, terminate when the
  980. // desired count is reached.
  981. //
  982. for( LPTSTR p = pszTemp + uLen - 1; p != pszTemp; p-- )
  983. {
  984. if (*p == gchSeparator)
  985. {
  986. if (!--uCount)
  987. {
  988. *p = NULL;
  989. bStatus DBGCHK = strString.bUpdate( pszTemp );
  990. break;
  991. }
  992. }
  993. }
  994. }
  995. delete [] pszTemp;
  996. }
  997. return bStatus;
  998. }
  999. /*++
  1000. Name:
  1001. NumSetBits
  1002. Description:
  1003. Determines the number of set bits in the specified value.
  1004. Arguments:
  1005. DWORD Value - Value to count set bits.
  1006. Return Value:
  1007. Number of set bits in the value.
  1008. Notes:
  1009. --*/
  1010. UINT
  1011. TPhysicalLocation::
  1012. NumSetBits(
  1013. IN DWORD Value
  1014. )
  1015. {
  1016. UINT Count = 0;
  1017. //
  1018. // Start with the high order bit set and shift the bit
  1019. // to the right. This routine could be made very generic
  1020. // if a pointer to the value and the size in bytes of the
  1021. // value was accepted.
  1022. //
  1023. for( DWORD i = 1 << ( sizeof(Value) * 8 - 1 ); i; i >>= 1 )
  1024. {
  1025. Count += (Value & i) ? 1 : 0;
  1026. }
  1027. return Count;
  1028. }
  1029. /*++
  1030. Name:
  1031. TSubnets
  1032. Description:
  1033. Constructor.
  1034. Arguments:
  1035. None.
  1036. Return Value:
  1037. Nothing.
  1038. Notes:
  1039. --*/
  1040. TPhysicalLocation::TSubnets::
  1041. TSubnets(
  1042. VOID
  1043. ) : m_uNumEntries( 0 ),
  1044. m_pstrTable( NULL )
  1045. {
  1046. }
  1047. /*++
  1048. Name:
  1049. TSubnets
  1050. Description:
  1051. Destructor.
  1052. Arguments:
  1053. None.
  1054. Return Value:
  1055. Nothing.
  1056. Notes:
  1057. --*/
  1058. TPhysicalLocation::TSubnets::
  1059. ~TSubnets(
  1060. VOID
  1061. )
  1062. {
  1063. delete [] m_pstrTable;
  1064. }
  1065. /*++
  1066. Name:
  1067. ClearAll
  1068. Description:
  1069. Release the all the subnet entries.
  1070. Arguments:
  1071. None.
  1072. Return Value:
  1073. Nothing.
  1074. Notes:
  1075. --*/
  1076. VOID
  1077. TPhysicalLocation::TSubnets::
  1078. ClearAll(
  1079. VOID
  1080. )
  1081. {
  1082. m_uNumEntries = 0;
  1083. delete [] m_pstrTable;
  1084. m_pstrTable = NULL;
  1085. }
  1086. /*++
  1087. Name:
  1088. NumEntries
  1089. Description:
  1090. Return the total number of valid entries.
  1091. Arguments:
  1092. None.
  1093. Return Value:
  1094. Number of subnet entries.
  1095. Notes:
  1096. --*/
  1097. UINT
  1098. TPhysicalLocation::TSubnets::
  1099. NumEntries(
  1100. VOID
  1101. )
  1102. {
  1103. return m_uNumEntries;
  1104. }
  1105. /*++
  1106. Name:
  1107. Table
  1108. Description:
  1109. Return the string using the speified index.
  1110. Arguments:
  1111. Index - Zero based index of which string to return.
  1112. Return Value:
  1113. Refrence to string.
  1114. Notes:
  1115. --*/
  1116. TString &
  1117. TPhysicalLocation::TSubnets::
  1118. Table(
  1119. UINT Index
  1120. )
  1121. {
  1122. SPLASSERT( m_pstrTable || Index < m_uNumEntries);
  1123. return m_pstrTable[Index];
  1124. }
  1125. /*++
  1126. Name:
  1127. AddEntry
  1128. Description:
  1129. Add a new subnet entry into the array of subnet strings.
  1130. Arguments:
  1131. pszNew - pointer to new subnet string to add.
  1132. Return Value:
  1133. TRUE new subnet string was added, FALSE error.
  1134. Notes:
  1135. --*/
  1136. BOOL
  1137. TPhysicalLocation::TSubnets::
  1138. AddEntry(
  1139. IN LPCTSTR pszNew
  1140. )
  1141. {
  1142. TStatusB bStatus;
  1143. //
  1144. // Assume failure.
  1145. //
  1146. bStatus DBGNOCHK = FALSE;
  1147. //
  1148. // Allocate the new array of strings. Yes this
  1149. // is not the most efficent code but it works.
  1150. // Maybe a string list would be a better
  1151. // choice if I had one or the time to implement one.
  1152. //
  1153. TString *pTemp = new TString [m_uNumEntries+1];
  1154. if (pTemp)
  1155. {
  1156. //
  1157. // Assume success this is needed when the first
  1158. // string is added.
  1159. //
  1160. bStatus DBGNOCHK = TRUE;
  1161. //
  1162. // Copy the strings to the new array of strings.
  1163. //
  1164. for( UINT i = 0; i < m_uNumEntries; i++ )
  1165. {
  1166. if (!(bStatus DBGCHK = pTemp[i].bUpdate( m_pstrTable[i] )))
  1167. {
  1168. break;
  1169. }
  1170. }
  1171. //
  1172. // Add the new string.
  1173. //
  1174. if (bStatus)
  1175. {
  1176. bStatus DBGCHK = pTemp[i].bUpdate( pszNew );
  1177. if( bStatus )
  1178. {
  1179. delete [] m_pstrTable;
  1180. m_pstrTable = pTemp;
  1181. m_uNumEntries++;
  1182. }
  1183. }
  1184. //
  1185. // If something failed free the temp string array.
  1186. //
  1187. if( !bStatus )
  1188. {
  1189. delete [] pTemp;
  1190. }
  1191. }
  1192. return bStatus;
  1193. }
  1194. /*++
  1195. Name:
  1196. TPhysicalLocation::bLocationEnabled
  1197. Description:
  1198. Checks policy bit to determine if physical location support is enabled
  1199. Arguments:
  1200. None
  1201. Return Value:
  1202. TRUE if enabled, FALSE otherwise
  1203. Notes:
  1204. Support is disabled by default
  1205. --*/
  1206. BOOL
  1207. TPhysicalLocation::
  1208. bLocationEnabled(
  1209. VOID
  1210. )
  1211. {
  1212. TStatusB bStatus;
  1213. BOOL bRet = FALSE;
  1214. TPersist PersistPolicy( gszSpoolerPolicy, TPersist::kOpen|TPersist::kRead, HKEY_LOCAL_MACHINE );
  1215. if( VALID_OBJ( PersistPolicy ) )
  1216. {
  1217. bStatus DBGNOCHK = PersistPolicy.bRead( gszUsePhysicalLocation, bRet );
  1218. }
  1219. return bRet;
  1220. }