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.

934 lines
19 KiB

  1. // Copyright (c) 2001 Microsoft Corporation
  2. //
  3. // File: state.cpp
  4. //
  5. // Synopsis: Defines the state object that is global
  6. // to CYS. It holds the network and OS/SKU info
  7. //
  8. // History: 02/02/2001 JeffJon Created
  9. #include "pch.h"
  10. #include "state.h"
  11. #include "cys.h"
  12. static State* stateInstance = 0;
  13. State::State() :
  14. dhcpServerAvailableOnAllNics(true),
  15. dhcpAvailabilityRetrieved(false),
  16. hasStateBeenRetrieved(false),
  17. rerunWizard(true),
  18. isRebootScenario(false),
  19. productSKU(CYS_SERVER),
  20. hasNTFSDrive(false),
  21. localComputer(),
  22. computerName(),
  23. domainDNSName(),
  24. domainNetbiosName(),
  25. wizardStartPage(0)
  26. {
  27. LOG_CTOR(State);
  28. HRESULT unused = localComputer.Refresh();
  29. ASSERT(SUCCEEDED(unused));
  30. RetrievePlatform();
  31. }
  32. void
  33. State::Destroy()
  34. {
  35. LOG_FUNCTION(State::Destroy);
  36. if (stateInstance)
  37. {
  38. delete stateInstance;
  39. stateInstance = 0;
  40. }
  41. }
  42. State&
  43. State::GetInstance()
  44. {
  45. if (!stateInstance)
  46. {
  47. stateInstance = new State();
  48. }
  49. ASSERT(stateInstance);
  50. return *stateInstance;
  51. }
  52. bool
  53. State::IsRemoteSession() const
  54. {
  55. LOG_FUNCTION(State::IsRemoteSession);
  56. bool result =
  57. Win::GetSystemMetrics(SM_REMOTESESSION) ?
  58. true : false;
  59. LOG_BOOL(result);
  60. return result;
  61. }
  62. bool
  63. State::IsWindowsSetupRunning() const
  64. {
  65. LOG_FUNCTION(State::IsWindowsSetupRunning);
  66. bool result = false;
  67. // Try to create a mutex for the default
  68. // sysoc inf file. If it already exists
  69. // then we know SYSOCMGR is running
  70. static const String mutexName = L"Global\\sysoc";
  71. HANDLE mutexHandle = INVALID_HANDLE_VALUE;
  72. HRESULT hr =
  73. Win::CreateMutex(
  74. 0,
  75. true,
  76. mutexName,
  77. mutexHandle);
  78. if (hr == Win32ToHresult(ERROR_ALREADY_EXISTS))
  79. {
  80. // SysOCMGR is running
  81. result = true;
  82. }
  83. if (mutexHandle != INVALID_HANDLE_VALUE)
  84. {
  85. // Close the handle
  86. Win::CloseHandle(mutexHandle);
  87. }
  88. LOG_BOOL(result);
  89. return result;
  90. }
  91. bool
  92. State::IsDC() const
  93. {
  94. LOG_FUNCTION(State::IsDC);
  95. bool result = localComputer.IsDomainController();
  96. LOG_BOOL(result);
  97. return result;
  98. }
  99. bool
  100. State::IsDCPromoRunning() const
  101. {
  102. LOG_FUNCTION(State::IsDCPromoRunning);
  103. // Uses the IsDcpromoRunning from Burnslib
  104. bool result = IsDcpromoRunning();
  105. LOG_BOOL(result);
  106. return result;
  107. }
  108. bool
  109. State::IsDCPromoPendingReboot() const
  110. {
  111. LOG_FUNCTION(State::IsDCPromoPendingReboot);
  112. bool result = false;
  113. do
  114. {
  115. // Uses the IsDcpromoRunning from Burnslib
  116. if (!IsDcpromoRunning())
  117. {
  118. // this test is redundant if dcpromo is running, so only
  119. // perform it when dcpromo is not running.
  120. DSROLE_OPERATION_STATE_INFO* info = 0;
  121. HRESULT hr = MyDsRoleGetPrimaryDomainInformation(0, info);
  122. if (SUCCEEDED(hr) && info)
  123. {
  124. if (info->OperationState == DsRoleOperationNeedReboot)
  125. {
  126. result = true;
  127. }
  128. ::DsRoleFreeMemory(info);
  129. }
  130. }
  131. } while (false);
  132. LOG_BOOL(result);
  133. return result;
  134. }
  135. bool
  136. State::IsJoinedToDomain() const
  137. {
  138. LOG_FUNCTION(State::IsJoinedToDomain);
  139. bool result = localComputer.IsJoinedToDomain();
  140. LOG_BOOL(result);
  141. return result;
  142. }
  143. bool
  144. State::IsUpgradeState() const
  145. {
  146. LOG_FUNCTION(State::IsUpgradeState);
  147. bool result = false;
  148. do
  149. {
  150. DSROLE_UPGRADE_STATUS_INFO* info = 0;
  151. HRESULT hr = MyDsRoleGetPrimaryDomainInformation(0, info);
  152. if (FAILED(hr))
  153. {
  154. LOG(String::format(
  155. L"MyDsRoleGetPrimaryDomainInformation(0): hr = 0x%1!x!",
  156. hr));
  157. break;
  158. }
  159. if (info && info->OperationState == DSROLE_UPGRADE_IN_PROGRESS)
  160. {
  161. result = true;
  162. }
  163. ::DsRoleFreeMemory(info);
  164. } while (false);
  165. LOG_BOOL(result);
  166. return result;
  167. }
  168. bool
  169. State::IsFirstDC() const
  170. {
  171. LOG_FUNCTION(State::IsFirstDC);
  172. DWORD value = 0;
  173. bool result = GetRegKeyValue(CYS_FIRST_DC_REGKEY, CYS_FIRST_DC_VALUE, value);
  174. if (value != 1)
  175. {
  176. result = false;
  177. }
  178. LOG_BOOL(result);
  179. return result;
  180. }
  181. unsigned int
  182. State::GetNICCount() const
  183. {
  184. return adapterConfiguration.GetNICCount();
  185. }
  186. unsigned int
  187. State::GetNonModemNICCount()
  188. {
  189. unsigned int result = 0;
  190. for (
  191. unsigned int index = 0;
  192. index < GetNICCount();
  193. ++index)
  194. {
  195. NetworkInterface* nic = GetNIC(index);
  196. if (nic &&
  197. !nic->IsModem())
  198. {
  199. ++result;
  200. }
  201. }
  202. LOG(
  203. String::format(
  204. L"Non-modem NIC count: %1!d!",
  205. result));
  206. return result;
  207. }
  208. NetworkInterface*
  209. State::GetNIC(unsigned int nicIndex)
  210. {
  211. LOG_FUNCTION2(
  212. State::GetNIC,
  213. String::format(
  214. L"%1!d!",
  215. nicIndex));
  216. return adapterConfiguration.GetNIC(nicIndex);
  217. }
  218. NetworkInterface*
  219. State::GetNICFromName(const String& name, bool& found)
  220. {
  221. LOG_FUNCTION2(
  222. State::GetNICFromName,
  223. name.c_str());
  224. return adapterConfiguration.GetNICFromName(name, found);
  225. }
  226. NetworkInterface*
  227. State::GetLocalNICFromRegistry()
  228. {
  229. LOG_FUNCTION(State::GetLocalNICFromRegistry);
  230. // Read the local NIC GUID from the registry
  231. String nicName;
  232. NetworkInterface* nic = 0;
  233. if (!GetRegKeyValue(
  234. CYS_FIRST_DC_REGKEY,
  235. CYS_FIRST_DC_LOCAL_NIC,
  236. nicName))
  237. {
  238. LOG(L"Failed to read LocalNIC regkey, using default local NIC");
  239. nic = State::GetInstance().GetLocalNIC();
  240. if (nic)
  241. {
  242. nicName = nic->GetName();
  243. }
  244. }
  245. SetLocalNIC(nicName, false);
  246. if (!nic)
  247. {
  248. nic = GetLocalNIC();
  249. }
  250. return nic;
  251. }
  252. bool
  253. State::RetrieveMachineConfigurationInformation(
  254. HWND progressStatic,
  255. bool doDHCPCheck,
  256. int nicInfoResID,
  257. int osInfoResID,
  258. int defaultConnectionResID,
  259. int detectSettingsResID)
  260. {
  261. LOG_FUNCTION(State::RetrieveMachineConfigurationInformation);
  262. ASSERT(!hasStateBeenRetrieved);
  263. // This is used to get the minimal information needed to
  264. // determine if we should enable the express path
  265. // This should probably just be changed to gather the
  266. // information and let the page decide what to do
  267. if (progressStatic)
  268. {
  269. Win::SetWindowText(
  270. progressStatic,
  271. String::load(nicInfoResID));
  272. }
  273. HRESULT hr = RetrieveNICInformation();
  274. if (SUCCEEDED(hr))
  275. {
  276. // Only bother to check for a DHCP server on the network if we are not
  277. // a DC, not a DNS server, not a DHCP server and have at least one NIC.
  278. // Right now we only use this info for determining whether or not to
  279. // show the Express path option
  280. if (!(IsDC() || IsUpgradeState()) &&
  281. (GetNICCount() > 0) &&
  282. doDHCPCheck)
  283. {
  284. CheckDhcpServer(
  285. progressStatic,
  286. defaultConnectionResID,
  287. detectSettingsResID);
  288. }
  289. }
  290. if (progressStatic)
  291. {
  292. Win::SetWindowText(
  293. progressStatic,
  294. String::load(osInfoResID));
  295. }
  296. RetrieveProductSKU();
  297. RetrievePlatform();
  298. // Retrieve the drive information (quotas enabled, partition types, etc.)
  299. RetrieveDriveInformation();
  300. hasStateBeenRetrieved = true;
  301. return true;
  302. }
  303. DWORD
  304. State::RetrieveProductSKU()
  305. {
  306. LOG_FUNCTION(State::RetrieveProductSKU);
  307. // I am making the assumption that we are on a
  308. // Server SKU if GetVersionEx fails
  309. productSKU = CYS_UNSUPPORTED_SKU;
  310. OSVERSIONINFOEX info;
  311. HRESULT hr = Win::GetVersionEx(info);
  312. if (SUCCEEDED(hr))
  313. {
  314. LOG(String::format(
  315. L"wSuiteMask = 0x%1!x!",
  316. info.wSuiteMask));
  317. LOG(String::format(
  318. L"wProductType = 0x%1!x!",
  319. info.wProductType));
  320. do
  321. {
  322. if (info.wProductType == VER_NT_SERVER ||
  323. info.wProductType == VER_NT_DOMAIN_CONTROLLER)
  324. {
  325. if (info.wSuiteMask & VER_SUITE_DATACENTER)
  326. {
  327. // datacenter
  328. productSKU = CYS_DATACENTER_SERVER;
  329. break;
  330. }
  331. else if (info.wSuiteMask & VER_SUITE_ENTERPRISE)
  332. {
  333. // advanced server
  334. productSKU = CYS_ADVANCED_SERVER;
  335. break;
  336. }
  337. else if (info.wSuiteMask & VER_SUITE_SMALLBUSINESS ||
  338. info.wSuiteMask & VER_SUITE_BACKOFFICE ||
  339. info.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED ||
  340. info.wSuiteMask & VER_SUITE_EMBEDDEDNT ||
  341. info.wSuiteMask & VER_SUITE_BLADE)
  342. {
  343. // Unsupported server
  344. productSKU = CYS_UNSUPPORTED_SKU;
  345. break;
  346. }
  347. else
  348. {
  349. // default to standard server
  350. productSKU = CYS_SERVER;
  351. }
  352. break;
  353. }
  354. // All other SKUs are unsupported
  355. productSKU = CYS_UNSUPPORTED_SKU;
  356. } while (false);
  357. }
  358. LOG(String::format(L"Product SKU = 0x%1!x!", productSKU ));
  359. return productSKU;
  360. }
  361. void
  362. State::RetrievePlatform()
  363. {
  364. LOG_FUNCTION(State::RetrievePlatform);
  365. // I am making the assumption that we are not on a
  366. // 64bit machine if GetSystemInfo fails
  367. SYSTEM_INFO info;
  368. Win::GetSystemInfo(info);
  369. switch (info.wProcessorArchitecture)
  370. {
  371. case PROCESSOR_ARCHITECTURE_IA64:
  372. case PROCESSOR_ARCHITECTURE_AMD64:
  373. platform = CYS_64BIT;
  374. break;
  375. default:
  376. platform = CYS_32BIT;
  377. break;
  378. }
  379. LOG(String::format(L"Platform = 0x%1!x!", platform));
  380. return;
  381. }
  382. HRESULT
  383. State::RetrieveNICInformation()
  384. {
  385. ASSERT(!hasStateBeenRetrieved);
  386. HRESULT hr = S_OK;
  387. if (!adapterConfiguration.IsInitialized())
  388. {
  389. hr = adapterConfiguration.Initialize();
  390. }
  391. LOG_HRESULT(hr);
  392. return hr;
  393. }
  394. void
  395. State::CheckDhcpServer(
  396. HWND progressStatic,
  397. int defaultConnectionNameResID,
  398. int detectSettingsResID)
  399. {
  400. LOG_FUNCTION(State::CheckDhcpServer);
  401. // This should loop through all network interfaces
  402. // seeing if we can obtain a lease on any of them
  403. for (unsigned int idx = 0; idx < GetNICCount(); ++idx)
  404. {
  405. NetworkInterface* nic = GetNIC(idx);
  406. if (!nic)
  407. {
  408. continue;
  409. }
  410. // Update the text on the NetDetectProgressDialog
  411. String progress =
  412. String::format(
  413. detectSettingsResID,
  414. nic->GetFriendlyName(
  415. String::load(defaultConnectionNameResID)).c_str());
  416. if (progressStatic)
  417. {
  418. Win::SetWindowText(progressStatic, progress);
  419. }
  420. // Now try to renew the lease
  421. if (!nic->CanDetectDHCPServer())
  422. {
  423. dhcpServerAvailableOnAllNics = false;
  424. // Don't break because we need to retrieve the
  425. // avialability of a DHCP server on all NICs
  426. }
  427. }
  428. dhcpAvailabilityRetrieved = true;
  429. LOG_BOOL(dhcpServerAvailableOnAllNics);
  430. }
  431. bool
  432. State::HasNTFSDrive() const
  433. {
  434. LOG_FUNCTION(State::HasNTFSDrive);
  435. return hasNTFSDrive;
  436. }
  437. void
  438. State::RetrieveDriveInformation()
  439. {
  440. LOG_FUNCTION(State::RetrieveDriveInformation);
  441. do
  442. {
  443. // Get a list of the valid drives
  444. StringVector dl;
  445. HRESULT hr = FS::GetValidDrives(std::back_inserter(dl));
  446. if (FAILED(hr))
  447. {
  448. LOG(String::format(L"Failed to GetValidDrives: hr = %1!x!", hr));
  449. break;
  450. }
  451. // Loop through the list
  452. ASSERT(dl.size());
  453. for (
  454. StringVector::iterator i = dl.begin();
  455. i != dl.end();
  456. ++i)
  457. {
  458. // look for the NTFS partition
  459. FS::FSType fsType = FS::GetFileSystemType(*i);
  460. if (fsType == FS::NTFS5 ||
  461. fsType == FS::NTFS4)
  462. {
  463. // found one. good to go
  464. LOG(String::format(L"%1 is NTFS", i->c_str()));
  465. hasNTFSDrive = true;
  466. break;
  467. }
  468. }
  469. } while (false);
  470. LOG_BOOL(hasNTFSDrive);
  471. return;
  472. }
  473. /*
  474. void
  475. State::SetRerunWizard(bool rerun)
  476. {
  477. LOG_FUNCTION2(
  478. State::SetRerunWizard,
  479. rerun ? L"true" : L"false");
  480. rerunWizard = rerun;
  481. }
  482. */
  483. bool
  484. State::SetHomeRegkey(const String& newKeyValue)
  485. {
  486. LOG_FUNCTION2(
  487. State::SetHomeRegkey,
  488. newKeyValue);
  489. bool result = SetRegKeyValue(
  490. CYS_HOME_REGKEY,
  491. CYS_HOME_VALUE,
  492. newKeyValue,
  493. HKEY_LOCAL_MACHINE,
  494. true);
  495. ASSERT(result);
  496. LOG_BOOL(result);
  497. return result;
  498. }
  499. bool
  500. State::GetHomeRegkey(String& keyValue) const
  501. {
  502. LOG_FUNCTION(State::GetHomeRegkey);
  503. bool result = GetRegKeyValue(
  504. CYS_HOME_REGKEY,
  505. CYS_HOME_VALUE,
  506. keyValue);
  507. LOG_BOOL(result);
  508. return result;
  509. }
  510. String
  511. State::GetComputerName()
  512. {
  513. LOG_FUNCTION(State::GetComputerName);
  514. if (computerName.empty())
  515. {
  516. computerName = Win::GetComputerNameEx(ComputerNameDnsHostname);
  517. }
  518. LOG(computerName);
  519. return computerName;
  520. }
  521. String
  522. State::GetDomainDNSName()
  523. {
  524. LOG_FUNCTION(State::GetDomainDNSName);
  525. if (domainDNSName.empty())
  526. {
  527. domainDNSName = localComputer.GetDomainDnsName();
  528. }
  529. LOG(domainDNSName);
  530. return domainDNSName;
  531. }
  532. String
  533. State::GetDomainNetbiosName()
  534. {
  535. LOG_FUNCTION(State::GetDomainNetbiosName);
  536. if (domainNetbiosName.empty())
  537. {
  538. domainNetbiosName = localComputer.GetDomainNetbiosName();
  539. }
  540. LOG(domainNetbiosName);
  541. return domainNetbiosName;
  542. }
  543. bool
  544. State::HasDNSServerOnAnyNicToForwardTo()
  545. {
  546. LOG_FUNCTION(State::HasDNSServerOnAnyNicToForwardTo);
  547. // A valid DNS server is considered to be any DNS
  548. // server defined on any NIC that does not point
  549. // to itself for resolution. The reason I consider
  550. // a DNS server that points to itself as invalid is
  551. // because this routine is used to determine if the
  552. // DNS server can be used as a forwarder. Since DNS
  553. // servers cannot forward to themselves I consider
  554. // this an invalid DNS server.
  555. // Also consider the "next available" IP address to
  556. // be invalid because chances are the "next available"
  557. // IP address will be used as the static IP address
  558. // of this server in the express path.
  559. bool result = false;
  560. DWORD nextAvailableAddress =
  561. GetNextAvailableIPAddress(
  562. CYS_DEFAULT_IPADDRESS,
  563. CYS_DEFAULT_SUBNETMASK);
  564. for (unsigned int idx = 0; idx < GetNICCount(); ++idx)
  565. {
  566. IPAddressList dnsServers;
  567. NetworkInterface* nic = GetNIC(idx);
  568. if (!nic)
  569. {
  570. continue;
  571. }
  572. nic->GetDNSServers(dnsServers);
  573. if (dnsServers.empty())
  574. {
  575. continue;
  576. }
  577. // Only return true if there is a DNS server in the list
  578. // and the IP address is not the local machine
  579. DWORD ipaddress = nic->GetIPAddress(0);
  580. for (IPAddressList::iterator itr = dnsServers.begin();
  581. itr != dnsServers.end();
  582. ++itr)
  583. {
  584. DWORD currentServer = *itr;
  585. if (ipaddress != currentServer &&
  586. ipaddress != nextAvailableAddress)
  587. {
  588. LOG(String::format(
  589. L"Found valid server: %1",
  590. IPAddressToString(currentServer).c_str()));
  591. result = true;
  592. break;
  593. }
  594. }
  595. if (result)
  596. {
  597. break;
  598. }
  599. }
  600. LOG_BOOL(result);
  601. return result;
  602. }
  603. void
  604. State::SetLocalNIC(
  605. String guid,
  606. bool setInRegistry)
  607. {
  608. LOG_FUNCTION2(
  609. State::SetLocalNIC,
  610. guid.c_str());
  611. LOG_BOOL(setInRegistry);
  612. adapterConfiguration.SetLocalNIC(guid, setInRegistry);
  613. }
  614. NetworkInterface*
  615. State::GetLocalNIC()
  616. {
  617. LOG_FUNCTION(State::GetLocalNIC);
  618. return adapterConfiguration.GetLocalNIC();
  619. }
  620. bool
  621. State::IsRebootScenario() const
  622. {
  623. LOG_FUNCTION(State::IsRebootScenario);
  624. LOG_BOOL(isRebootScenario);
  625. return isRebootScenario;
  626. }
  627. void
  628. State::SetRebootScenario(bool reboot)
  629. {
  630. LOG_FUNCTION(State::SetRebootScenario);
  631. LOG_BOOL(reboot);
  632. isRebootScenario = reboot;
  633. }
  634. bool
  635. State::ShouldRunMYS() const
  636. {
  637. LOG_FUNCTION(State::ShouldRunMYS);
  638. bool result = false;
  639. do
  640. {
  641. // First check to be sure this is a supported SKU
  642. if (!::IsSupportedSku())
  643. {
  644. break;
  645. }
  646. // Now check the startup flags
  647. if (!::IsStartupFlagSet())
  648. {
  649. break;
  650. }
  651. // Check the policy setting
  652. if (!::ShouldShowMYSAccordingToPolicy())
  653. {
  654. // The policy is enabled so that means don't show MYS
  655. break;
  656. }
  657. // everything passed so we should run MYS
  658. result = true;
  659. } while (false);
  660. LOG_BOOL(result);
  661. return result;
  662. }
  663. DWORD
  664. State::GetNextAvailableIPAddress(
  665. DWORD startAddress,
  666. DWORD subnetMask)
  667. {
  668. LOG_FUNCTION2(
  669. State::GetNextAvailableIPAddress,
  670. IPAddressToString(startAddress));
  671. DWORD result = startAddress;
  672. DWORD currentAddress = startAddress;
  673. bool isIPInUse = false;
  674. do
  675. {
  676. isIPInUse = false;
  677. // Check to see if the IP address
  678. // is in use on any NIC. If it is
  679. // then increment and try all the NICs
  680. // again.
  681. for (
  682. unsigned int index = 0;
  683. index < GetNICCount();
  684. ++index)
  685. {
  686. NetworkInterface* nic = GetNIC(index);
  687. if (nic)
  688. {
  689. bool isInUseOnThisNIC =
  690. nic->IsIPAddressInUse(
  691. currentAddress,
  692. subnetMask);
  693. isIPInUse = isIPInUse || isInUseOnThisNIC;
  694. }
  695. if (isIPInUse)
  696. {
  697. break;
  698. }
  699. }
  700. if (isIPInUse)
  701. {
  702. ++currentAddress;
  703. if ((currentAddress & subnetMask) != (startAddress & subnetMask))
  704. {
  705. // REVIEW_JEFFJON : what should the behavior be if there are
  706. // no available addresses? Is this likely to happen?
  707. // Since we couldn't find an available address in this subnet
  708. // use the start address
  709. currentAddress = startAddress;
  710. break;
  711. }
  712. }
  713. } while (isIPInUse);
  714. result = currentAddress;
  715. LOG(IPAddressToString(result));
  716. return result;
  717. }