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.

2440 lines
54 KiB

  1. /*++
  2. Copyright (c) 1994-2000 Microsoft Corporation
  3. Module Name :
  4. iismachine.cpp
  5. Abstract:
  6. IIS Machine node
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Sergei Antonov (sergeia)
  10. Project:
  11. Internet Services Manager
  12. Revision History:
  13. 10/28/2000 sergeia Split from iisobj.cpp
  14. --*/
  15. #include "stdafx.h"
  16. #include "common.h"
  17. #include "inetprop.h"
  18. #include "InetMgrApp.h"
  19. #include "supdlgs.h"
  20. #include "connects.h"
  21. #include "metaback.h"
  22. #include "iisobj.h"
  23. #include "shutdown.h"
  24. #include "machsht.h"
  25. #include "w3sht.h"
  26. #include "fltdlg.h"
  27. #include "savedata.h"
  28. #include "util.h"
  29. #include "tracker.h"
  30. #include "iishelp.h"
  31. #ifdef _DEBUG
  32. #undef THIS_FILE
  33. static char BASED_CODE THIS_FILE[] = __FILE__;
  34. #endif
  35. #define new DEBUG_NEW
  36. extern CPropertySheetTracker g_OpenPropertySheetTracker;
  37. extern CWNetConnectionTrackerGlobal g_GlobalConnections;
  38. extern CInetmgrApp theApp;
  39. #if defined(_DEBUG) || DBG
  40. extern CDebug_IISObject g_Debug_IISObject;
  41. #endif
  42. extern DWORD g_dwInetmgrParamFlags;
  43. DWORD WINAPI CIISMachine::GetProcessModeThread(LPVOID pInfo)
  44. {
  45. CError err(ERROR_NOT_FOUND);
  46. GET_PROCESS_MODE_STRUCT * pMyStructOfInfo = (GET_PROCESS_MODE_STRUCT *) pInfo;
  47. //
  48. // This thread needs its own CoInitialize
  49. //
  50. CoInitialize(NULL);
  51. // Do the work
  52. CIISAppPool pool(pMyStructOfInfo->pComAuthInfo, (LPCTSTR) _T("LM/W3SVC"));
  53. DWORD dwProcessMode = -1;
  54. pMyStructOfInfo->dwProcessMode = dwProcessMode;
  55. err = pool.GetProcessMode(&dwProcessMode);
  56. if (err.Succeeded())
  57. {
  58. pMyStructOfInfo->dwProcessMode = dwProcessMode;
  59. }
  60. pMyStructOfInfo->dwReturnStatus = err;
  61. return err;
  62. }
  63. BOOL CIISMachine::GetProcessMode(GET_PROCESS_MODE_STRUCT * pMyStructOfInfo)
  64. {
  65. BOOL bReturn = FALSE;
  66. DWORD ThreadID = 0;
  67. DWORD status = 0;
  68. HANDLE hMyThread = ::CreateThread(NULL,0,GetProcessModeThread,pMyStructOfInfo,0,&ThreadID);
  69. if (hMyThread)
  70. {
  71. // wait for 10 secs only
  72. DWORD res = WaitForSingleObject(hMyThread,10*1000);
  73. if (res == WAIT_TIMEOUT)
  74. {
  75. GetExitCodeThread(hMyThread, &status);
  76. if (status == STILL_ACTIVE)
  77. {
  78. if (hMyThread != NULL)
  79. {TerminateThread(hMyThread, 0);}
  80. }
  81. }
  82. else
  83. {
  84. GetExitCodeThread(hMyThread, &status);
  85. if (status == STILL_ACTIVE)
  86. {
  87. if (hMyThread != NULL)
  88. {TerminateThread(hMyThread, 0);}
  89. }
  90. else
  91. {
  92. if (ERROR_SUCCESS == status)
  93. {
  94. bReturn = TRUE;
  95. }
  96. }
  97. if (hMyThread != NULL)
  98. {CloseHandle(hMyThread);}
  99. }
  100. }
  101. return bReturn;
  102. }
  103. /* static */ LPOLESTR CIISMachine::_cszNodeName = _T("LM");
  104. /* static */ CComBSTR CIISMachine::_bstrYes;
  105. /* static */ CComBSTR CIISMachine::_bstrNo;
  106. /* static */ CComBSTR CIISMachine::_bstrVersionFmt;
  107. /* static */ BOOL CIISMachine::_fStaticsLoaded = FALSE;
  108. //
  109. // Define result view for machine objects
  110. //
  111. /* static */ int CIISMachine::_rgnLabels[COL_TOTAL] =
  112. {
  113. IDS_RESULT_COMPUTER_NAME,
  114. IDS_RESULT_COMPUTER_LOCAL,
  115. IDS_RESULT_COMPUTER_VERSION,
  116. IDS_RESULT_STATUS,
  117. };
  118. /* static */ int CIISMachine::_rgnWidths[COL_TOTAL] =
  119. {
  120. 200,
  121. 50,
  122. //100,
  123. 150,
  124. 200,
  125. };
  126. /* static */
  127. void
  128. CIISMachine::InitializeHeaders(
  129. LPHEADERCTRL lpHeader
  130. )
  131. {
  132. BuildResultView(lpHeader, COL_TOTAL, _rgnLabels, _rgnWidths);
  133. if (!_fStaticsLoaded)
  134. {
  135. _fStaticsLoaded =
  136. _bstrYes.LoadString(IDS_YES) &&
  137. _bstrNo.LoadString(IDS_NO) &&
  138. _bstrVersionFmt.LoadString(IDS_VERSION_FMT);
  139. }
  140. }
  141. /* virtual */
  142. void
  143. CIISMachine::InitializeChildHeaders(
  144. LPHEADERCTRL lpHeader
  145. )
  146. {
  147. CIISService::InitializeHeaders(lpHeader);
  148. }
  149. /* static */
  150. HRESULT
  151. CIISMachine::VerifyMachine(
  152. CIISMachine *& pMachine
  153. )
  154. /*++
  155. Routine Description:
  156. Create the interface on the given machine object.
  157. Arguments:
  158. CIISMachine *& pMachine : Machine object
  159. BOOL fAskBeforeRedirecting
  160. Return Value:
  161. HRESULT
  162. Notes:
  163. THe CIISMachine object pass in may refer to the cluster master
  164. on return.
  165. --*/
  166. {
  167. CError err;
  168. if (pMachine)
  169. {
  170. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  171. CWaitCursor wait;
  172. //
  173. // Attempt to create the interface to ensure the machine
  174. // contains a metabase.
  175. //
  176. err = pMachine->CreateInterface(FALSE);
  177. }
  178. return err;
  179. }
  180. CIISMachine::CIISMachine(
  181. IConsoleNameSpace * pConsoleNameSpace,
  182. IConsole * pConsole,
  183. CComAuthInfo * pAuthInfo,
  184. CIISRoot * pRoot
  185. )
  186. : m_pInterface(NULL),
  187. m_bstrDisplayName(NULL),
  188. m_auth(pAuthInfo),
  189. m_pRootExt(pRoot),
  190. m_err(),
  191. //
  192. // By default we assume the password is entered.
  193. // If this machine object is constructed from the
  194. // cache, it will get reset by InitializeFromStream()
  195. //
  196. m_fPasswordEntered(TRUE),
  197. m_dwVersion(MAKELONG(5, 0)), // Assume as a default
  198. m_pAppPoolsContainer(NULL),
  199. m_pWebServiceExtensionContainer(NULL),
  200. CIISMBNode(this, _cszNodeName),
  201. m_MachineWNetConnections(&g_GlobalConnections)
  202. {
  203. //
  204. // Load one-liner error messages
  205. //
  206. SetErrorOverrides(m_err, TRUE);
  207. SetDisplayName();
  208. SetConsoleData(pConsoleNameSpace,pConsole);
  209. m_fIsLocalHostIP = FALSE;
  210. m_fLocalHostIPChecked = FALSE;
  211. }
  212. CIISMachine::~CIISMachine()
  213. /*++
  214. Routine Description:
  215. Destructor
  216. Arguments:
  217. N/A
  218. Return Value:
  219. N/A
  220. --*/
  221. {
  222. if (m_bstrDisplayName)
  223. {
  224. ::SysFreeString(m_bstrDisplayName);
  225. }
  226. // Disconnect all connections made from this iismachine.
  227. m_MachineWNetConnections.Clear();
  228. SAFE_DELETE(m_pInterface);
  229. }
  230. /* static */
  231. HRESULT
  232. CIISMachine::ReadFromStream(
  233. IStream * pStream,
  234. CIISMachine ** ppMachine,
  235. IConsoleNameSpace * pConsoleNameSpace,
  236. IConsole * pConsole
  237. )
  238. /*++
  239. Routine Description:
  240. Static helper function to allocate a new CIISMachine object read
  241. from the storage stream.
  242. Arguments:
  243. IStream * pStream : Stream to read from
  244. CIISMachine ** ppMachine : Returns CIISMachine object
  245. Return Value:
  246. HRESULT
  247. --*/
  248. {
  249. CComBSTR strMachine, strUser;
  250. ASSERT_WRITE_PTR(ppMachine);
  251. ASSERT_READ_WRITE_PTR(pStream);
  252. CError err;
  253. *ppMachine = NULL;
  254. do
  255. {
  256. err = strMachine.ReadFromStream(pStream);
  257. BREAK_ON_ERR_FAILURE(err);
  258. err = strUser.ReadFromStream(pStream);
  259. BREAK_ON_ERR_FAILURE(err);
  260. *ppMachine = new CIISMachine(pConsoleNameSpace,pConsole,CComAuthInfo(strMachine, strUser));
  261. if (!*ppMachine)
  262. {
  263. err = ERROR_NOT_ENOUGH_MEMORY;
  264. break;
  265. }
  266. err = (*ppMachine)->InitializeFromStream(pStream);
  267. }
  268. while(FALSE);
  269. return err;
  270. }
  271. HRESULT
  272. CIISMachine::WriteToStream(
  273. IStream * pStgSave
  274. )
  275. /*++
  276. Routine Description:
  277. Write machine information to stream.
  278. Arguments:
  279. IStream * pStgSave : Open stream
  280. Return Value:
  281. HRESULT
  282. Notes:
  283. Be sure to keep this information in sync with CIISMachine::InitializeFromStream()
  284. --*/
  285. {
  286. ASSERT_READ_WRITE_PTR(pStgSave);
  287. CComBSTR bstrServerName(m_auth.QueryServerName());
  288. CComBSTR bstrUserName(m_auth.QueryUserName());
  289. CError err;
  290. ULONG cb;
  291. do
  292. {
  293. err = bstrServerName.WriteToStream(pStgSave);
  294. BREAK_ON_ERR_FAILURE(err);
  295. err = bstrUserName.WriteToStream(pStgSave);
  296. BREAK_ON_ERR_FAILURE(err);
  297. //
  298. // Now cache the dynamically-generated information, such
  299. // as version number, snapin status etc. This will be
  300. // displayed in the result view before the interface is
  301. // created.
  302. //
  303. err = pStgSave->Write(&m_dwVersion, sizeof(m_dwVersion), &cb);
  304. BREAK_ON_ERR_FAILURE(err);
  305. }
  306. while(FALSE);
  307. return err;
  308. }
  309. HRESULT
  310. CIISMachine::InitializeFromStream(
  311. IStream * pStream
  312. )
  313. /*++
  314. Routine Description:
  315. Read version number and other cached parameters that will
  316. be overridden at runtime when the interface is created.
  317. This is cached, because it's required before the interface
  318. is created.
  319. Arguments:
  320. IStream * pStream : Open stream
  321. Return Value:
  322. HRESULT
  323. Notes:
  324. Be sure to keep this information in sync with CIISMachine::WriteToStream()
  325. --*/
  326. {
  327. ASSERT_READ_PTR(pStream);
  328. CError err;
  329. ULONG cb;
  330. //
  331. // Passwords are never cached. IIS status will
  332. // always be verified when the actual interface
  333. // is created.
  334. //
  335. m_fPasswordEntered = FALSE;
  336. //
  337. // Version number
  338. //
  339. err = pStream->Read(&m_dwVersion, sizeof(m_dwVersion), &cb);
  340. return err;
  341. }
  342. void
  343. CIISMachine::SetDisplayName()
  344. /*++
  345. Routine Description:
  346. Create a special display name for this machine object if it's
  347. either the local machine, or
  348. --*/
  349. {
  350. CString fmt;
  351. if (IsLocal())
  352. {
  353. //
  354. // Use the local computer name, and not the name
  355. // that's on the server object, because that could
  356. // be and ip address or "localhost".
  357. //
  358. TCHAR szLocalServer[MAX_PATH + 1];
  359. DWORD dwSize = MAX_PATH;
  360. VERIFY(::GetComputerName(szLocalServer, &dwSize));
  361. fmt.Format(IDS_LOCAL_COMPUTER, szLocalServer);
  362. }
  363. else
  364. {
  365. //
  366. // No special display name necessary
  367. //
  368. m_bstrDisplayName = NULL;
  369. return;
  370. }
  371. m_bstrDisplayName = ::SysAllocStringLen(fmt, fmt.GetLength());
  372. TRACEEOLID("Machine display name: " << m_bstrDisplayName);
  373. }
  374. LPOLESTR
  375. CIISMachine::QueryDisplayName()
  376. /*++
  377. Routine Description:
  378. Get the display name for the machine/cluster object
  379. Arguments:
  380. None
  381. Return Value:
  382. Display Name
  383. --*/
  384. {
  385. if (m_pRootExt != NULL)
  386. return m_pRootExt->QueryDisplayName();
  387. else
  388. return m_bstrDisplayName ? m_bstrDisplayName : QueryServerName();
  389. }
  390. int
  391. CIISMachine::QueryImage() const
  392. /*++
  393. Routine Description:
  394. Return machine bitmap index appropriate for the current
  395. state of this machine object.
  396. Arguments:
  397. None
  398. Return Value:
  399. Bitmap index
  400. --*/
  401. {
  402. if (m_pRootExt != NULL)
  403. {
  404. return m_pRootExt->QueryImage();
  405. }
  406. else
  407. {
  408. if (m_err.Failed())
  409. {
  410. return IsLocal() ? iLocalMachineErr : iMachineErr;
  411. }
  412. else
  413. {
  414. return IsLocal() ? iLocalMachine : iMachine;
  415. }
  416. }
  417. }
  418. HRESULT
  419. CIISMachine::CreateInterface(
  420. BOOL fShowError
  421. )
  422. /*++
  423. Routine Description:
  424. Create the interface. If the interface is already created, recreate it.
  425. Arguments:
  426. BOOL fShowError : TRUE to display error messages
  427. Return Value:
  428. HRESULT
  429. Notes:
  430. This function is deliberately NOT called from the constructor for performance
  431. reasons.
  432. --*/
  433. {
  434. CError err;
  435. BOOL bHasInterface = FALSE;
  436. bHasInterface = HasInterface();
  437. if (bHasInterface)
  438. {
  439. //
  440. // Recreate the interface (this should re-use the impersonation)
  441. //
  442. TRACEEOLID("Warning: Rebinding existing interface.");
  443. err = m_pInterface->Regenerate();
  444. }
  445. else
  446. {
  447. //
  448. // Create new interface
  449. //
  450. m_pInterface = new CMetaKey(&m_auth);
  451. err = m_pInterface
  452. ? m_pInterface->QueryResult()
  453. : ERROR_NOT_ENOUGH_MEMORY;
  454. }
  455. if (err.Succeeded())
  456. {
  457. //
  458. // Load its display parameters
  459. //
  460. err = RefreshData();
  461. if (bHasInterface)
  462. {
  463. // Do extra stuff if we regenerated an existing interface...
  464. }
  465. CMetabasePath path;
  466. err = DetermineIfAdministrator(
  467. m_pInterface,
  468. path,
  469. &m_fIsAdministrator,
  470. &m_dwMetabaseSystemChangeNumber
  471. );
  472. // Set the latest system change number.
  473. RefreshMetabaseSystemChangeNumber();
  474. }
  475. if (err.Failed())
  476. {
  477. if (fShowError)
  478. {
  479. CWnd * pWnd = GetMainWindow(GetConsole());
  480. DisplayError(err,pWnd ? pWnd->m_hWnd : NULL);
  481. }
  482. //
  483. // Kill bogus interface
  484. //
  485. SAFE_DELETE(m_pInterface);
  486. }
  487. return err;
  488. }
  489. /* virtual */
  490. int
  491. CIISMachine::CompareScopeItem(
  492. CIISObject * pObject
  493. )
  494. /*++
  495. Routine Description:
  496. Compare against another CIISMachine object.
  497. Arguments:
  498. CIISObject * pObject : Object to compare against
  499. Return Value:
  500. 0 if the two objects are identical
  501. <0 if this object is less than pObject
  502. >0 if this object is greater than pObject
  503. --*/
  504. {
  505. ASSERT_READ_PTR(pObject);
  506. //
  507. // First criteria is object type
  508. //
  509. int n1 = QuerySortWeight();
  510. int n2 = pObject->QuerySortWeight();
  511. if (n1 != n2)
  512. {
  513. return n1 - n2;
  514. }
  515. //
  516. // pObject is a CIISMachine object (same sortweight)
  517. //
  518. CIISMachine * pMachine = (CIISMachine *)pObject;
  519. //
  520. // Next sort on local key (local sorts before non-local)
  521. //
  522. n1 = IsLocal() ? 0 : 1;
  523. n2 = pMachine->IsLocal() ? 0 : 1;
  524. if (n1 != n2)
  525. {
  526. return n1 - n2;
  527. }
  528. if (!n1 && !n2)
  529. {
  530. //
  531. // This is the local machine, even if the name is different
  532. //
  533. return 0;
  534. }
  535. //
  536. // Else sort on name.
  537. //
  538. return _tcsicmp(QueryServerName(), pMachine->QueryServerName());
  539. }
  540. BOOL
  541. CIISMachine::SetCacheDirty()
  542. /*++
  543. Routine Description:
  544. Set the cache as dirty
  545. Arguments:
  546. None
  547. Return Value:
  548. TRUE for success, FALSE if the cache was not found
  549. --*/
  550. {
  551. ASSERT(m_pRootExt == NULL);
  552. //
  553. // Cache is stored at the root object
  554. //
  555. CIISRoot * pRoot = GetRoot();
  556. ASSERT_PTR(pRoot);
  557. if (pRoot)
  558. {
  559. pRoot->m_scServers.SetDirty();
  560. return TRUE;
  561. }
  562. return FALSE;
  563. }
  564. int
  565. CIISMachine::ResolvePasswordFromCache()
  566. /*++
  567. Routine Description:
  568. Look through the machine cache for machines with the same username
  569. as this object. If they have a password entered, grab it.
  570. Arguments:
  571. None
  572. Return Value:
  573. TRUE if a machine with the same username was found whose password
  574. we stole. FALSE otherwise.
  575. --*/
  576. {
  577. BOOL fUpdated = FALSE;
  578. //
  579. // Doesn't make sense if this machine object doesn't use impersonation
  580. // or already has a password.
  581. //
  582. ASSERT(UsesImpersonation() && !PasswordEntered());
  583. CIISRoot * pRoot = GetRoot();
  584. ASSERT_PTR(pRoot);
  585. if (pRoot)
  586. {
  587. CIISMachine * pMachine = pRoot->m_scServers.GetFirst();
  588. while(pMachine)
  589. {
  590. if (pMachine->UsesImpersonation() && pMachine->PasswordEntered())
  591. {
  592. if (!_tcsicmp(QueryUserName(), pMachine->QueryUserName()))
  593. {
  594. TRACEEOLID("Swiping cached password from " << pMachine->QueryServerName());
  595. StorePassword(pMachine->QueryPassword());
  596. ++fUpdated;
  597. break;
  598. }
  599. }
  600. pMachine = pRoot->m_scServers.GetNext();
  601. }
  602. }
  603. return fUpdated;
  604. }
  605. HRESULT
  606. CIISMachine::Impersonate(
  607. LPCTSTR szUserName,
  608. LPCTSTR szPassword
  609. )
  610. /*++
  611. Routine Description:
  612. Set and store proxy blanket security information. Store username/password
  613. for use by metaback and other interfaces.
  614. Arguments:
  615. LPCTSTR szUserName : Username (domain\username)
  616. LPCTSTR szPassword : Password
  617. Return Value:
  618. None
  619. --*/
  620. {
  621. ASSERT_READ_PTR(szUserName);
  622. CError err;
  623. if (m_pInterface)
  624. {
  625. //
  626. // Already have an interface created; Change the
  627. // the security blanket.
  628. //
  629. err = m_pInterface->ChangeProxyBlanket(szUserName, szPassword);
  630. }
  631. if (err.Succeeded())
  632. {
  633. //
  634. // Store new username/password
  635. //
  636. m_auth.SetImpersonation(szUserName, szPassword);
  637. m_fPasswordEntered = TRUE;
  638. }
  639. return err;
  640. }
  641. void
  642. CIISMachine::RemoveImpersonation()
  643. /*++
  644. Routine Description:
  645. Remove impersonation parameters. Destroy any existing interface.
  646. Arguments:
  647. None
  648. Return Value:
  649. N/A
  650. --*/
  651. {
  652. m_auth.RemoveImpersonation();
  653. m_fPasswordEntered = FALSE;
  654. SAFE_DELETE(m_pInterface);
  655. }
  656. void
  657. CIISMachine::StorePassword(
  658. LPCTSTR szPassword
  659. )
  660. /*++
  661. Routine Description:
  662. Store password.
  663. Arguments:
  664. LPCTSTR szPassword : Password
  665. Return Value:
  666. None
  667. --*/
  668. {
  669. ASSERT_READ_PTR(szPassword);
  670. m_auth.StorePassword(szPassword);
  671. m_fPasswordEntered = TRUE;
  672. }
  673. BOOL
  674. CIISMachine::ResolveCredentials()
  675. /*++
  676. Routine Description:
  677. If this machine object uses impersonation, but hasn't entered a password
  678. yet, check to see if there are any other machines in the cache with the
  679. same username and grab its password. If not, prompt the user for it.
  680. Arguments:
  681. None
  682. Return Value:
  683. TRUE if a password was entered. FALSE otherwise.
  684. --*/
  685. {
  686. BOOL fPasswordEntered = FALSE;
  687. if (UsesImpersonation() && !PasswordEntered())
  688. {
  689. //
  690. // Attempt to find the password from the cache
  691. //
  692. if (!ResolvePasswordFromCache())
  693. {
  694. //
  695. // Didn't find the password in the cache. Prompt
  696. // the user for it.
  697. //
  698. CLoginDlg dlg(LDLG_ENTER_PASS, this, GetMainWindow(GetConsole()));
  699. if (dlg.DoModal() == IDOK)
  700. {
  701. fPasswordEntered = TRUE;
  702. if (dlg.UserNameChanged())
  703. {
  704. //
  705. // User name has changed -- remember to
  706. // save the machine cache later.
  707. //
  708. SetCacheDirty();
  709. }
  710. }
  711. else
  712. {
  713. //
  714. // Pressing cancel on this dialog means the user
  715. // wants to stop using impersonation.
  716. //
  717. RemoveImpersonation();
  718. SetCacheDirty();
  719. }
  720. }
  721. }
  722. return fPasswordEntered;
  723. }
  724. BOOL
  725. CIISMachine::HandleAccessDenied(
  726. CError & err
  727. )
  728. /*++
  729. Routine Description:
  730. After calling interface method, pass the error object to this function
  731. to handle the access denied case. If the error is access denied,
  732. give the user a chance to change credentials. Since we assume an
  733. attempt has been made to create an interface at least -- the interface
  734. will be recreated with the new credentials.
  735. Arguments:
  736. CError & err : Error object. Checked for ACCESS_DENIED on entry,
  737. will contain new error code on exit if the interface
  738. was recreated.
  739. Return Value:
  740. TRUE if new credentials were applied
  741. --*/
  742. {
  743. BOOL fPasswordEntered = FALSE;
  744. //
  745. // If access denied occurs here -- give another chance
  746. // at entering the password.
  747. //
  748. if (err.Win32Error() == ERROR_ACCESS_DENIED)
  749. {
  750. CLoginDlg dlg(LDLG_ACCESS_DENIED, this, GetMainWindow(GetConsole()));
  751. if (dlg.DoModal() == IDOK)
  752. {
  753. fPasswordEntered = TRUE;
  754. err.Reset();
  755. if (!HasInterface())
  756. {
  757. //
  758. // If we already had an interface, the login dialog
  759. // will have applied the new security blanket.
  760. // If we didn't have an interface, it needs to be
  761. // recreated with the new security blanket.
  762. //
  763. CWaitCursor wait;
  764. err = CreateInterface(FALSE);
  765. }
  766. }
  767. }
  768. return fPasswordEntered;
  769. }
  770. HRESULT
  771. CIISMachine::CheckCapabilities()
  772. /*++
  773. Routine Description:
  774. Load the capabilities information for this server.
  775. Arguments:
  776. None
  777. Return Value:
  778. HRESULT
  779. --*/
  780. {
  781. CError err = AssureInterfaceCreated(TRUE);
  782. if (err.Succeeded())
  783. {
  784. //
  785. // Fetch capability bits and version numbers.
  786. //
  787. CString strMDInfo;
  788. CMetabasePath::GetServiceInfoPath(_T(""), strMDInfo,SZ_MBN_WEB);
  789. //
  790. // Reuse existing interface we have lying around.
  791. //
  792. CMetaKey mk(m_pInterface);
  793. err = mk.QueryResult();
  794. if (err.Succeeded())
  795. {
  796. if (FAILED(mk.DoesPathExist(strMDInfo)))
  797. {
  798. CMetabasePath::GetServiceInfoPath(_T(""),strMDInfo,SZ_MBN_FTP);
  799. if (FAILED(mk.DoesPathExist(strMDInfo)))
  800. {
  801. CMetabasePath::GetServiceInfoPath(_T(""),strMDInfo,SZ_MBN_SMTP);
  802. if (FAILED(mk.DoesPathExist(strMDInfo)))
  803. {
  804. CMetabasePath::GetServiceInfoPath(_T(""),strMDInfo,SZ_MBN_NNTP);
  805. if (FAILED(mk.DoesPathExist(strMDInfo)))
  806. {
  807. TRACEEOLID("No services exist:W3SVC,MSFTPSVC,SMTPSVC,NNTPSVC");
  808. }
  809. }
  810. }
  811. }
  812. }
  813. //if (m_pInterface)
  814. {
  815. CServerCapabilities sc(m_pInterface, strMDInfo);
  816. err = sc.LoadData();
  817. if (err.Succeeded())
  818. {
  819. DWORD dwVersion = sc.QueryMajorVersion();
  820. if (dwVersion)
  821. {
  822. m_dwVersion = dwVersion | (sc.QueryMinorVersion() << SIZE_IN_BITS(WORD));
  823. }
  824. m_fCanAddInstance = sc.HasMultipleSites();
  825. m_fHas10ConnectionsLimit = sc.Has10ConnectionLimit();
  826. m_fIsWorkstation = sc.IsWorkstation();
  827. m_fIsPerformanceConfigurable = sc.IsPerformanceConfigurable();
  828. m_fIsServiceLevelConfigurable = sc.IsServiceLevelConfigurable();
  829. }
  830. }
  831. }
  832. return err;
  833. }
  834. /* virtual */
  835. HRESULT
  836. CIISMachine::RefreshData()
  837. /*++
  838. Routine Description:
  839. Refresh relevant configuration data required for display.
  840. Arguments:
  841. None
  842. Return Value:
  843. HRESULT
  844. --*/
  845. {
  846. CError err;
  847. IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
  848. // Check if we have a valid connection to the metabase
  849. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,METADATA_MASTER_ROOT_HANDLE);
  850. if (err.Succeeded())
  851. {
  852. //
  853. // Check capability and version information.
  854. //
  855. err = CheckCapabilities();
  856. SetDisplayName();
  857. if (err.Succeeded())
  858. {
  859. // check if we should be showing the App Pools node...
  860. if (QueryMajorVersion() >= 6)
  861. {
  862. BOOL fCompatMode = FALSE;
  863. CMetabasePath path(TRUE, SZ_MBN_WEB);
  864. CMetaKey mk(QueryAuthInfo(), path, METADATA_PERMISSION_READ);
  865. err = mk.QueryResult();
  866. if (err.Succeeded())
  867. {
  868. err = mk.QueryValue(MD_GLOBAL_STANDARD_APP_MODE_ENABLED, fCompatMode);
  869. }
  870. // If we fail here, then we have no Web service or no standard mode property defined
  871. // That means that we are either not in standard mode or it doesn't matter
  872. err.Reset();
  873. // Loop thru the scope items to see what we actually have displayed...
  874. CIISMBNode * pBadGuy = NULL;
  875. CIISService * pWebService = NULL;
  876. HSCOPEITEM hChild = NULL, hCurrent;
  877. LONG_PTR cookie = 0;
  878. BOOL bAppPoolsNodeExists = FALSE;
  879. HSCOPEITEM hScope = QueryScopeItem();
  880. if (hScope)
  881. {
  882. HRESULT hr = pConsoleNameSpace->GetChildItem(hScope, &hChild, &cookie);
  883. while (SUCCEEDED(hr) && hChild != NULL)
  884. {
  885. CIISMBNode * pNode = (CIISMBNode *)cookie;
  886. if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cAppPoolsNode))
  887. {
  888. pBadGuy = pNode;
  889. bAppPoolsNodeExists = TRUE;
  890. // Check if the Application Node container exists...
  891. // if it does, then make sure we're in the right mode.
  892. }
  893. else
  894. {
  895. if (0 == _tcsicmp(pNode->GetNodeName(), SZ_MBN_WEB))
  896. {
  897. pWebService = (CIISService *) pNode;
  898. }
  899. }
  900. hCurrent = hChild;
  901. hr = pConsoleNameSpace->GetNextItem(hCurrent, &hChild, &cookie);
  902. }
  903. if (pWebService)
  904. {
  905. // do this check only if we have a W3SVC service
  906. // that's because if the user only installed FTP
  907. // we won't have the interface required for AppPool (WAM interface)
  908. // and this may potential AV!!!!
  909. //
  910. // Find out what mode IIS is R-E-A-L-L-Y running as...
  911. GET_PROCESS_MODE_STRUCT MyStructOfInfo;
  912. MyStructOfInfo.pComAuthInfo = QueryAuthInfo();
  913. MyStructOfInfo.dwReturnStatus = 0;
  914. MyStructOfInfo.dwProcessMode = -1;
  915. if (GetProcessMode(&MyStructOfInfo))
  916. {
  917. // We got it back in time (no timeout)
  918. if (-1 != MyStructOfInfo.dwProcessMode)
  919. {
  920. fCompatMode = FALSE;
  921. if (0 == MyStructOfInfo.dwProcessMode)
  922. {
  923. fCompatMode = TRUE;
  924. }
  925. TRACEEOLID("GetProcessMode:" << MyStructOfInfo.dwProcessMode);
  926. }
  927. }
  928. else
  929. {
  930. // Leave it at whatever we got from the metabase...
  931. }
  932. }
  933. // fCompatMode = 1 means there should be No App Pools (bAppPoolsNodeExists should be 0)
  934. // fCompatMode = 0 means there should be App Pools (bAppPoolsNodeExists should be 1)
  935. TRACEEOLID("fCompatMode:" << fCompatMode);
  936. if (fCompatMode == bAppPoolsNodeExists)
  937. {
  938. if (fCompatMode && bAppPoolsNodeExists)
  939. {
  940. // find it and delete it.
  941. if (pBadGuy->IsMyPropertySheetOpen())
  942. {
  943. // don't remove it if the property sheet is open on it.
  944. }
  945. else
  946. {
  947. pBadGuy->RemoveScopeItem();
  948. }
  949. }
  950. else if (!fCompatMode && !bAppPoolsNodeExists)
  951. {
  952. if (pWebService)
  953. {
  954. m_pAppPoolsContainer = NULL;
  955. CAppPoolsContainer * pPools = new CAppPoolsContainer(this, pWebService);
  956. if (pPools)
  957. {
  958. // Insert pools container before Web Services node
  959. pPools->AddRef();
  960. pPools->AddToScopePane(pWebService->QueryScopeItem(), FALSE, TRUE);
  961. m_pAppPoolsContainer = pPools;
  962. }
  963. }
  964. }
  965. }
  966. }
  967. }
  968. }
  969. }
  970. #if defined(_DEBUG) || DBG
  971. //DumpAllScopeItems(pConsoleNameSpace,m_hScopeItem,0);
  972. #endif
  973. return err;
  974. }
  975. /* virtual */
  976. void
  977. CIISMachine::SetInterfaceError(
  978. HRESULT hr
  979. )
  980. /*++
  981. Routine Description:
  982. Set the interface error. If different from current error,
  983. change the display icon
  984. Arguments:
  985. HRESULT hr : Error code (S_OK is acceptable)
  986. Return Value:
  987. None
  988. --*/
  989. {
  990. if (m_err.HResult() != hr)
  991. {
  992. //
  993. // Change to error/machine icon for the parent machine.
  994. //
  995. m_err = hr;
  996. RefreshDisplay();
  997. }
  998. }
  999. /* virtual */
  1000. HRESULT
  1001. CIISMachine::BuildMetaPath(
  1002. CComBSTR & bstrPath
  1003. ) const
  1004. /*++
  1005. Routine Description:
  1006. Recursively build up the metabase path from the current node
  1007. and its parents
  1008. Arguments:
  1009. CComBSTR & bstrPath : Returns metabase path
  1010. Return Value:
  1011. HRESULT
  1012. --*/
  1013. {
  1014. //
  1015. // This starts off the path
  1016. //
  1017. bstrPath.Append(_cszSeparator);
  1018. bstrPath.Append(QueryNodeName());
  1019. return S_OK;
  1020. }
  1021. /* virtual */
  1022. HRESULT
  1023. CIISMachine::BuildURL(
  1024. CComBSTR & bstrURL
  1025. ) const
  1026. /*++
  1027. Routine Description:
  1028. Recursively build up the URL from the current node
  1029. and its parents. The URL built up from a machine node
  1030. doesn't make a lot of sense, but for want of anything better,
  1031. this will bring up the default web site.
  1032. Arguments:
  1033. CComBSTR & bstrURL : Returns URL
  1034. Return Value:
  1035. HRESULT
  1036. --*/
  1037. {
  1038. CString strOwner;
  1039. if (IsLocal())
  1040. {
  1041. //
  1042. // Security reasons restrict this to "localhost" oftentimes
  1043. //
  1044. strOwner = _bstrLocalHost;
  1045. }
  1046. else
  1047. {
  1048. LPOLESTR lpOwner = QueryMachineName();
  1049. strOwner = PURE_COMPUTER_NAME(lpOwner);
  1050. }
  1051. //
  1052. // An URL on the machine node is built in isolation.
  1053. //
  1054. // ISSUE: Is this really a desirable URL? Maybe we should
  1055. // use something else.
  1056. //
  1057. bstrURL = _T("http://");
  1058. bstrURL.Append(strOwner);
  1059. return S_OK;
  1060. }
  1061. /* virtual */
  1062. HRESULT
  1063. CIISMachine::CreatePropertyPages(
  1064. LPPROPERTYSHEETCALLBACK lpProvider,
  1065. LONG_PTR handle,
  1066. IUnknown * pUnk,
  1067. DATA_OBJECT_TYPES type
  1068. )
  1069. /*++
  1070. Routine Description:
  1071. Create the property pages for the given object
  1072. Arguments:
  1073. LPPROPERTYSHEETCALLBACK lpProvider : Provider
  1074. LONG_PTR handle : Handle.
  1075. IUnknown * pUnk,
  1076. DATA_OBJECT_TYPES type
  1077. Return Value:
  1078. HRESULT
  1079. --*/
  1080. {
  1081. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  1082. CError err;
  1083. if (S_FALSE == (HRESULT)(err = CIISMBNode::CreatePropertyPages(lpProvider, handle, pUnk, type)))
  1084. {
  1085. return S_OK;
  1086. }
  1087. if (ERROR_ALREADY_EXISTS == err.Win32Error())
  1088. {
  1089. return S_FALSE;
  1090. }
  1091. if (err.Succeeded())
  1092. {
  1093. CComBSTR bstrPath;
  1094. //
  1095. // ISSUE: What to do with m_err? This might be
  1096. // a bad machine object in the first place. Aborting
  1097. // when the machine object has an error code isn't
  1098. // such a bad solution here. If the error condition
  1099. // no longer exists, a refresh will cure.
  1100. //
  1101. if (m_err.Failed())
  1102. {
  1103. m_err.MessageBox();
  1104. return m_err;
  1105. }
  1106. err = BuildMetaPath(bstrPath);
  1107. if (err.Succeeded())
  1108. {
  1109. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrPath);
  1110. if (err.Succeeded())
  1111. {
  1112. CIISMachineSheet * pSheet = new CIISMachineSheet(
  1113. QueryAuthInfo(), bstrPath, GetMainWindow(GetConsole()),
  1114. (LPARAM)this,(LPARAM) NULL
  1115. );
  1116. if (pSheet)
  1117. {
  1118. // cache handle for user in MMCPropertyChangeNotify
  1119. m_ppHandle = handle;
  1120. pSheet->SetModeless();
  1121. err = AddMMCPage(lpProvider, new CIISMachinePage(pSheet));
  1122. }
  1123. else
  1124. {
  1125. err = ERROR_NOT_ENOUGH_MEMORY;
  1126. }
  1127. }
  1128. }
  1129. }
  1130. err.MessageBoxOnFailure();
  1131. return err;
  1132. }
  1133. /* virtual */
  1134. HRESULT
  1135. CIISMachine::EnumerateScopePane(
  1136. HSCOPEITEM hParent
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. Enumerate scope child items.
  1141. Arguments:
  1142. HSCOPEITEM hParent : Parent console handle
  1143. Return Value:
  1144. HRESULT
  1145. --*/
  1146. {
  1147. ASSERT(m_hScopeItem == hParent);
  1148. CError err;
  1149. CString str;
  1150. CIISService * pService, * pWebService = NULL;
  1151. CWaitCursor wait;
  1152. CMetaEnumerator * pme = NULL;
  1153. if (IsExpanded())
  1154. {
  1155. //
  1156. // Verify user credentials are satisfactorily resolved.
  1157. // Machines objects are loaded from the cache without a
  1158. // password, so the function below will ask for it.
  1159. //
  1160. ResolveCredentials();
  1161. wait.Restore();
  1162. BOOL fShouldRefresh = !HasInterface();
  1163. BOOL fCompatMode = FALSE;
  1164. err = AssureInterfaceCreated(FALSE);
  1165. if (err.Succeeded() && QueryMajorVersion() >= 6)
  1166. {
  1167. CMetabasePath path(TRUE, SZ_MBN_WEB);
  1168. CMetaKey mk(QueryAuthInfo(), path, METADATA_PERMISSION_READ);
  1169. err = mk.QueryResult();
  1170. if (err.Succeeded())
  1171. {
  1172. err = mk.QueryValue(MD_GLOBAL_STANDARD_APP_MODE_ENABLED, fCompatMode);
  1173. }
  1174. // If we fail here, then we have no Web service or no standard mode property defined
  1175. // That means that we are either not in standard mode or it doesn't matter
  1176. err.Reset();
  1177. }
  1178. if (err.Succeeded())
  1179. {
  1180. //
  1181. // Creation of the interface will have loaded display parameters, which
  1182. // may differ from the cached parameters.
  1183. //
  1184. if (fShouldRefresh)
  1185. {
  1186. RefreshDisplay();
  1187. }
  1188. err = CreateEnumerator(pme);
  1189. }
  1190. //
  1191. // Only check for acces denied now, because virtually any idiot
  1192. // is allowed to create a metabase interface, but will get the
  1193. // access denied when calling a method, such as enumeration.
  1194. //
  1195. if (HandleAccessDenied(err))
  1196. {
  1197. wait.Restore();
  1198. //
  1199. // Credentials were changed. Try again (interface should be
  1200. // created already)
  1201. //
  1202. SAFE_DELETE(pme);
  1203. if (err.Succeeded())
  1204. {
  1205. err = RefreshData();
  1206. CMetabasePath path;
  1207. err = DetermineIfAdministrator(
  1208. m_pInterface,
  1209. path,
  1210. &m_fIsAdministrator,
  1211. &m_dwMetabaseSystemChangeNumber
  1212. );
  1213. // Set the latest system change number.
  1214. RefreshMetabaseSystemChangeNumber();
  1215. err = CreateEnumerator(pme);
  1216. }
  1217. }
  1218. //
  1219. // Enumerate administerable services from the metabase
  1220. //
  1221. while (err.Succeeded())
  1222. {
  1223. err = pme->Next(str);
  1224. if (err.Succeeded())
  1225. {
  1226. TRACEEOLID("Enumerating node: " << str);
  1227. pService = new CIISService(this, str);
  1228. if (!pService)
  1229. {
  1230. err = ERROR_NOT_ENOUGH_MEMORY;
  1231. break;
  1232. }
  1233. //
  1234. // See if we care
  1235. //
  1236. if (pService->IsManagedService())
  1237. {
  1238. pService->AddRef();
  1239. // update the service state
  1240. pService->GetServiceState();
  1241. err = pService->AddToScopePane(hParent);
  1242. if (err.Succeeded())
  1243. {
  1244. if (0 == _tcsicmp(pService->GetNodeName(), SZ_MBN_WEB))
  1245. {
  1246. pWebService = pService;
  1247. }
  1248. }
  1249. else
  1250. {
  1251. pService->Release();
  1252. }
  1253. }
  1254. else
  1255. {
  1256. //
  1257. // Node is not a managed service, or we're managing the
  1258. // cluster and the service is not clustered.
  1259. //
  1260. pService->Release();
  1261. }
  1262. }
  1263. }
  1264. if (err.Win32Error() == ERROR_NO_MORE_ITEMS)
  1265. {
  1266. err.Reset();
  1267. }
  1268. if (pWebService)
  1269. {
  1270. // do this check only if we have a W3SVC service
  1271. // that's because if the user only installed FTP
  1272. // we won't have the interface required for AppPool (WAM interface)
  1273. // and this may potential AV!!!!
  1274. //
  1275. // Find out what mode IIS is R-E-A-L-L-Y running as...
  1276. GET_PROCESS_MODE_STRUCT MyStructOfInfo;
  1277. MyStructOfInfo.pComAuthInfo = QueryAuthInfo();
  1278. MyStructOfInfo.dwReturnStatus = 0;
  1279. MyStructOfInfo.dwProcessMode = -1;
  1280. if (GetProcessMode(&MyStructOfInfo))
  1281. {
  1282. // We got it back in time (no timeout)
  1283. if (-1 != MyStructOfInfo.dwProcessMode)
  1284. {
  1285. fCompatMode = FALSE;
  1286. if (0 == MyStructOfInfo.dwProcessMode)
  1287. {
  1288. fCompatMode = TRUE;
  1289. }
  1290. TRACEEOLID("GetProcessMode:" << MyStructOfInfo.dwProcessMode);
  1291. }
  1292. }
  1293. else
  1294. {
  1295. // Leave it at whatever we got from the metabase...
  1296. }
  1297. }
  1298. // If we are encountered web service, we should add
  1299. // Application Pools container before this service
  1300. //
  1301. m_pAppPoolsContainer = NULL;
  1302. if (err.Succeeded() && pWebService != NULL && !fCompatMode)
  1303. {
  1304. // We could have iis5 machine which doesn't have any pools
  1305. //
  1306. CMetabasePath path(TRUE, SZ_MBN_WEB, SZ_MBN_APP_POOLS);
  1307. CMetaKey mk(pme, path);
  1308. if (mk.Succeeded())
  1309. {
  1310. CAppPoolsContainer * pPools = new CAppPoolsContainer(
  1311. this, pWebService);
  1312. if (!pPools)
  1313. {
  1314. err = ERROR_NOT_ENOUGH_MEMORY;
  1315. goto Fail;
  1316. }
  1317. // Insert pools container before Web Services node
  1318. pPools->AddRef();
  1319. err = pPools->AddToScopePane(pWebService->QueryScopeItem(), FALSE, TRUE);
  1320. m_pAppPoolsContainer = pPools;
  1321. }
  1322. }
  1323. // If we are encountered web service, we should add
  1324. // this container before after the web service
  1325. //
  1326. m_pWebServiceExtensionContainer = NULL;
  1327. if (err.Succeeded() && pWebService != NULL)
  1328. {
  1329. if (QueryMajorVersion() >= 6)
  1330. {
  1331. // We could have iis5 machine which doesn't have any extensions
  1332. CWebServiceExtensionContainer * pNode = new CWebServiceExtensionContainer(this, pWebService);
  1333. if (!pNode)
  1334. {
  1335. err = ERROR_NOT_ENOUGH_MEMORY;
  1336. goto Fail;
  1337. }
  1338. // Insert container AFTER Web Services node
  1339. pNode->AddRef();
  1340. err = pNode->AddToScopePane(pWebService->QueryScopeItem(), FALSE, FALSE);
  1341. m_pWebServiceExtensionContainer = pNode;
  1342. }
  1343. }
  1344. Fail:
  1345. if (err.Failed())
  1346. {
  1347. CWnd * pWnd = GetMainWindow(GetConsole());
  1348. DisplayError(err,pWnd ? pWnd->m_hWnd : NULL);
  1349. }
  1350. SetInterfaceError(err);
  1351. //
  1352. // Clean up
  1353. //
  1354. SAFE_DELETE(pme);
  1355. }
  1356. return err;
  1357. }
  1358. /* virtual */
  1359. HRESULT
  1360. CIISMachine::RemoveScopeItem()
  1361. /*++
  1362. Routine Description:
  1363. Remove the machine from the scope view and the cache.
  1364. Arguments:
  1365. None
  1366. Return Value:
  1367. HRESULT
  1368. --*/
  1369. {
  1370. ASSERT(m_pRootExt == NULL);
  1371. //
  1372. // Find out root before deleting scope node
  1373. //
  1374. CIISRoot * pRoot = GetRoot();
  1375. ASSERT_PTR(pRoot);
  1376. //
  1377. // Remove from the tree
  1378. //
  1379. #if defined(_DEBUG) || DBG
  1380. // check if we have open property pages...
  1381. g_OpenPropertySheetTracker.Dump();
  1382. // dump out any open connections
  1383. m_MachineWNetConnections.Dump();
  1384. #endif
  1385. HRESULT hr = CIISMBNode::RemoveScopeItem();
  1386. if (SUCCEEDED(hr) && pRoot)
  1387. {
  1388. // Disconnect all connections made from this iismachine.
  1389. m_MachineWNetConnections.Clear();
  1390. pRoot->m_scServers.Remove(this);
  1391. #if defined(_DEBUG) || DBG
  1392. // check if we leaked anything.
  1393. g_Debug_IISObject.Dump(2);
  1394. #endif
  1395. }
  1396. return hr;
  1397. }
  1398. HRESULT
  1399. CIISMachine::DeleteChildObjects(HSCOPEITEM hItem)
  1400. {
  1401. CMetaInterface * pInterface = QueryInterface();
  1402. if (pInterface)
  1403. {
  1404. pInterface->SaveData();
  1405. }
  1406. return CIISMBNode::DeleteChildObjects(hItem);
  1407. }
  1408. BOOL
  1409. CIISMachine::IsLocalHost()
  1410. {
  1411. if (FALSE == m_fLocalHostIPChecked)
  1412. {
  1413. BOOL bIsLocalHost = FALSE;
  1414. LPOLESTR lpOwner = QueryMachineName();
  1415. CString strCleanName;
  1416. strCleanName = PURE_COMPUTER_NAME(lpOwner);
  1417. // Check if MachineName is mapped to 127.0.0.1 or localhost...
  1418. // if the machine specified
  1419. // is not the local machine...
  1420. if (!::IsLocalHost(strCleanName,&bIsLocalHost))
  1421. {
  1422. // WinSockFailure
  1423. }
  1424. m_fIsLocalHostIP = bIsLocalHost;
  1425. m_fLocalHostIPChecked = TRUE;
  1426. }
  1427. return m_fIsLocalHostIP;
  1428. }
  1429. /* virtual */
  1430. LPOLESTR
  1431. CIISMachine::GetResultPaneColInfo(int nCol)
  1432. /*++
  1433. Routine Description:
  1434. Return result pane string for the given column number
  1435. Arguments:
  1436. int nCol : Column number
  1437. Return Value:
  1438. String
  1439. --*/
  1440. {
  1441. if (m_pRootExt != NULL)
  1442. {
  1443. return m_pRootExt->GetResultPaneColInfo(nCol);
  1444. }
  1445. ASSERT(_fStaticsLoaded);
  1446. switch(nCol)
  1447. {
  1448. case COL_NAME:
  1449. return QueryDisplayName();
  1450. case COL_LOCAL:
  1451. return IsLocalHost() ? _bstrYes : _bstrNo;
  1452. case COL_VERSION:
  1453. {
  1454. CString str;
  1455. str.Format(_bstrVersionFmt, QueryMajorVersion(), QueryMinorVersion());
  1456. _bstrResult = str;
  1457. }
  1458. return _bstrResult;
  1459. case COL_STATUS:
  1460. {
  1461. if (m_err.Succeeded())
  1462. {
  1463. return OLESTR("");
  1464. }
  1465. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  1466. return m_err;
  1467. }
  1468. }
  1469. ASSERT_MSG("Bad column number");
  1470. return OLESTR("");
  1471. }
  1472. /* virtual */
  1473. HRESULT
  1474. CIISMachine::GetResultViewType(
  1475. LPOLESTR * lplpViewType,
  1476. long * lpViewOptions
  1477. )
  1478. /*++
  1479. Routine Description:
  1480. If we have an URL built up, display our result view as that URL,
  1481. and destroy it. This is done when 'browsing' a metabase node.
  1482. The derived class will build the URL, and reselect the node.
  1483. Arguments:
  1484. BSTR * lplpViewType : Return view type here
  1485. long * lpViewOptions : View options
  1486. Return Value:
  1487. S_FALSE to use default view type, S_OK indicates the
  1488. view type is returned in *ppViewType
  1489. --*/
  1490. {
  1491. if (m_bstrURL.Length())
  1492. {
  1493. *lpViewOptions = MMC_VIEW_OPTIONS_NONE;
  1494. *lplpViewType = (LPOLESTR)::CoTaskMemAlloc(
  1495. (m_bstrURL.Length() + 1) * sizeof(WCHAR)
  1496. );
  1497. if (*lplpViewType)
  1498. {
  1499. lstrcpy(*lplpViewType, m_bstrURL);
  1500. //
  1501. // Destroy URL so we get a normal result view next time
  1502. //
  1503. m_bstrURL.Empty();
  1504. m_fSkipEnumResult = TRUE;
  1505. return S_OK;
  1506. }
  1507. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  1508. }
  1509. //
  1510. // No URL waiting -- use standard result view
  1511. //
  1512. return CIISObject::GetResultViewType(lplpViewType, lpViewOptions);
  1513. }
  1514. /* virtual */
  1515. HRESULT
  1516. CIISMachine::AddMenuItems(
  1517. LPCONTEXTMENUCALLBACK lpContextMenuCallback,
  1518. long * pInsertionAllowed,
  1519. DATA_OBJECT_TYPES type
  1520. )
  1521. /*++
  1522. Routine Description:
  1523. Add menu items to the context menu
  1524. Arguments:
  1525. LPCONTEXTMENUCALLBACK lpContextMenuCallback : Context menu callback
  1526. long * pInsertionAllowed : Insertion allowed
  1527. DATA_OBJECT_TYPES type : Object type
  1528. Return Value:
  1529. HRESULT
  1530. --*/
  1531. {
  1532. ASSERT_READ_PTR(lpContextMenuCallback);
  1533. IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)GetConsoleNameSpace();
  1534. //
  1535. // Add base menu items
  1536. //
  1537. HRESULT hr = CIISObject::AddMenuItems(
  1538. lpContextMenuCallback,
  1539. pInsertionAllowed,
  1540. type
  1541. );
  1542. if (SUCCEEDED(hr))
  1543. {
  1544. if (IsAdministrator() && (*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK) != 0)
  1545. {
  1546. AddMenuItemByCommand(lpContextMenuCallback, IDM_METABACKREST);
  1547. AddMenuItemByCommand(lpContextMenuCallback, IDM_SHUTDOWN);
  1548. }
  1549. // Check if we can do save data on this version of iis...
  1550. if (IsConfigFlushable() && (*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK) != 0)
  1551. {
  1552. AddMenuItemByCommand(lpContextMenuCallback, IDM_SAVE_DATA);
  1553. }
  1554. #if 0
  1555. if (CanAddInstance())
  1556. {
  1557. ASSERT(pInsertionAllowed != NULL);
  1558. if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0)
  1559. {
  1560. #define ADD_SERVICE_MENU(x)\
  1561. if (!bSepAdded)\
  1562. {\
  1563. AddMenuSeparator(lpContextMenuCallback);\
  1564. bSepAdded = TRUE;\
  1565. }\
  1566. AddMenuItemByCommand(lpContextMenuCallback, (x))
  1567. HSCOPEITEM hChild = NULL, hCurrent;
  1568. LONG_PTR cookie;
  1569. BOOL bSepAdded = FALSE;
  1570. hr = pConsoleNameSpace->GetChildItem(QueryScopeItem(), &hChild, &cookie);
  1571. while (SUCCEEDED(hr) && hChild != NULL)
  1572. {
  1573. CIISMBNode * pNode = (CIISMBNode *)cookie;
  1574. ASSERT(pNode != NULL);
  1575. if (_tcsicmp(pNode->GetNodeName(), SZ_MBN_FTP) == 0)
  1576. {
  1577. ADD_SERVICE_MENU(IDM_NEW_FTP_SITE);
  1578. }
  1579. else if (_tcsicmp(pNode->GetNodeName(), SZ_MBN_WEB) == 0)
  1580. {
  1581. ADD_SERVICE_MENU(IDM_NEW_WEB_SITE);
  1582. }
  1583. else if (_tcsicmp(pNode->GetNodeName(), SZ_MBN_APP_POOLS) == 0)
  1584. {
  1585. ADD_SERVICE_MENU(IDM_NEW_APP_POOL);
  1586. }
  1587. hCurrent = hChild;
  1588. hr = pConsoleNameSpace->GetNextItem(hCurrent, &hChild, &cookie);
  1589. }
  1590. }
  1591. }
  1592. #endif
  1593. //
  1594. // CODEWORK: Add new instance commands for each of the services
  1595. // keeping in mind which ones are installed and all.
  1596. // add that info to the table, remembering that this
  1597. // is per service.
  1598. //
  1599. }
  1600. return hr;
  1601. }
  1602. #if 0
  1603. // BUGBUG: It should be quite different -> we don't know in advance
  1604. // which service is this site for
  1605. HRESULT
  1606. CIISMachine::InsertNewInstance(DWORD inst)
  1607. {
  1608. CError err;
  1609. // Now we should insert and select this new site
  1610. TCHAR buf[16];
  1611. CIISSite * pSite = new CIISSite(m_pOwner, this, _itot(inst, buf, 10));
  1612. if (pSite != NULL)
  1613. {
  1614. // If machine is not expanded we will get error and no effect
  1615. if (!IsExpanded())
  1616. {
  1617. SelectScopeItem();
  1618. IConsoleNameSpace2 * pConsole
  1619. = (IConsoleNameSpace2 *)GetConsoleNameSpace();
  1620. pConsole->Expand(QueryScopeItem());
  1621. }
  1622. // Now we should find the relevant service node, and inset this one under
  1623. // this node
  1624. pSite->AddRef();
  1625. err = pSite->AddToScopePaneSorted(QueryScopeItem(), FALSE);
  1626. if (err.Succeeded())
  1627. {
  1628. VERIFY(SUCCEEDED(pSite->SelectScopeItem()));
  1629. }
  1630. else
  1631. {
  1632. pSite->Release();
  1633. }
  1634. }
  1635. else
  1636. {
  1637. err = ERROR_NOT_ENOUGH_MEMORY;
  1638. }
  1639. return err;
  1640. }
  1641. #endif
  1642. HRESULT
  1643. CIISMachine::Command(
  1644. long lCommandID,
  1645. CSnapInObjectRootBase * pObj,
  1646. DATA_OBJECT_TYPES type
  1647. )
  1648. /*++
  1649. Routine Description:
  1650. Handle command from context menu.
  1651. Arguments:
  1652. long lCommandID : Command ID
  1653. CSnapInObjectRootBase * pObj : Base object
  1654. DATA_OBJECT_TYPES type : Data object type
  1655. Return Value:
  1656. HRESULT
  1657. --*/
  1658. {
  1659. HRESULT hr = S_OK;
  1660. switch (lCommandID)
  1661. {
  1662. case IDM_DISCONNECT:
  1663. hr = OnDisconnect();
  1664. break;
  1665. case IDM_METABACKREST:
  1666. hr = OnMetaBackRest();
  1667. break;
  1668. case IDM_SHUTDOWN:
  1669. hr = OnShutDown();
  1670. break;
  1671. case IDM_SAVE_DATA:
  1672. hr = OnSaveData();
  1673. break;
  1674. #if 0
  1675. case IDM_NEW_FTP_SITE:
  1676. CError err;
  1677. CComBSTR bstrMetaPath;
  1678. BuildMetaPath(bstrMetaPath);
  1679. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrMetaPath);
  1680. if (!IsLostInterface(err))
  1681. {
  1682. // reset error if an other error other than No interface
  1683. err.Reset();
  1684. }
  1685. if (err.Succeeded())
  1686. {
  1687. if (SUCCEEDED(hr = AddFTPSite(pObj, type, &inst)))
  1688. {
  1689. hr = InsertNewInstance(inst);
  1690. }
  1691. }
  1692. break;
  1693. case IDM_NEW_WEB_SITE:
  1694. CError err;
  1695. CComBSTR bstrMetaPath;
  1696. BuildMetaPath(bstrMetaPath);
  1697. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrMetaPath);
  1698. if (!IsLostInterface(err))
  1699. {
  1700. // reset error if an other error other than No interface
  1701. err.Reset();
  1702. }
  1703. if (err.Succeeded())
  1704. {
  1705. if (SUCCEEDED(hr = AddWebSite(pObj, type, &inst)))
  1706. {
  1707. hr = InsertNewInstance(inst);
  1708. }
  1709. }
  1710. break;
  1711. case IDM_NEW_APP_POOL:
  1712. CError err;
  1713. CComBSTR bstrMetaPath;
  1714. BuildMetaPath(bstrMetaPath);
  1715. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrMetaPath);
  1716. if (!IsLostInterface(err))
  1717. {
  1718. // reset error if an other error other than No interface
  1719. err.Reset();
  1720. }
  1721. if (err.Succeeded())
  1722. {
  1723. hr = AddAppPool(pObj, type);
  1724. }
  1725. break;
  1726. #endif
  1727. //
  1728. // Pass on to base class
  1729. //
  1730. default:
  1731. hr = CIISMBNode::Command(lCommandID, pObj, type);
  1732. }
  1733. return hr;
  1734. }
  1735. HRESULT
  1736. CIISMachine::OnDisconnect()
  1737. /*++
  1738. Routine Description:
  1739. Disconnect this machine. Confirm user choice.
  1740. Arguments:
  1741. None
  1742. Return Value:
  1743. HRESULT
  1744. --*/
  1745. {
  1746. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  1747. CString str;
  1748. str.Format(IDS_CONFIRM_DISCONNECT, QueryDisplayName());
  1749. BOOL bOpenPropertySheets = FALSE;
  1750. CIISObject * pOpenItem = NULL;
  1751. if (g_OpenPropertySheetTracker.IsPropertySheetOpenComputer(this,TRUE,&pOpenItem))
  1752. {
  1753. g_OpenPropertySheetTracker.Dump();
  1754. if (pOpenItem)
  1755. {
  1756. HWND hHwnd = pOpenItem->IsMyPropertySheetOpen();
  1757. // a property sheet is open somewhere..
  1758. // make sure they close it before proceeding with refresh...
  1759. // Highlight the property sheet.
  1760. if (hHwnd && (hHwnd != (HWND) 1))
  1761. {
  1762. DoHelpMessageBox(NULL,IDS_CLOSE_ALL_PROPERTY_SHEET_DISCONNECT, MB_APPLMODAL | MB_OK | MB_ICONINFORMATION, 0);
  1763. if (!SetForegroundWindow(hHwnd))
  1764. {
  1765. // wasn't able to bring this property sheet to
  1766. // the foreground, the propertysheet must not
  1767. // exist anymore. let's just clean the hwnd
  1768. // so that the user will be able to open propertysheet
  1769. pOpenItem->SetMyPropertySheetOpen(0);
  1770. }
  1771. bOpenPropertySheets = TRUE;
  1772. }
  1773. }
  1774. }
  1775. if (!bOpenPropertySheets)
  1776. {
  1777. if (NoYesMessageBox(str))
  1778. {
  1779. return RemoveScopeItem();
  1780. }
  1781. }
  1782. return S_OK;
  1783. }
  1784. HRESULT
  1785. CIISMachine::OnMetaBackRest()
  1786. /*++
  1787. Routine Description:
  1788. Backup/Restore the metabase
  1789. Arguments:
  1790. None
  1791. Return Value:
  1792. HRESULT
  1793. --*/
  1794. {
  1795. CError err;
  1796. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  1797. //
  1798. // Verify user credentials are satisfactorily resolved.
  1799. // Machines objects are loaded from the cache without a
  1800. // password, so the function below will ask for it.
  1801. //
  1802. ResolveCredentials();
  1803. // ensure the dialog gets themed
  1804. CThemeContextActivator activator(theApp.GetFusionInitHandle());
  1805. CBackupDlg dlg(this, QueryServerName(), GetMainWindow(GetConsole()));
  1806. dlg.DoModal();
  1807. if (dlg.ServicesWereRestarted())
  1808. {
  1809. //
  1810. // Rebind all metabase handles on this server
  1811. //
  1812. err = CreateInterface(TRUE);
  1813. //
  1814. // Now do a refresh on the computer node. Since we've forced
  1815. // the rebinding already, we should not get the disconnect warning.
  1816. //
  1817. if (err.Succeeded())
  1818. {
  1819. err = Refresh(TRUE);
  1820. }
  1821. }
  1822. else
  1823. {
  1824. if (dlg.HasChangedMetabase())
  1825. {
  1826. //
  1827. // Refresh and re-enumerate child objects
  1828. //
  1829. err = Refresh(TRUE);
  1830. }
  1831. }
  1832. return err;
  1833. }
  1834. HRESULT
  1835. CIISMachine::OnShutDown()
  1836. /*++
  1837. Routine Description:
  1838. Bring up the IIS shutdown dialog. If the services on the remote
  1839. machine are restarted, the metabase interface should be recreated.
  1840. Arguments:
  1841. None
  1842. Return Value:
  1843. HRESULT
  1844. --*/
  1845. {
  1846. CError err;
  1847. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  1848. //
  1849. // Verify user credentials are satisfactorily resolved.
  1850. // Machines objects are loaded from the cache without a
  1851. // password, so the function below will ask for it.
  1852. //
  1853. ResolveCredentials();
  1854. // ensure the dialog gets themed
  1855. CThemeContextActivator activator(theApp.GetFusionInitHandle());
  1856. CIISShutdownDlg dlg(this, GetMainWindow(GetConsole()));
  1857. dlg.DoModal();
  1858. if (dlg.ServicesWereRestarted())
  1859. {
  1860. //
  1861. // Rebind all metabase handles on this server
  1862. //
  1863. err = CreateInterface(TRUE);
  1864. //
  1865. // Now do a refresh on the computer node. Since we've forced
  1866. // the rebinding already, we should not get the disconnect warning.
  1867. //
  1868. if (err.Succeeded())
  1869. {
  1870. err = Refresh(TRUE);
  1871. }
  1872. }
  1873. return err;
  1874. }
  1875. HRESULT
  1876. CIISMachine::OnSaveData()
  1877. /*++
  1878. Routine Description:
  1879. Flush the metabase to disk and display saved config file
  1880. Arguments:
  1881. None
  1882. Return Value:
  1883. HRESULT
  1884. --*/
  1885. {
  1886. CError err;
  1887. CComBSTR bstrPath;
  1888. err = BuildMetaPath(bstrPath);
  1889. err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrPath);
  1890. if (err.Succeeded())
  1891. {
  1892. err = DoOnSaveData(::GetActiveWindow(), QueryServerName(),QueryInterface(),TRUE,GetMetabaseSystemChangeNumber());
  1893. RefreshMetabaseSystemChangeNumber();
  1894. }
  1895. return err;
  1896. }
  1897. HRESULT
  1898. CIISMachine::RefreshMetabaseSystemChangeNumber()
  1899. /*++
  1900. Routine Description:
  1901. Arguments:
  1902. None
  1903. Return Value:
  1904. HRESULT
  1905. --*/
  1906. {
  1907. return QueryInterface()->GetSystemChangeNumber(&m_dwMetabaseSystemChangeNumber);
  1908. }