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.

1518 lines
36 KiB

  1. // Copyright (C) 2002 Microsoft Corporation
  2. //
  3. // class ManageYourServer, which implements IManageYourServer
  4. //
  5. // 21 January 2002 sburns
  6. #include "headers.hxx"
  7. #include "resource.h"
  8. #include "ManageYourServer.hpp"
  9. #include "util.hpp"
  10. #include <cys.h>
  11. #include <regkeys.h>
  12. // All of these includes are needed to get functionality in State class in CYS.
  13. #include <iptypes.h>
  14. #include <lm.h>
  15. #include <common.h>
  16. #include <state.h>
  17. const size_t NUMBER_OF_AUTOMATION_INTERFACES = 1;
  18. bool ManageYourServer::isDCCheckInitialized = false;
  19. bool ManageYourServer::fragMapBuilt = false;
  20. ManageYourServer::RoleToFragmentNameMap ManageYourServer::fragMap;
  21. const String QUOT(L"&quot;");
  22. const String OPEN_XML_PI(L"<?xml");
  23. const String CLOSE_XML_PI(L"?>");
  24. // This constant needs to be the same as that defined in res\mysdynamic.xsl in
  25. // the template "TranslateParagraphs".
  26. const String NEW_PARAGRAPH (L"PARA_MARKER");
  27. // NTRAID#NTBUG9-626890-2002/06/28-artm
  28. // support changing TS text based on [non]presence of licensing server
  29. bool
  30. FoundTSLicensingServer()
  31. {
  32. LOG_FUNCTION(FoundTSLicensingServer);
  33. #ifdef DBG
  34. // Calculate the hresult that corresponds to asking for the wrong type of key value.
  35. static const HRESULT WRONG_VALUE_TYPE = Win32ToHresult(ERROR_INVALID_FUNCTION);
  36. #endif
  37. static const String TS_LICENSING_PATH(L"Software\\Microsoft\\MSLicensing\\Parameters");
  38. static const String REG_DOMAIN_SERVER_MULTI(L"DomainLicenseServerMulti");
  39. static const String ENTERPRISE_SERVER_MULTI(L"EnterpriseServerMulti");
  40. bool found = false;
  41. RegistryKey tsLicensingKey;
  42. // Try to open the TS licensing key.
  43. HRESULT keyHr = tsLicensingKey.Open(
  44. HKEY_LOCAL_MACHINE,
  45. TS_LICENSING_PATH,
  46. KEY_READ);
  47. if (SUCCEEDED(keyHr))
  48. {
  49. StringList data;
  50. // Was a licensing server found at the domain level?
  51. keyHr = tsLicensingKey.GetValue(
  52. REG_DOMAIN_SERVER_MULTI,
  53. back_inserter(data));
  54. ASSERT(keyHr != WRONG_VALUE_TYPE);
  55. // NTRAID#NTBUG9-691505-2002/08/23-artm
  56. // If a value is empty then that means a licensing server was not found.
  57. if (FAILED(keyHr) || data.empty())
  58. {
  59. // If not, was a licensing server found at the enterprise level?
  60. data.clear();
  61. keyHr = tsLicensingKey.GetValue(
  62. ENTERPRISE_SERVER_MULTI,
  63. back_inserter(data));
  64. ASSERT(keyHr != WRONG_VALUE_TYPE);
  65. }
  66. // Did we find the value?
  67. if (SUCCEEDED(keyHr) && !data.empty())
  68. {
  69. found = true;
  70. }
  71. }
  72. return found;
  73. }
  74. bool
  75. IsHardened(const String& keyName)
  76. {
  77. LOG_FUNCTION2(IsHardened, keyName);
  78. // By default, IE security is not hardened.
  79. bool hardened = false;
  80. RegistryKey key;
  81. static const String IE_HARD_VALUE (L"IsInstalled");
  82. static const DWORD HARD_SECURITY = 1;
  83. static const DWORD SOFT_SECURITY = 0;
  84. do
  85. {
  86. HRESULT hr = key.Open(HKEY_LOCAL_MACHINE, keyName);
  87. // If key not found, assume default setting.
  88. BREAK_ON_FAILED_HRESULT(hr);
  89. DWORD setting = 0;
  90. hr = key.GetValue(IE_HARD_VALUE, setting);
  91. // If value not found, assume default setting.
  92. BREAK_ON_FAILED_HRESULT(hr);
  93. if (setting == HARD_SECURITY)
  94. {
  95. hardened = true;
  96. }
  97. else if (setting == SOFT_SECURITY)
  98. {
  99. hardened = false;
  100. }
  101. else
  102. {
  103. LOG(L"unexpected value for IE security level, assuming default level");
  104. }
  105. } while(false);
  106. key.Close();
  107. LOG_BOOL(hardened);
  108. return hardened;
  109. }
  110. #ifdef LOGGING_BUILD
  111. static const String HARDENED_LEVEL [] = {
  112. L"NO_HARDENING",
  113. L"USERS_HARDENED",
  114. L"ADMINS_HARDENED",
  115. L"ALL_HARDENED"
  116. };
  117. #endif
  118. HardenedLevel
  119. GetIEHardLevel()
  120. {
  121. LOG_FUNCTION(GetIEHardLevel);
  122. static const String IE_HARD_ADMINS_KEY (L"SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}");
  123. static const String IE_HARD_USERS_KEY (L"SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}");
  124. HardenedLevel level = NO_HARDENING;
  125. bool usersHard = IsHardened(IE_HARD_USERS_KEY);
  126. bool adminsHard = IsHardened(IE_HARD_ADMINS_KEY);
  127. if (adminsHard && usersHard)
  128. {
  129. level = ALL_HARDENED;
  130. }
  131. else if (adminsHard)
  132. {
  133. level = ADMINS_HARDENED;
  134. }
  135. else if (usersHard)
  136. {
  137. level = USERS_HARDENED;
  138. }
  139. else
  140. {
  141. level = NO_HARDENING;
  142. }
  143. LOG(HARDENED_LEVEL[level]);
  144. return level;
  145. }
  146. void
  147. TerminalServerParamSub(String& s)
  148. {
  149. LOG_FUNCTION(TerminalServerParamSub);
  150. static const String tlsFound = String::load(IDS_TS_LICENSING_FOUND);
  151. static const String tlsNotFound = String::load(IDS_TS_LICENSING_NOT_FOUND);
  152. String description = FoundTSLicensingServer() ? tlsFound : tlsNotFound;
  153. // This lookup table needs to be the same size as the HardenedLevel
  154. // enumeration defined above, and should be in the same order.
  155. static const String TS_HARD_TABLE [] = {
  156. String::load(IDS_TS_IE_SOFTENED),
  157. String::load(IDS_TS_IE_HARDENED_USERS),
  158. String::load(IDS_TS_IE_HARDENED_ADMINS),
  159. String::load(IDS_TS_IE_HARDENED)
  160. };
  161. static const int DESCRIPTION_TABLE_SIZE =
  162. sizeof(TS_HARD_TABLE) / sizeof(TS_HARD_TABLE[0]);
  163. HardenedLevel level = GetIEHardLevel();
  164. if (0 <= level && level < DESCRIPTION_TABLE_SIZE)
  165. {
  166. description += NEW_PARAGRAPH + TS_HARD_TABLE[level];
  167. }
  168. else
  169. {
  170. // Unexpected hardening level.
  171. LOG(L"unexpected hardening level");
  172. ASSERT(false);
  173. description += NEW_PARAGRAPH + TS_HARD_TABLE[0];
  174. }
  175. s = String::format(s, description.c_str());
  176. }
  177. //NTRAID#9-607219-30-Apr-2002-jrowlett
  178. // callback function to fill out the web role xml to give to the HTA.
  179. void
  180. WebServerParamSub(String& s)
  181. {
  182. // NTRAID#NTBUG9-665774-2002/07/17-artm
  183. // Need to customize role description based on if the machine is 64-bit or not.
  184. // <Role
  185. // name="Application Server"
  186. // description="%1"
  187. // mys_id="WebServer"
  188. // >
  189. // <Link
  190. // description="%2"
  191. // type="%3"
  192. // command="%4"
  193. // tooltip="Provides tools for using a Web browser to administer a Web server remotely."
  194. // />
  195. LOG_FUNCTION(WebServerParamSub);
  196. String roleDesc;
  197. String webDesc;
  198. String webType;
  199. String webCommand;
  200. if (State::GetInstance().Is64Bit())
  201. {
  202. roleDesc = String::load(IDS_WEB_SERVER_64_DESC);
  203. }
  204. else
  205. {
  206. roleDesc = String::load(IDS_WEB_SERVER_NO64_DESC);
  207. }
  208. if (IsSAKUnitInstalled(WEB))
  209. {
  210. webDesc = String::load(IDS_WEB_SERVER_SAK_DESC);
  211. webType = L"url";
  212. webCommand = GetSAKURL();
  213. }
  214. else
  215. {
  216. webDesc = String::load(IDS_WEB_SERVER_NO_SAK_DESC);
  217. webType = L"help";
  218. webCommand = L"ntshowto.chm::/SAK_howto.htm";
  219. }
  220. s =
  221. String::format(
  222. s,
  223. roleDesc.c_str(),
  224. webDesc.c_str(),
  225. webType.c_str(),
  226. webCommand.c_str());
  227. }
  228. void
  229. Pop3ServerParamSub(String& s)
  230. {
  231. LOG_FUNCTION(Pop3ServerParamSub);
  232. static String pop3ConsolePath;
  233. if (pop3ConsolePath.empty())
  234. {
  235. // initialize the path from the registry
  236. do
  237. {
  238. RegistryKey key;
  239. HRESULT hr =
  240. key.Open(
  241. HKEY_LOCAL_MACHINE,
  242. L"Software\\Microsoft\\Pop3 Service",
  243. KEY_READ);
  244. BREAK_ON_FAILED_HRESULT(hr);
  245. // not the file, like you might think from the name, but the
  246. // folder the file is in. Bother.
  247. hr = key.GetValue(L"ConsoleFile", pop3ConsolePath);
  248. BREAK_ON_FAILED_HRESULT(hr);
  249. pop3ConsolePath = FS::AppendPath(pop3ConsolePath, L"p3server.msc");
  250. if (!FS::PathExists(pop3ConsolePath))
  251. {
  252. // the path had better exist if the reg key is present!
  253. ASSERT(false);
  254. LOG(L"pop3 console is not present");
  255. pop3ConsolePath.erase();
  256. }
  257. }
  258. while (0);
  259. }
  260. s =
  261. String::format(
  262. s,
  263. pop3ConsolePath.empty()
  264. // If we can't find it, then hope that the console is on the
  265. // search path
  266. ? L"&quot;p3server.msc&quot;"
  267. : (QUOT + pop3ConsolePath + QUOT).c_str());
  268. }
  269. // NTRAID#NTBUG9-698722-2002/09/03-artm
  270. //
  271. // Replace the DCPromo status check function pointer
  272. // with one appropriate for MYS.
  273. //
  274. // This is a little bit of a hack, but there isn't
  275. // a better alternative...
  276. void
  277. ManageYourServer::InitDCPromoStatusCheck()
  278. {
  279. LOG_FUNCTION(ManageYourServer::InitDCPromoStatusCheck);
  280. size_t roleCount = GetServerRoleStatusTableElementCount();
  281. for (size_t i = 0; i < roleCount; ++i)
  282. {
  283. if (serverRoleStatusTable[i].role == DC_SERVER)
  284. {
  285. serverRoleStatusTable[i].Status = GetDCStatusForMYS;
  286. // Sanity check.
  287. ASSERT(serverRoleStatusTable[i].Status);
  288. break;
  289. }
  290. }
  291. }
  292. void
  293. ManageYourServer::BuildFragMap()
  294. {
  295. LOG_FUNCTION(ManageYourServer::BuildFragMap);
  296. fragMap.insert(
  297. RoleToFragmentNameMap::value_type(
  298. DHCP_SERVER,
  299. std::make_pair(
  300. String(L"DhcpServerRole.xml"),
  301. (ParamSubFunc) 0) ) );
  302. fragMap.insert(
  303. RoleToFragmentNameMap::value_type(
  304. WINS_SERVER,
  305. std::make_pair(
  306. String(L"WinsServerRole.xml"),
  307. (ParamSubFunc) 0) ) );
  308. fragMap.insert(
  309. RoleToFragmentNameMap::value_type(
  310. RRAS_SERVER,
  311. std::make_pair(
  312. String(L"RrasServerRole.xml"),
  313. (ParamSubFunc) 0) ) );
  314. fragMap.insert(
  315. RoleToFragmentNameMap::value_type(
  316. TERMINALSERVER_SERVER,
  317. std::make_pair(
  318. String(L"TerminalServerRole.xml"),
  319. (ParamSubFunc) TerminalServerParamSub) ) );
  320. fragMap.insert(
  321. RoleToFragmentNameMap::value_type(
  322. FILESERVER_SERVER,
  323. std::make_pair(
  324. String(L"FileServerRole.xml"),
  325. (ParamSubFunc) 0) ) );
  326. fragMap.insert(
  327. RoleToFragmentNameMap::value_type(
  328. PRINTSERVER_SERVER,
  329. std::make_pair(
  330. String(L"PrintServerRole.xml"),
  331. (ParamSubFunc) 0) ) );
  332. fragMap.insert(
  333. RoleToFragmentNameMap::value_type(
  334. MEDIASERVER_SERVER,
  335. std::make_pair(
  336. String(L"MediaServerRole.xml"),
  337. (ParamSubFunc) 0) ) );
  338. fragMap.insert(
  339. RoleToFragmentNameMap::value_type(
  340. WEBAPP_SERVER,
  341. std::make_pair(
  342. String(L"WebServerRole.xml"),
  343. (ParamSubFunc) WebServerParamSub) ) );
  344. fragMap.insert(
  345. RoleToFragmentNameMap::value_type(
  346. DC_SERVER,
  347. std::make_pair(
  348. String(L"DomainControllerRole.xml"),
  349. (ParamSubFunc) 0) ) );
  350. fragMap.insert(
  351. RoleToFragmentNameMap::value_type(
  352. POP3_SERVER,
  353. std::make_pair(
  354. String(L"Pop3ServerRole.xml"),
  355. (ParamSubFunc) Pop3ServerParamSub) ) );
  356. fragMap.insert(
  357. RoleToFragmentNameMap::value_type(
  358. DNS_SERVER,
  359. std::make_pair(
  360. String(L"DnsServerRole.xml"),
  361. (ParamSubFunc) 0) ) );
  362. ASSERT(fragMap.size() == GetServerRoleStatusTableElementCount());
  363. }
  364. ManageYourServer::ManageYourServer()
  365. :
  366. refcount(1), // implicit AddRef
  367. roleStatus(),
  368. foundTLS(false),
  369. ieSecurity(NO_HARDENING)
  370. {
  371. LOG_CTOR(ManageYourServer);
  372. m_ppTypeInfo = new ITypeInfo*[NUMBER_OF_AUTOMATION_INTERFACES];
  373. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  374. {
  375. m_ppTypeInfo[i] = NULL;
  376. }
  377. ITypeLib *ptl = 0;
  378. HRESULT hr = LoadRegTypeLib(LIBID_ManageYourServerLib, 1, 0, 0, &ptl);
  379. if (SUCCEEDED(hr))
  380. {
  381. ptl->GetTypeInfoOfGuid(IID_IManageYourServer, &(m_ppTypeInfo[0]));
  382. ptl->Release();
  383. }
  384. if (!isDCCheckInitialized)
  385. {
  386. InitDCPromoStatusCheck();
  387. isDCCheckInitialized = true;
  388. }
  389. if (!fragMapBuilt)
  390. {
  391. BuildFragMap();
  392. fragMapBuilt = true;
  393. }
  394. foundTLS = FoundTSLicensingServer();
  395. ieSecurity = GetIEHardLevel();
  396. }
  397. ManageYourServer::~ManageYourServer()
  398. {
  399. LOG_DTOR(ManageYourServer);
  400. ASSERT(refcount == 0);
  401. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  402. {
  403. m_ppTypeInfo[i]->Release();
  404. }
  405. delete[] m_ppTypeInfo;
  406. }
  407. HRESULT __stdcall
  408. ManageYourServer::QueryInterface(REFIID riid, void **ppv)
  409. {
  410. LOG_FUNCTION(ManageYourServer::QueryInterface);
  411. if (riid == IID_IUnknown)
  412. {
  413. LOG(L"IUnknown");
  414. *ppv =
  415. static_cast<IUnknown*>(static_cast<IManageYourServer*>(this));
  416. }
  417. else if (riid == IID_IManageYourServer)
  418. {
  419. LOG(L"IManageYourServer");
  420. *ppv = static_cast<IManageYourServer*>(this);
  421. }
  422. else if (riid == IID_IDispatch && m_ppTypeInfo[0])
  423. {
  424. LOG(L"IDispatch");
  425. *ppv = static_cast<IDispatch*>(this);
  426. }
  427. // CODEWORK
  428. // else if (riid == IID_ISupportErrorInfo)
  429. // {
  430. // LOG(L"ISupportErrorInfo");
  431. //
  432. // *ppv = static_cast<ISupportErrorInfo*>(this);
  433. // }
  434. else
  435. {
  436. LOG(L"unknown interface queried");
  437. return (*ppv = 0), E_NOINTERFACE;
  438. }
  439. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  440. return S_OK;
  441. }
  442. ULONG __stdcall
  443. ManageYourServer::AddRef(void)
  444. {
  445. LOG_ADDREF(ManageYourServer);
  446. return Win::InterlockedIncrement(refcount);
  447. }
  448. ULONG __stdcall
  449. ManageYourServer::Release(void)
  450. {
  451. LOG_RELEASE(ManageYourServer);
  452. // need to copy the result of the decrement, because if we delete this,
  453. // refcount will no longer be valid memory, and that might hose
  454. // multithreaded callers. NTRAID#NTBUG9-566901-2002/03/06-sburns
  455. long newref = Win::InterlockedDecrement(refcount);
  456. if (newref == 0)
  457. {
  458. delete this;
  459. return 0;
  460. }
  461. // we should not have decremented into negative values.
  462. ASSERT(newref > 0);
  463. return newref;
  464. }
  465. HRESULT __stdcall
  466. ManageYourServer::GetTypeInfoCount(UINT *pcti)
  467. {
  468. LOG_FUNCTION(ManageYourServer::GetTypeInfoCount);
  469. if (pcti == 0)
  470. {
  471. return E_POINTER;
  472. }
  473. *pcti = 1;
  474. return S_OK;
  475. }
  476. HRESULT __stdcall
  477. ManageYourServer::GetTypeInfo(UINT cti, LCID, ITypeInfo **ppti)
  478. {
  479. LOG_FUNCTION(ManageYourServer::GetTypeInfo);
  480. if (ppti == 0)
  481. {
  482. return E_POINTER;
  483. }
  484. if (cti != 0)
  485. {
  486. *ppti = 0;
  487. return DISP_E_BADINDEX;
  488. }
  489. (*ppti = m_ppTypeInfo[0])->AddRef();
  490. return S_OK;
  491. }
  492. HRESULT __stdcall
  493. ManageYourServer::GetIDsOfNames(
  494. REFIID riid,
  495. OLECHAR **prgpsz,
  496. UINT cNames,
  497. LCID lcid,
  498. DISPID *prgids)
  499. {
  500. LOG_FUNCTION(ManageYourServer::GetIDsOfNames);
  501. HRESULT hr = S_OK;
  502. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  503. {
  504. hr = (m_ppTypeInfo[i])->GetIDsOfNames(prgpsz, cNames, prgids);
  505. if (SUCCEEDED(hr) || DISP_E_UNKNOWNNAME != hr)
  506. break;
  507. }
  508. return hr;
  509. }
  510. HRESULT __stdcall
  511. ManageYourServer::Invoke(
  512. DISPID id,
  513. REFIID riid,
  514. LCID lcid,
  515. WORD wFlags,
  516. DISPPARAMS *params,
  517. VARIANT *pVarResult,
  518. EXCEPINFO *pei,
  519. UINT *puArgErr)
  520. {
  521. LOG_FUNCTION(ManageYourServer::Invoke);
  522. HRESULT hr = S_OK;
  523. IDispatch *pDispatch[NUMBER_OF_AUTOMATION_INTERFACES] =
  524. {
  525. (IDispatch*)(IManageYourServer *)(this),
  526. };
  527. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  528. {
  529. hr =
  530. (m_ppTypeInfo[i])->Invoke(
  531. pDispatch[i],
  532. id,
  533. wFlags,
  534. params,
  535. pVarResult,
  536. pei,
  537. puArgErr);
  538. if (DISP_E_MEMBERNOTFOUND != hr)
  539. break;
  540. }
  541. return hr;
  542. }
  543. // HRESULT __stdcall
  544. // ManageYourServer::InterfaceSupportsErrorInfo(const IID& iid)
  545. // {
  546. // LOG_FUNCTION(ManageYourServer::InterfaceSupportsErrorInfo);
  547. //
  548. // if (iid == IID_IManageYourServer)
  549. // {
  550. // return S_OK;
  551. // }
  552. //
  553. // return S_FALSE;
  554. // }
  555. void
  556. ManageYourServer::GetRoleStatus(RoleStatusVector& stat)
  557. {
  558. LOG_FUNCTION(ManageYourServer::GetRoleStatus);
  559. size_t roleCount = GetServerRoleStatusTableElementCount();
  560. stat.clear();
  561. stat.resize(roleCount);
  562. for (size_t i = 0; i < roleCount; ++i)
  563. {
  564. ASSERT(serverRoleStatusTable[i].Status);
  565. stat[i].role = serverRoleStatusTable[i].role;
  566. stat[i].status = serverRoleStatusTable[i].Status();
  567. // this is for debugging
  568. // stat[i].status = STATUS_CONFIGURED;
  569. LOG(
  570. String::format(
  571. L"role = %1!d! status = %2",
  572. stat[i].role,
  573. statusStrings[stat[i].status].c_str()));
  574. }
  575. }
  576. void
  577. ManageYourServer::AppendXmlFragment(
  578. String& s,
  579. const String& fragName,
  580. ParamSubFunc subFunc)
  581. {
  582. LOG_FUNCTION2(ManageYourServer::AppendXmlFragment, fragName);
  583. ASSERT(!fragName.empty());
  584. // Look up the resource by name, load it into a string, and append
  585. // the string to s.
  586. String fragment;
  587. size_t fragmentCharCount = 0;
  588. HRESULT hr = S_OK;
  589. do
  590. {
  591. HRSRC rsc = 0;
  592. hr = Win::FindResource(fragName.c_str(), RT_HTML, rsc);
  593. BREAK_ON_FAILED_HRESULT2(hr, L"Find Resource");
  594. DWORD resSize = 0;
  595. hr = Win::SizeofResource(rsc, resSize);
  596. BREAK_ON_FAILED_HRESULT2(hr, L"SizeofResource");
  597. if (!resSize)
  598. {
  599. hr = E_FAIL;
  600. BREAK_ON_FAILED_HRESULT2(hr, L"resource is size 0");
  601. }
  602. // we don't expect the xml fragments to be larger than this.
  603. // NTRAID#NTBUG9-628965-2002/05/29-artm
  604. // Resource limit was too small. Increasing to 1MB.
  605. static const size_t RES_MAX_BYTES = 1024 * 1024;
  606. if (resSize > RES_MAX_BYTES)
  607. {
  608. hr = E_FAIL;
  609. BREAK_ON_FAILED_HRESULT2(hr, L"resource is too big");
  610. }
  611. HGLOBAL glob = 0;
  612. hr = Win::LoadResource(rsc, glob);
  613. BREAK_ON_FAILED_HRESULT2(hr, L"Load Resource");
  614. void* data = ::LockResource(glob);
  615. if (!data)
  616. {
  617. hr = E_FAIL;
  618. BREAK_ON_FAILED_HRESULT2(hr, L"Lock Resource");
  619. }
  620. ASSERT(data);
  621. // at this point, we have a pointer to the beginning of the binary
  622. // resource data, which we know is a stream of unicode characters
  623. // beginning with 0xFFFE, and is resSize bytes large.
  624. const wchar_t* text = (wchar_t*) data;
  625. // FEFF == FFFE to you and me. hey, that rhymes!
  626. static const int FFFE = 0xFEFF;
  627. ASSERT(text[0] == FFFE);
  628. // skip the leading marker.
  629. ++text;
  630. // character count is 1 less 'cause we skipped a the leading marker
  631. fragmentCharCount = resSize / sizeof(wchar_t) - 1;
  632. // +1 for paranoid null termination
  633. fragment.resize(fragmentCharCount + 1, 0);
  634. wchar_t* rawBuf = const_cast<wchar_t*>(fragment.c_str());
  635. // REVIEWED-2002/03/07-sburns correct byte count passed
  636. ::CopyMemory(rawBuf, text, fragmentCharCount * sizeof wchar_t);
  637. // now that we have a fragment, dike off the xml format tag. This is
  638. // to turn the text from a valid xml document to a fragment, which is
  639. // necessary because of a limitation of our xml localization tools.
  640. // NTRAID#NTBUG9-559423-2002/04/02-sburns
  641. //
  642. // Part II: NTRAID#NTBUG9-620044-2002/05/12-artm
  643. // Apparently localization needs encoding="unicode" as an attribute
  644. // on the process instruction. To reduce resource churn and load
  645. // on localization---and to make this code more robust---we'll search
  646. // for any <?xml ... ?> processing instruction and replace it with an
  647. // empty string. The code is uglier but less fragile.
  648. String::size_type endPosition = 0;
  649. String sub;
  650. // Look for an XML processing instruction.
  651. for (String::size_type nextPosition = fragment.find(OPEN_XML_PI);
  652. nextPosition != String::npos;
  653. nextPosition = fragment.find(OPEN_XML_PI))
  654. {
  655. // We found one, locate the end of the PI.
  656. endPosition = fragment.find(CLOSE_XML_PI);
  657. // Do a sanity check on the resources we've loaded.
  658. // The PI should be closed, and the closing should
  659. // come after the opening. This should never happen.
  660. if (endPosition == String::npos || endPosition < nextPosition)
  661. {
  662. ASSERT(false);
  663. break;
  664. }
  665. // Move the end position past the end of the PI.
  666. endPosition += CLOSE_XML_PI.length();
  667. // Get the substring and replace it with an empty string.
  668. // The more elegant way to do this would be to call a different
  669. // version of replace() with the start position and max # characters;
  670. // however, the compiler cannot find that inherited overload.
  671. sub = fragment.substr(nextPosition, endPosition - nextPosition);
  672. fragment.replace(sub, L"");
  673. }
  674. }
  675. while (0);
  676. if (subFunc)
  677. {
  678. subFunc(fragment);
  679. }
  680. LOG(fragment);
  681. s.append(fragment);
  682. }
  683. HRESULT __stdcall
  684. ManageYourServer::GetConfiguredRoleMarkup(
  685. /* [retval][out] */ BSTR *result)
  686. {
  687. LOG_FUNCTION(ManageYourServer::GetConfiguredRoleMarkup);
  688. ASSERT(result);
  689. HRESULT hr = S_OK;
  690. do
  691. {
  692. if (!result)
  693. {
  694. hr = E_INVALIDARG;
  695. break;
  696. }
  697. // Localization will need to include the encoding="unicode" attribute. For
  698. // consistency we will use that encoding by default.
  699. // NTRAID#NTBUG9-620044-2002/05/12-artm
  700. String s(L"<?xml version=\"1.0\" encoding=\"unicode\" ?>\n");
  701. s.append(L"<Roles>");
  702. GetRoleStatus(roleStatus);
  703. // Assemble the role markup fragments in the same order as in the
  704. // role status table used by CYS (which is the order that the roles
  705. // appear in the CYS role listbox.
  706. for (
  707. RoleStatusVector::iterator i = roleStatus.begin();
  708. i != roleStatus.end();
  709. ++i)
  710. {
  711. if (i->status == STATUS_CONFIGURED || i->status == STATUS_COMPLETED)
  712. {
  713. // find the corresponding XML fragment for the role.
  714. String fragmentName = fragMap[i->role].first;
  715. ASSERT(!fragmentName.empty());
  716. if (!fragmentName.empty())
  717. {
  718. AppendXmlFragment(s, fragmentName, fragMap[i->role].second);
  719. }
  720. }
  721. }
  722. s.append(L"</Roles>");
  723. *result = ::SysAllocString(s.c_str());
  724. // sort by role so that the comparison to old status vectors will work
  725. // with operator != in HasRoleStatusChanged
  726. std::sort(roleStatus.begin(), roleStatus.end());
  727. }
  728. while (0);
  729. LOG_HRESULT(hr);
  730. return hr;
  731. }
  732. HRESULT __stdcall
  733. ManageYourServer::HasRoleStatusChanged(
  734. /* [retval][out] */ BOOL *result)
  735. {
  736. LOG_FUNCTION(ManageYourServer::HasRoleStatusChanged);
  737. ASSERT(result);
  738. HRESULT hr = S_OK;
  739. do
  740. {
  741. if (!result)
  742. {
  743. hr = E_INVALIDARG;
  744. break;
  745. }
  746. *result = FALSE;
  747. RoleStatusVector newStatus;
  748. GetRoleStatus(newStatus);
  749. // sort by role so that the comparison to old status vectors will work
  750. // with operator !=
  751. std::sort(newStatus.begin(), newStatus.end());
  752. HardenedLevel currentSecurity = GetIEHardLevel();
  753. if (newStatus != roleStatus)
  754. {
  755. *result = TRUE;
  756. roleStatus = newStatus;
  757. }
  758. else if (FoundTSLicensingServer() != foundTLS)
  759. {
  760. // NTRAID#NTBUG9-626890-2002/07/03-artm
  761. // If a TS licensing server comes on line, that counts as a role status change.
  762. foundTLS = !foundTLS;
  763. *result = TRUE;
  764. }
  765. else if (currentSecurity != ieSecurity)
  766. {
  767. // If the IE security settings have changed, that counts
  768. // as a role status change (b/c it updates TS text).
  769. // NTRAID#NTBUG9-760269-2003/01/07-artm
  770. ieSecurity = currentSecurity;
  771. *result = TRUE;
  772. }
  773. LOG_BOOL(*result);
  774. // CODEWORK:
  775. // the links can change based on the installation of add-ons, even
  776. // if the role has not changed:
  777. // fileserver: sak becomes installed, server mgmt becomes installed
  778. }
  779. while (0);
  780. LOG_HRESULT(hr);
  781. return hr;
  782. }
  783. HRESULT __stdcall
  784. ManageYourServer::IsClusterNode(
  785. /* [retval][out] */ BOOL *result)
  786. {
  787. LOG_FUNCTION(ManageYourServer::IsClusterNode);
  788. ASSERT(result);
  789. HRESULT hr = S_OK;
  790. do
  791. {
  792. if (!result)
  793. {
  794. hr = E_INVALIDARG;
  795. break;
  796. }
  797. *result = IsClusterServer() ? TRUE : FALSE;
  798. LOG_BOOL(*result);
  799. }
  800. while (0);
  801. LOG_HRESULT(hr);
  802. return hr;
  803. }
  804. HRESULT __stdcall
  805. ManageYourServer::IsCurrentUserAnAdministrator(
  806. /* [out, retval] */ BOOL* result)
  807. {
  808. LOG_FUNCTION(ManageYourServer::IsCurrentUserAnAdministrator);
  809. ASSERT(result);
  810. HRESULT hr = S_OK;
  811. do
  812. {
  813. if (!result)
  814. {
  815. hr = E_INVALIDARG;
  816. break;
  817. }
  818. *result = IsCurrentUserAdministrator() ? TRUE : FALSE;
  819. LOG_BOOL(*result);
  820. }
  821. while (0);
  822. LOG_HRESULT(hr);
  823. return hr;
  824. }
  825. HRESULT __stdcall
  826. ManageYourServer::IsSupportedSku(
  827. /* [out, retval] */ BOOL* result)
  828. {
  829. LOG_FUNCTION(ManageYourServer::IsSupportedSku);
  830. ASSERT(result);
  831. HRESULT hr = S_OK;
  832. do
  833. {
  834. if (!result)
  835. {
  836. hr = E_INVALIDARG;
  837. break;
  838. }
  839. *result = ::IsSupportedSku() ? TRUE : FALSE;
  840. LOG_BOOL(*result);
  841. }
  842. while (0);
  843. LOG_HRESULT(hr);
  844. return hr;
  845. }
  846. HRESULT __stdcall
  847. ManageYourServer::IsStartupFlagSet(
  848. /* [out, retval] */ BOOL* result)
  849. {
  850. LOG_FUNCTION(ManageYourServer::IsStartupFlagSet);
  851. ASSERT(result);
  852. HRESULT hr = S_OK;
  853. do
  854. {
  855. if (!result)
  856. {
  857. hr = E_INVALIDARG;
  858. break;
  859. }
  860. *result = ::IsStartupFlagSet();
  861. LOG_BOOL(*result);
  862. }
  863. while (0);
  864. LOG_HRESULT(hr);
  865. return hr;
  866. }
  867. HRESULT __stdcall
  868. ManageYourServer::SetRunAtLogon(
  869. /* [in] */ BOOL newState)
  870. {
  871. LOG_FUNCTION2(
  872. ManageYourServer::SetRunAtLogon,
  873. newState ? L"TRUE" : L"FALSE");
  874. HRESULT hr = S_OK;
  875. do
  876. {
  877. // we only need to set the uplevel flag, since this will only run on an
  878. // uplevel machine.
  879. RegistryKey key;
  880. hr = key.Create(HKEY_CURRENT_USER, SZ_REGKEY_SRVWIZ_ROOT);
  881. BREAK_ON_FAILED_HRESULT2(hr, L"Create key");
  882. hr = key.SetValue(L"", newState ? 1 : 0);
  883. BREAK_ON_FAILED_HRESULT2(hr, L"Set Value");
  884. hr = key.Close();
  885. BREAK_ON_FAILED_HRESULT2(hr, L"Close key");
  886. // NTRAID#NTBUG9-627785-2002/05/22-artm
  887. // Need to update REGTIPS key as well if it exists, o'wise user's setting is potentially
  888. // ignored.
  889. hr = key.Open(HKEY_CURRENT_USER, REGTIPS, KEY_WRITE);
  890. if (SUCCEEDED(hr))
  891. {
  892. hr = key.SetValue(L"Show", newState ? 1 : 0);
  893. // If this failed we still want to remove the obsolete
  894. // key if it exists.
  895. //BREAK_ON_FAILED_HRESULT2(hr, L"Set Tips Value");
  896. }
  897. // attempt to remove the obsolete Win2k value so that it doesn't
  898. // enter into the "should run" equation.
  899. HRESULT hr2 =
  900. Win32ToHresult(
  901. ::SHDeleteValue(HKEY_CURRENT_USER, SZ_REGKEY_W2K, SZ_REGVAL_W2K));
  902. if (FAILED(hr2))
  903. {
  904. // this is not a problem: if the key is not there, fine. If it
  905. // is and we can't remove it, oh well.
  906. LOG(String::format(L"failed to delete win2k value %1!08X!", hr2));
  907. }
  908. }
  909. while (0);
  910. LOG_HRESULT(hr);
  911. return hr;
  912. }
  913. #define WSZ_FILE_SERVMGMT_MSC L"\\administration\\servmgmt.msc"
  914. // NTRAID#NTBUG9-530202-29-Mar-2002-jrowlett
  915. // support needed to check if link is valid
  916. HRESULT __stdcall
  917. ManageYourServer::IsServerManagementConsolePresent(
  918. /* [out, retval] */ BOOL* result)
  919. {
  920. LOG_FUNCTION(ManageYourServer::IsServerManagementConsolePresent);
  921. ASSERT(result);
  922. HRESULT hr = S_OK;
  923. do
  924. {
  925. if (!result)
  926. {
  927. hr = E_INVALIDARG;
  928. break;
  929. }
  930. String serverManagementConsole =
  931. Win::GetSystemDirectory() + WSZ_FILE_SERVMGMT_MSC;
  932. LOG(String::format(
  933. L"Server Management Console = %1",
  934. serverManagementConsole.c_str()));
  935. *result = FS::FileExists(serverManagementConsole) ? TRUE : FALSE;
  936. LOG_BOOL(*result);
  937. }
  938. while (0);
  939. LOG_HRESULT(hr);
  940. return hr;
  941. }
  942. // NTRAID#NTBUG9-602954-29-Apr-2002-jrowlett
  943. // support needed to show or hide check box is the policy is configured and enabled.
  944. HRESULT __stdcall
  945. ManageYourServer::IsShowAtStartupPolicyEnabled(
  946. /* [out, retval] */ BOOL* result)
  947. {
  948. LOG_FUNCTION(ManageYourServer::IsShowAtStartupPolicyEnabled);
  949. ASSERT(result);
  950. HRESULT hr = S_OK;
  951. DWORD dwType = REG_DWORD;
  952. DWORD dwData = 0;
  953. DWORD cbSize = sizeof(dwData);
  954. do
  955. {
  956. if (!result)
  957. {
  958. hr = E_INVALIDARG;
  959. break;
  960. }
  961. // If group policy is set for "Don't show MYS",
  962. // then don't show MYS regardless of user setting
  963. *result = !::ShouldShowMYSAccordingToPolicy();
  964. // failure is interpreted as if the policy is "not configured"
  965. LOG_BOOL(*result);
  966. }
  967. while (0);
  968. LOG_HRESULT(hr);
  969. return hr;
  970. }
  971. // NTRAID#NTBUG9-627875-2002/05/22-artm
  972. // support hiding startup checkbox when running on datacenter servers
  973. HRESULT __stdcall
  974. ManageYourServer::IsDatacenterServer(
  975. /* [out, retval] */ BOOL* result)
  976. {
  977. LOG_FUNCTION(ManageYourServer::IsDatacenterServer);
  978. ASSERT(result);
  979. HRESULT hr = S_OK;
  980. do
  981. {
  982. if (!result)
  983. {
  984. hr = E_INVALIDARG;
  985. break;
  986. }
  987. *result = FALSE;
  988. if (State::GetInstance().GetProductSKU() & CYS_DATACENTER_SERVER)
  989. {
  990. *result = TRUE;
  991. }
  992. LOG_BOOL(*result);
  993. }
  994. while (0);
  995. LOG_HRESULT(hr);
  996. return hr;
  997. }
  998. // NTRAID#NTBUG9-648428-2002/06/25-artm
  999. // support hiding web application server console link if on IA64
  1000. HRESULT __stdcall
  1001. ManageYourServer::IsWebServerConsolePresent(
  1002. /* [out, retval] */ BOOL* result )
  1003. {
  1004. LOG_FUNCTION(ManageYourServer::IsWebServerConsolePresent);
  1005. HRESULT hr = S_OK;
  1006. if (result)
  1007. {
  1008. static String sys32 = Win::GetSystemDirectory();
  1009. static String webmgmtPath = FS::AppendPath(sys32, String::load(IDS_WEB_SERVER_MSC));
  1010. *result = FS::PathExists(webmgmtPath);
  1011. LOG_BOOL(*result);
  1012. }
  1013. else
  1014. {
  1015. ASSERT(false);
  1016. hr = E_INVALIDARG;
  1017. }
  1018. return hr;
  1019. }
  1020. // NTRAID#NTBUG9-632113-2002/07/01-artm
  1021. // support saving collapsed/expanded state of role nodes
  1022. HRESULT __stdcall
  1023. ManageYourServer::CollapseRole(
  1024. /* [in] */ BSTR roleId, /* [in] */ BOOL collapse )
  1025. {
  1026. LOG_FUNCTION(ManageYourServer::CollapseRole);
  1027. ASSERT(roleId);
  1028. HRESULT hr = S_OK;
  1029. do
  1030. {
  1031. RegistryKey key;
  1032. if (!roleId)
  1033. {
  1034. hr = E_INVALIDARG;
  1035. break;
  1036. }
  1037. hr = key.Create(HKEY_CURRENT_USER, SZ_REGKEY_SRVWIZ_ROOT);
  1038. BREAK_ON_FAILED_HRESULT2(hr, L"Create key");
  1039. // Update the collapsed state for the given role.
  1040. hr = key.SetValue(roleId, collapse ? 1 : 0);
  1041. BREAK_ON_FAILED_HRESULT2(hr, L"Set Value");
  1042. hr = key.Close();
  1043. BREAK_ON_FAILED_HRESULT2(hr, L"Close key");
  1044. }
  1045. while (0);
  1046. LOG_HRESULT(hr);
  1047. return hr;
  1048. }
  1049. // NTRAID#NTBUG9-632113-2002/07/01-artm
  1050. // support checking collapsed state of role nodes
  1051. HRESULT __stdcall
  1052. ManageYourServer::IsRoleCollapsed(
  1053. /* [in] */ BSTR roleId, /* [out, retval] */ BOOL* result)
  1054. {
  1055. LOG_FUNCTION(ManageYourServer::IsRoleCollapsed);
  1056. ASSERT(result);
  1057. ASSERT(roleId);
  1058. HRESULT hr = S_OK;
  1059. do // false loop
  1060. {
  1061. if (!result || !roleId)
  1062. {
  1063. hr = E_INVALIDARG;
  1064. break;
  1065. }
  1066. DWORD data = 0;
  1067. *result = FALSE;
  1068. // The role is only collapsed if it has a non-zero saved value.
  1069. bool regResult =
  1070. GetRegKeyValue(
  1071. SZ_REGKEY_SRVWIZ_ROOT,
  1072. roleId,
  1073. data,
  1074. HKEY_CURRENT_USER);
  1075. if (regResult && (data != 0))
  1076. {
  1077. *result = TRUE;
  1078. }
  1079. } while(0);
  1080. LOG_HRESULT(hr);
  1081. return hr;
  1082. }
  1083. // NTRAID#NTBUG9-680200-2002/08/01-artm
  1084. // Support retrieving working area of the display.
  1085. //
  1086. // Area info is returned as a comma separated string b/c JScript does not
  1087. // support getting back SAFEARRAY's.
  1088. //
  1089. // e.g. "0,0,800,600" --> working area is 800 wide, 600 high, and starts at
  1090. // screen position (0,0)
  1091. HRESULT __stdcall
  1092. ManageYourServer::GetWorkingAreaInfo(
  1093. /* [out, retval] */ BSTR* info)
  1094. {
  1095. LOG_FUNCTION(ManageYourServer::GetDisplayWorkingArea);
  1096. if (!info)
  1097. {
  1098. ASSERT(NULL != info);
  1099. return E_INVALIDARG;
  1100. }
  1101. HRESULT hr = S_OK;
  1102. *info = NULL;
  1103. do // false loop
  1104. {
  1105. static const String AREA_FORMAT_STRING = L"%1!d!,%2!d!,%3!d!,%4!d!";
  1106. // Get the area info from the system.
  1107. RECT area;
  1108. ::ZeroMemory(&area, sizeof(RECT));
  1109. BOOL success = SystemParametersInfo(
  1110. SPI_GETWORKAREA,
  1111. 0,
  1112. &area,
  1113. 0);
  1114. if (!success)
  1115. {
  1116. hr = HRESULT_FROM_WIN32(GetLastError());
  1117. break;
  1118. }
  1119. // Copy the area info to the return parameter.
  1120. String result;
  1121. try
  1122. {
  1123. // The (right, bottom) point of the area is not
  1124. // inclusive. In other words, if we get back
  1125. // (0, 0) and (800, 600), the point (800, 600)
  1126. // should not be considered to be in the display
  1127. // area. If it was the width and height would
  1128. // actually be 801 and 601, respectively.
  1129. result = String::format(
  1130. AREA_FORMAT_STRING,
  1131. area.left,
  1132. area.top,
  1133. area.right - area.left, // width
  1134. area.bottom - area.top); // height
  1135. }
  1136. catch (const std::bad_alloc&)
  1137. {
  1138. hr = E_OUTOFMEMORY;
  1139. }
  1140. if (FAILED(hr))
  1141. {
  1142. break;
  1143. }
  1144. *info = ::SysAllocString(result.c_str());
  1145. if (NULL == *info)
  1146. {
  1147. hr = E_OUTOFMEMORY;
  1148. break;
  1149. }
  1150. }
  1151. while(false);
  1152. LOG_HRESULT(hr);
  1153. return hr;
  1154. }