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.

412 lines
9.8 KiB

  1. // Copyright (C) 1998 Microsoft Corporation
  2. //
  3. // DNS installation and configuration code
  4. //
  5. // 6-16-98 sburns
  6. #include "headers.hxx"
  7. #include "resource.h"
  8. #include "ProgressDialog.hpp"
  9. #include "state.hpp"
  10. static const DWORD HELP_MAP[] =
  11. {
  12. 0, 0
  13. };
  14. static const int NAP_TIME = 3000; // in ms
  15. int
  16. millisecondsToSeconds(int millis)
  17. {
  18. static const int MILLIS_PER_SECOND = 1000;
  19. return millis / MILLIS_PER_SECOND;
  20. }
  21. bool
  22. pollForDNSServiceStart(ProgressDialog& progressDialog)
  23. {
  24. LOG_FUNCTION(PollForDNSServiceStart);
  25. for (int waitCount = 0; /* empty */ ; waitCount++)
  26. {
  27. progressDialog.UpdateText(
  28. String::format(
  29. IDS_WAITING_FOR_SERVICE_START,
  30. millisecondsToSeconds(NAP_TIME * waitCount)));
  31. if (progressDialog.WaitForButton(NAP_TIME) == ProgressDialog::PRESSED)
  32. {
  33. progressDialog.UpdateButton(String());
  34. popup.Info(
  35. progressDialog.GetHWND(),
  36. String::load(IDS_SKIP_DNS_MESSAGE));
  37. break;
  38. }
  39. if (Dns::IsServiceRunning())
  40. {
  41. // success!
  42. return true;
  43. }
  44. }
  45. return false;
  46. }
  47. bool
  48. pollForDNSServiceInstallAndStart(ProgressDialog& progressDialog)
  49. {
  50. LOG_FUNCTION(pollForDNSServiceInstallAndStart);
  51. State& state = State::GetInstance();
  52. bool shouldTimeout = false;
  53. if (state.RunHiddenUnattended())
  54. {
  55. // need to timeout in case the user cancelled the installer.
  56. // NTRAID#NTBUG9-424845-2001/07/02-sburns
  57. shouldTimeout = true;
  58. }
  59. static const int MAX_WAIT_COUNT = 60; // NAP_TIME * 60 = 3 minutes
  60. for (
  61. int waitCount = 0;
  62. !(shouldTimeout && (waitCount > MAX_WAIT_COUNT));
  63. ++waitCount)
  64. {
  65. progressDialog.UpdateText(
  66. String::format(
  67. IDS_WAITING_FOR_SERVICE_INSTALL,
  68. millisecondsToSeconds(NAP_TIME * waitCount)));
  69. if (progressDialog.WaitForButton(NAP_TIME) == ProgressDialog::PRESSED)
  70. {
  71. progressDialog.UpdateButton(String());
  72. popup.Info(
  73. progressDialog.GetHWND(),
  74. String::load(IDS_SKIP_DNS_MESSAGE));
  75. break;
  76. }
  77. if (Dns::IsServiceInstalled())
  78. {
  79. // Service is installed. Now check to see if it is running.
  80. return pollForDNSServiceStart(progressDialog);
  81. }
  82. }
  83. return false;
  84. }
  85. HRESULT
  86. createTempFile(const String& name, int textResID)
  87. {
  88. LOG_FUNCTION2(createTempFile, name);
  89. ASSERT(!name.empty());
  90. ASSERT(textResID);
  91. ASSERT(FS::IsValidPath(name));
  92. HRESULT hr = S_OK;
  93. HANDLE h = INVALID_HANDLE_VALUE;
  94. do
  95. {
  96. hr =
  97. // REVIEWED-2002/02/26-sburns name is full path, we overwrite any
  98. // squatters, default ACLs are ok
  99. FS::CreateFile(
  100. name,
  101. h,
  102. // REVIEWED-2002/02/28-sburns this level of access is correct.
  103. GENERIC_WRITE,
  104. 0,
  105. CREATE_ALWAYS,
  106. FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
  107. BREAK_ON_FAILED_HRESULT(hr);
  108. // write to file with Unicode text and end of file character.
  109. // NTRAID#NTBUG9-495994-2001/11/21-sburns
  110. hr =
  111. FS::Write(
  112. h,
  113. (wchar_t) 0xFEFF // Unicode Byte-order marker
  114. + String::load(textResID)
  115. + L"\032"); // end of file
  116. BREAK_ON_FAILED_HRESULT(hr);
  117. }
  118. while (0);
  119. Win::CloseHandle(h);
  120. return hr;
  121. }
  122. HRESULT
  123. spawnDNSInstaller(PROCESS_INFORMATION& info)
  124. {
  125. LOG_FUNCTION(spawnDNSInstaller);
  126. HRESULT hr = S_OK;
  127. // CODEWORK: use GetTempPath?
  128. // ISSUE-2002/03/01-sburns yes, probably, even though the contents
  129. // are not interesting.
  130. String sysFolder = Win::GetSystemDirectory();
  131. String infPath = sysFolder + L"\\dcpinf.000";
  132. String unattendPath = sysFolder + L"\\dcpunat.001";
  133. // create the inf and unattend files for the oc manager
  134. do
  135. {
  136. hr = createTempFile(infPath, IDS_INSTALL_DNS_INF_TEXT);
  137. BREAK_ON_FAILED_HRESULT(hr);
  138. hr = createTempFile(unattendPath, IDS_INSTALL_DNS_UNATTEND_TEXT);
  139. BREAK_ON_FAILED_HRESULT(hr);
  140. // NTRAID#NTBUG9-417879-2001/06/18-sburns
  141. State& state = State::GetInstance();
  142. String cancelOption;
  143. if (state.RunHiddenUnattended())
  144. {
  145. String option =
  146. state.GetAnswerFileOption(
  147. AnswerFile::OPTION_DISABLE_CANCEL_ON_DNS_INSTALL);
  148. if (option.icompare(AnswerFile::VALUE_YES) == 0)
  149. {
  150. cancelOption = L"/c";
  151. }
  152. }
  153. String commandLine =
  154. String::format(
  155. L"/i:%1 /u:%2 /x %3"
  156. // /z added per NTRAID#NTBUG9-440798-2001/07/23-sburns
  157. L" /z:netoc_show_unattended_messages",
  158. infPath.c_str(),
  159. unattendPath.c_str(),
  160. cancelOption.c_str());
  161. STARTUPINFO startup;
  162. // REVIEWED-2002/02/25-sburns correct byte count passed.
  163. ::ZeroMemory(&startup, sizeof startup);
  164. LOG(L"Calling CreateProcess");
  165. LOG(commandLine);
  166. // REVIEWED-2002/02/26-sburns wrapper requires full path to app
  167. hr =
  168. Win::CreateProcess(
  169. sysFolder + L"\\sysocmgr.exe",
  170. commandLine,
  171. 0,
  172. String(),
  173. startup,
  174. info);
  175. BREAK_ON_FAILED_HRESULT(hr);
  176. }
  177. while (0);
  178. return hr;
  179. }
  180. bool
  181. installDNS(ProgressDialog& progressDialog)
  182. {
  183. LOG_FUNCTION(installDNS);
  184. if (Dns::IsServiceInstalled())
  185. {
  186. LOG(L"DNS service is already installed");
  187. if (Dns::IsServiceRunning())
  188. {
  189. LOG(L"DNS service is already running");
  190. return true;
  191. }
  192. // @@ start the DNS service Dns::StartService?
  193. }
  194. progressDialog.UpdateText(String::load(IDS_INSTALLING_DNS));
  195. PROCESS_INFORMATION info;
  196. HRESULT hr = spawnDNSInstaller(info);
  197. if (FAILED(hr))
  198. {
  199. progressDialog.UpdateText(
  200. String::load(IDS_PROGRESS_ERROR_INSTALLING_DNS));
  201. popup.Error(
  202. progressDialog.GetHWND(),
  203. hr,
  204. IDS_ERROR_LAUNCHING_INSTALLER);
  205. return false;
  206. }
  207. progressDialog.UpdateButton(IDS_PROGRESS_BUTTON_SKIP_DNS);
  208. // monitor the state of the installer process.
  209. for (int waitCount = 0; /* empty */ ; waitCount++)
  210. {
  211. progressDialog.UpdateText(
  212. String::format(
  213. IDS_WAITING_FOR_INSTALLER,
  214. millisecondsToSeconds(NAP_TIME * waitCount)));
  215. if (progressDialog.WaitForButton(NAP_TIME) == ProgressDialog::PRESSED)
  216. {
  217. progressDialog.UpdateButton(String());
  218. popup.Info(
  219. progressDialog.GetHWND(),
  220. String::load(IDS_SKIP_DNS_MESSAGE));
  221. break;
  222. }
  223. DWORD exitCode = 0;
  224. hr = Win::GetExitCodeProcess(info.hProcess, exitCode);
  225. if (FAILED(hr))
  226. {
  227. LOG(L"GetExitCodeProcess failed");
  228. LOG_HRESULT(hr);
  229. progressDialog.UpdateText(
  230. String::load(IDS_PROGRESS_ERROR_INSTALLING_DNS));
  231. popup.Error(
  232. progressDialog.GetHWND(),
  233. hr,
  234. IDS_ERROR_QUERYING_INSTALLER);
  235. return false;
  236. }
  237. if (exitCode != STILL_ACTIVE)
  238. {
  239. // installer has terminated. Now check the status of the DNS
  240. // service
  241. return pollForDNSServiceInstallAndStart(progressDialog);
  242. }
  243. }
  244. // user bailed out
  245. return false;
  246. }
  247. bool
  248. InstallAndConfigureDns(
  249. ProgressDialog& progressDialog,
  250. const String& domainDNSName,
  251. bool isFirstDcInForest)
  252. {
  253. LOG_FUNCTION2(InstallAndConfigureDns, domainDNSName);
  254. ASSERT(!domainDNSName.empty());
  255. if (!installDNS(progressDialog))
  256. {
  257. return false;
  258. }
  259. progressDialog.UpdateText(String::load(IDS_CONFIGURING_DNS));
  260. SafeDLL dnsMgr(String::load(IDS_DNSMGR_DLL_NAME));
  261. FARPROC proc = 0;
  262. HRESULT hr = dnsMgr.GetProcAddress(L"DnsSetup", proc);
  263. if (SUCCEEDED(hr))
  264. {
  265. String p1 = domainDNSName;
  266. if (*(p1.rbegin()) != L'.')
  267. {
  268. // add trailing dot
  269. p1 += L'.';
  270. }
  271. String p2 = p1 + L"dns";
  272. DWORD flags = 0;
  273. if (isFirstDcInForest)
  274. {
  275. // NTRAID#NTBUG9-359894-2001/06/09-sburns
  276. flags |= DNS_SETUP_ZONE_CREATE_FOR_DCPROMO_FOREST;
  277. }
  278. if (State::GetInstance().ShouldConfigDnsClient())
  279. {
  280. // NTRAID#NTBUG9-489252-2001/11/08-sburns
  281. flags |= DNS_SETUP_AUTOCONFIG_CLIENT;
  282. }
  283. LOG(L"Calling DnsSetup");
  284. LOG(String::format(L"lpszFwdZoneName : %1", p1.c_str()));
  285. LOG(String::format(L"lpszFwdZoneFileName : %1", p2.c_str()));
  286. LOG( L"lpszRevZoneName : (null)");
  287. LOG( L"lpszRevZoneFileName : (null)");
  288. LOG(String::format(L"dwFlags : 0x%1!x!", flags));
  289. typedef HRESULT (*DNSSetup)(PCWSTR, PCWSTR, PCWSTR, PCWSTR, DWORD);
  290. DNSSetup dnsproc = reinterpret_cast<DNSSetup>(proc);
  291. hr = dnsproc(p1.c_str(), p2.c_str(), 0, 0, flags);
  292. LOG_HRESULT(hr);
  293. }
  294. else
  295. {
  296. LOG(L"unable to locate DnsSetup proc address");
  297. }
  298. if (FAILED(hr))
  299. {
  300. // unable to configure DNS, but it was installed.
  301. progressDialog.UpdateText(
  302. String::load(IDS_PROGRESS_ERROR_CONFIGURING_DNS));
  303. popup.Error(
  304. progressDialog.GetHWND(),
  305. hr,
  306. String::format(IDS_ERROR_CONFIGURING_DNS, domainDNSName.c_str()));
  307. return false;
  308. }
  309. return true;
  310. }