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.

497 lines
12 KiB

  1. // Copyright (c) 1997-2001 Microsoft Corporation
  2. //
  3. // File: DNSInstallationUnit.cpp
  4. //
  5. // Synopsis: Defines a DNSInstallationUnit
  6. // This object has the knowledge for installing the
  7. // DNS service
  8. //
  9. // History: 02/05/2001 JeffJon Created
  10. #include "pch.h"
  11. #include "resource.h"
  12. #include "DNSInstallationUnit.h"
  13. DNSInstallationUnit::DNSInstallationUnit() :
  14. isExpressPathInstall(false),
  15. staticIPAddress(0),
  16. subnetMask(0),
  17. NetworkServiceInstallationBase(
  18. IDS_DNS_SERVER_TYPE,
  19. IDS_DNS_SERVER_DESCRIPTION,
  20. IDS_DNS_SERVER_DESCRIPTION_INSTALLED,
  21. DNS_INSTALL)
  22. {
  23. LOG_CTOR(DNSInstallationUnit);
  24. }
  25. DNSInstallationUnit::~DNSInstallationUnit()
  26. {
  27. LOG_DTOR(DNSInstallationUnit);
  28. }
  29. InstallationReturnType
  30. DNSInstallationUnit::InstallService(HANDLE logfileHandle, HWND hwnd)
  31. {
  32. LOG_FUNCTION(DNSInstallationUnit::InstallService);
  33. InstallationReturnType result = INSTALL_SUCCESS;
  34. if (IsExpressPathInstall())
  35. {
  36. result = ExpressPathInstall(logfileHandle, hwnd);
  37. LOG_INSTALL_RETURN(result);
  38. return result;
  39. }
  40. // Create the inf and unattend files that are used by the
  41. // Optional Component Manager
  42. String infFileText;
  43. String unattendFileText;
  44. CreateInfFileText(infFileText, IDS_DNS_INF_WINDOW_TITLE);
  45. CreateUnattendFileText(unattendFileText, CYS_DNS_SERVICE_NAME);
  46. // Install the service through the Optional Component Manager
  47. bool ocmResult = InstallServiceWithOcManager(infFileText, unattendFileText);
  48. if (ocmResult &&
  49. IsServiceInstalled())
  50. {
  51. // Log the successful installation
  52. LOG(L"DNS was installed successfully");
  53. CYS_APPEND_LOG(String::load(IDS_LOG_INSTALL_START_DNS));
  54. // Run the DNS Wizard
  55. String resultText;
  56. if (ExecuteWizard(CYS_DNS_SERVICE_NAME, resultText))
  57. {
  58. // Check to be sure the wizard finished completely
  59. String configWizardResults;
  60. if (ReadConfigWizardRegkeys(configWizardResults))
  61. {
  62. // The Configure DNS Server Wizard completed successfully
  63. LOG(L"The Configure DNS Server Wizard completed successfully");
  64. CYS_APPEND_LOG(String::load(IDS_LOG_DNS_COMPLETED_SUCCESSFULLY));
  65. }
  66. else
  67. {
  68. // The Configure DNS Server Wizard did not finish successfully
  69. if (!configWizardResults.empty())
  70. {
  71. // An error was returned via the regkey
  72. LOG(String::format(
  73. L"The Configure DNS Server Wizard returned the error: %1",
  74. configWizardResults.c_str()));
  75. String formatString = String::load(IDS_LOG_DNS_WIZARD_ERROR);
  76. CYS_APPEND_LOG(String::format(formatString, configWizardResults.c_str()));
  77. }
  78. else
  79. {
  80. // The Configure DNS Server Wizard was cancelled by the user
  81. LOG(L"The Configure DNS Server Wizard was cancelled by the user");
  82. CYS_APPEND_LOG(String::load(IDS_LOG_DNS_WIZARD_CANCELLED));
  83. }
  84. }
  85. }
  86. else
  87. {
  88. // Show an error
  89. LOG(L"DNS could not be installed.");
  90. if (!resultText.empty())
  91. {
  92. CYS_APPEND_LOG(resultText);
  93. }
  94. }
  95. }
  96. else
  97. {
  98. // Log the failure
  99. LOG(L"DNS failed to install");
  100. CYS_APPEND_LOG(String::load(IDS_LOG_DNS_INSTALL_FAILED));
  101. result = INSTALL_FAILURE;
  102. }
  103. LOG_INSTALL_RETURN(result);
  104. return result;
  105. }
  106. InstallationReturnType
  107. DNSInstallationUnit::ExpressPathInstall(HANDLE /*logfileHandle*/, HWND /*hwnd*/)
  108. {
  109. LOG_FUNCTION(DNSInstallationUnit::ExpressPathInstall);
  110. InstallationReturnType result = INSTALL_SUCCESS;
  111. // Set the static IP address and the subnet mask
  112. // invoke netsh and wait for it to terminate
  113. String friendlyName = GetTcpIpInterfaceFriendlyName();
  114. do
  115. {
  116. // set static IP address and subnet mask
  117. String commandLine =
  118. String::format(
  119. L"netsh interface ip set address "
  120. L"name=\"%1\" source=static addr=%2 mask=%3 gateway=none",
  121. friendlyName.c_str(),
  122. GetStaticIPAddressString().c_str(),
  123. GetSubnetMaskString().c_str());
  124. DWORD exitCode1 = 0;
  125. HRESULT hr = ::CreateAndWaitForProcess(commandLine, exitCode1);
  126. if (FAILED(hr) || exitCode1)
  127. {
  128. LOG(String::format(
  129. L"Failed to set the static IP address and subnet mask: exitCode = %1!x!",
  130. exitCode1));
  131. result = INSTALL_FAILURE;
  132. break;
  133. }
  134. ASSERT(SUCCEEDED(hr));
  135. // set DNS server address to same address as local machine. netsh
  136. // does not allow the dns server address to be the loopback address.
  137. commandLine =
  138. String::format(
  139. L"netsh interface ip set dns name=\"%1\" source=static addr=%2",
  140. friendlyName.c_str(),
  141. GetStaticIPAddressString().c_str());
  142. DWORD exitCode2 = 0;
  143. hr = ::CreateAndWaitForProcess(commandLine, exitCode2);
  144. if (FAILED(hr) || exitCode2)
  145. {
  146. LOG(String::format(
  147. L"Failed to set the preferred DNS server IP address: exitCode = %1!x!",
  148. exitCode2));
  149. result = INSTALL_FAILURE;
  150. break;
  151. }
  152. } while (false);
  153. LOG_INSTALL_RETURN(result);
  154. return result;
  155. }
  156. // get guid name of the first tcp/ip interface we enum
  157. HRESULT
  158. DNSInstallationUnit::GetTcpIpInterfaceGuidName(String& result)
  159. {
  160. LOG_FUNCTION(DNSInstallationUnit::GetTcpIpInterfaceGuidName);
  161. result.erase();
  162. DWORD dwError = 0;
  163. ULONG ulSize = 0;
  164. PIP_INTERFACE_INFO pInfo = NULL;
  165. HRESULT hr = S_OK;
  166. while ( 1 )
  167. {
  168. dwError = ::GetInterfaceInfo( pInfo, &ulSize );
  169. if ( ERROR_INSUFFICIENT_BUFFER != dwError )
  170. {
  171. break;
  172. }
  173. if ( NULL != pInfo )
  174. {
  175. Win::LocalFree(pInfo);
  176. }
  177. if ( 0 == ulSize )
  178. {
  179. hr = E_FAIL;
  180. LOG_HRESULT(hr);
  181. return hr;
  182. }
  183. pInfo = (PIP_INTERFACE_INFO) ::LocalAlloc(LPTR, ulSize);
  184. if ( NULL == pInfo )
  185. {
  186. hr = E_OUTOFMEMORY;
  187. LOG_HRESULT(hr);
  188. return hr;
  189. }
  190. }
  191. if ( ERROR_SUCCESS != dwError || 0 == pInfo->NumAdapters )
  192. {
  193. if ( NULL != pInfo )
  194. {
  195. Win::LocalFree(pInfo);
  196. }
  197. hr = E_FAIL;
  198. LOG_HRESULT(hr);
  199. return hr;
  200. }
  201. // Skip the adapter prefix
  202. result = pInfo->Adapter[0].Name + strlen("\\Device\\Tcpip_"),
  203. // CODEWORK could do this with IIDFromString
  204. // // // // check whether this is a valid GUID
  205. // // //
  206. // // // SHUnicodeToTChar(wszGuidName, szGuid, ARRAYSIZE(szGuid));
  207. // // // if (!GUIDFromString(szGuid, &guid))
  208. // // // {
  209. // // // // we failed to get a valid tcp/ip interface
  210. // // // *wszGuidName = 0;
  211. // // // Win::LocalFree(pInfo);
  212. // // // return E_FAIL;
  213. // // // }
  214. LocalFree(pInfo);
  215. LOG(result);
  216. return S_OK;
  217. }
  218. // get friendly name of the first tcp/ip interface we enum
  219. String
  220. DNSInstallationUnit::GetTcpIpInterfaceFriendlyName()
  221. {
  222. LOG_FUNCTION(DNSInstallationUnit::GetTcpIpInterfaceFriendlyName);
  223. DWORD dwRet = 0;
  224. HANDLE hMprConfig = 0;
  225. static const unsigned friendlyNameLength = 128;
  226. wchar_t wszFriendlyName[friendlyNameLength];
  227. ZeroMemory(wszFriendlyName, sizeof(wchar_t) * friendlyNameLength);
  228. String result;
  229. String guidName;
  230. HRESULT hr = GetTcpIpInterfaceGuidName(guidName);
  231. if (SUCCEEDED(hr))
  232. {
  233. dwRet = MprConfigServerConnect(0, &hMprConfig);
  234. if (NO_ERROR == dwRet)
  235. {
  236. dwRet =
  237. MprConfigGetFriendlyName(
  238. hMprConfig,
  239. const_cast<wchar_t*>(guidName.c_str()),
  240. wszFriendlyName,
  241. sizeof(wchar_t) * friendlyNameLength);
  242. if (NO_ERROR != dwRet)
  243. {
  244. LOG(String::format(
  245. L"MprConfigGetFriendlyName() failed: error = %1!x!",
  246. dwRet));
  247. *wszFriendlyName = 0;
  248. }
  249. }
  250. else
  251. {
  252. LOG(String::format(
  253. L"MprConfigServerConnect() failed: error = %1!x!",
  254. dwRet));
  255. }
  256. MprConfigServerDisconnect(hMprConfig);
  257. }
  258. if (!*wszFriendlyName)
  259. {
  260. // we failed to get a friendly name, so use the default one
  261. // BUGBUG does this need to be localized?
  262. result = L"Local Area Connection";
  263. }
  264. else
  265. {
  266. result = wszFriendlyName;
  267. }
  268. LOG(result);
  269. return result;
  270. }
  271. bool
  272. DNSInstallationUnit::ReadConfigWizardRegkeys(String& configWizardResults) const
  273. {
  274. LOG_FUNCTION(DNSInstallationUnit::ReadConfigWizardRegkeys);
  275. bool result = true;
  276. do
  277. {
  278. DWORD value = 0;
  279. result = GetRegKeyValue(
  280. DNS_WIZARD_CONFIG_REGKEY,
  281. DNS_WIZARD_CONFIG_VALUE,
  282. value);
  283. if (result &&
  284. value != 0)
  285. {
  286. // The Configure DNS Server Wizard succeeded
  287. result = true;
  288. break;
  289. }
  290. // Since there was a failure (or the wizard was cancelled)
  291. // get the display string to log
  292. result = GetRegKeyValue(
  293. DNS_WIZARD_RESULT_REGKEY,
  294. DNS_WIZARD_RESULT_VALUE,
  295. configWizardResults);
  296. } while (false);
  297. LOG_BOOL(result);
  298. return result;
  299. }
  300. bool
  301. DNSInstallationUnit::IsServiceInstalled()
  302. {
  303. LOG_FUNCTION(DNSInstallationUnit::IsServiceInstalled);
  304. bool result = IsServiceInstalledHelper(CYS_DNS_SERVICE_NAME);
  305. LOG_BOOL(result);
  306. return result;
  307. }
  308. bool
  309. DNSInstallationUnit::GetFinishText(String& message)
  310. {
  311. LOG_FUNCTION(DNSInstallationUnit::GetFinishText);
  312. message = String::load(IDS_DNS_FINISH_TEXT);
  313. LOG_BOOL(true);
  314. return true;
  315. }
  316. void
  317. DNSInstallationUnit::SetExpressPathInstall(bool isExpressPath)
  318. {
  319. LOG_FUNCTION2(
  320. DNSInstallationUnit::SetExpressPathInstall,
  321. (isExpressPath) ? L"true" : L"false");
  322. isExpressPathInstall = isExpressPath;
  323. }
  324. bool
  325. DNSInstallationUnit::IsExpressPathInstall() const
  326. {
  327. LOG_FUNCTION(DNSInstallationUnit::IsExpressPathInstall);
  328. return isExpressPathInstall;
  329. }
  330. void
  331. DNSInstallationUnit::SetStaticIPAddress(DWORD ipaddress)
  332. {
  333. LOG_FUNCTION2(
  334. DNSInstallationUnit::SetStaticIPAddress,
  335. String::format(
  336. L"%1!d!.%2!d!.%3!d!.%4!d!",
  337. FIRST_IPADDRESS(ipaddress),
  338. SECOND_IPADDRESS(ipaddress),
  339. THIRD_IPADDRESS(ipaddress),
  340. FOURTH_IPADDRESS(ipaddress)));
  341. staticIPAddress = ipaddress;
  342. }
  343. void
  344. DNSInstallationUnit::SetSubnetMask(DWORD mask)
  345. {
  346. LOG_FUNCTION2(
  347. DNSInstallationUnit::SetSubnetMask,
  348. String::format(
  349. L"%1!d!.%2!d!.%3!d!.%4!d!",
  350. FIRST_IPADDRESS(mask),
  351. SECOND_IPADDRESS(mask),
  352. THIRD_IPADDRESS(mask),
  353. FOURTH_IPADDRESS(mask)));
  354. subnetMask = mask;
  355. }
  356. String
  357. DNSInstallationUnit::GetStaticIPAddressString() const
  358. {
  359. LOG_FUNCTION(DNSInstallationUnit::GetStaticIPAddressString);
  360. String result = String::format(
  361. L"%1!d!.%2!d!.%3!d!.%4!d!",
  362. FIRST_IPADDRESS(staticIPAddress),
  363. SECOND_IPADDRESS(staticIPAddress),
  364. THIRD_IPADDRESS(staticIPAddress),
  365. FOURTH_IPADDRESS(staticIPAddress));
  366. LOG(result);
  367. return result;
  368. }
  369. String
  370. DNSInstallationUnit::GetSubnetMaskString() const
  371. {
  372. LOG_FUNCTION(DNSInstallationUnit::GetSubnetMaskString);
  373. String result = String::format(
  374. L"%1!d!.%2!d!.%3!d!.%4!d!",
  375. FIRST_IPADDRESS(subnetMask),
  376. SECOND_IPADDRESS(subnetMask),
  377. THIRD_IPADDRESS(subnetMask),
  378. FOURTH_IPADDRESS(subnetMask));
  379. LOG(result);
  380. return result;
  381. }