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.

2944 lines
77 KiB

  1. /*===================================================================
  2. Microsoft IIS
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: WAMREG
  6. File: WamAdm.cpp
  7. Implementation of WamAdm object, including ClassFactory, IWamAdm,
  8. IMSAdminReplication
  9. Owner: LeiJin
  10. Note:
  11. WamAdm implementation
  12. ===================================================================*/
  13. #include "common.h"
  14. #include "iiscnfg.h"
  15. #include "iwamreg.h"
  16. #include "WamAdm.h"
  17. #include "auxfunc.h"
  18. #include "wmrgexp.h"
  19. #include "dbgutil.h"
  20. #include "mtxrepl.h"
  21. #ifdef _IIS_6_0
  22. #include "string.hxx"
  23. #include "multisz.hxx"
  24. #include "w3ctrlps.h"
  25. #include "iiscnfgp.h"
  26. #include "helpfunc.hxx"
  27. #endif // _IIS_6_0
  28. #define ReleaseInterface(p) if (p) { p->Release(); p = NULL; }
  29. const LPCWSTR APPPOOLPATH = L"/LM/W3SVC/AppPools/";
  30. #ifndef DBGERROR
  31. #define DBGERROR(args) ((void)0) /* Do Nothing */
  32. #endif
  33. #ifndef DBGWARN
  34. #define DBGWARN(args) ((void)0) /* Do Nothing */
  35. #endif
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CWamAdmin
  38. /*===================================================================
  39. CWamAdmin
  40. Constructor
  41. Parameter:
  42. NONE.
  43. Return:
  44. ===================================================================*/
  45. CWamAdmin::CWamAdmin()
  46. : m_cRef(1)
  47. {
  48. InterlockedIncrement((long *)&g_dwRefCount);
  49. }
  50. /*===================================================================
  51. ~CWamAdmin
  52. Constructor
  53. Parameter:
  54. NONE.
  55. Return:
  56. ===================================================================*/
  57. CWamAdmin::~CWamAdmin()
  58. {
  59. InterlockedDecrement((long *)&g_dwRefCount);
  60. }
  61. /*===================================================================
  62. CWamAdmin::QueryInterface
  63. QueryInterface, CWamAdmin supports 2 interfaces, one is IID_IWamAdmin,
  64. the other is IID_IMSAdminReplication.
  65. Parameter:
  66. riid
  67. ppv pointer to Interface pointer
  68. Return: HRESULT
  69. ===================================================================*/
  70. STDMETHODIMP CWamAdmin::QueryInterface(REFIID riid, void ** ppv)
  71. {
  72. if (riid == IID_IUnknown || riid == IID_IWamAdmin)
  73. {
  74. *ppv = static_cast<IWamAdmin*>(this);
  75. }
  76. else if (riid == IID_IWamAdmin2)
  77. {
  78. *ppv = static_cast<IWamAdmin2*>(this);
  79. }
  80. else if (riid == IID_IMSAdminReplication)
  81. {
  82. *ppv = static_cast<IMSAdminReplication*>(this);
  83. }
  84. #ifdef _IIS_6_0
  85. else if (riid == IID_IIISApplicationAdmin)
  86. {
  87. *ppv = static_cast<IIISApplicationAdmin*>(this);
  88. }
  89. #endif //_IIS_6_0
  90. else
  91. {
  92. *ppv = NULL;
  93. return E_NOINTERFACE;
  94. }
  95. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  96. return NOERROR;
  97. }
  98. /*===================================================================
  99. CWamAdmin::AddRef
  100. Parameter:
  101. NONE
  102. Return: HRESULT
  103. ===================================================================*/
  104. STDMETHODIMP_(ULONG) CWamAdmin::AddRef( )
  105. {
  106. return InterlockedIncrement(&m_cRef);
  107. }
  108. /*===================================================================
  109. CWamAdmin::Release
  110. Parameter:
  111. NONE
  112. Return: HRESULT
  113. ===================================================================*/
  114. STDMETHODIMP_(ULONG) CWamAdmin::Release( )
  115. {
  116. ULONG cRef = InterlockedDecrement(&m_cRef);
  117. if ( 0 == cRef )
  118. {
  119. delete this;
  120. }
  121. return cRef;
  122. }
  123. /*===================================================================
  124. CWamAdmin::AppCreate
  125. Create an application on szMDPath. The fInProc indicates whether the
  126. result application is in-proc or out-proc. If There is already an application
  127. existed on szMDPath, AppCreate will remove the old application if fInProc does not
  128. match with existing application. Otherwise, it is no-op.
  129. Parameter:
  130. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  131. fInProc TRUE if wants to have an InProc application,
  132. FALSE if wants to have an outproc application.
  133. Return: HRESULT
  134. ===================================================================*/
  135. STDMETHODIMP CWamAdmin::AppCreate(LPCWSTR szMDPath, BOOL fInProc)
  136. {
  137. DWORD dwAppMode = (fInProc) ?
  138. eAppRunInProc : eAppRunOutProcIsolated;
  139. return AppCreate2(szMDPath, dwAppMode);
  140. }
  141. /*===================================================================
  142. CWamAdmin::AppDelete
  143. Delete an application on a Metabase Path. If there is no application existed
  144. before, it is no-op.
  145. Parameter:
  146. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  147. fRecursive TRUE if wants to delete applications from all sub nodes of szMDPath,
  148. FALSE otherwise.
  149. Return: HRESULT
  150. ===================================================================*/
  151. STDMETHODIMP CWamAdmin::AppDelete(LPCWSTR szMDPath, BOOL fRecursive)
  152. {
  153. return PrivateDeleteApplication(szMDPath,
  154. fRecursive,
  155. FALSE, // Recoverable?
  156. TRUE); // RemoveAppPool?
  157. }
  158. HRESULT
  159. CWamAdmin::PrivateDeleteApplication
  160. (
  161. LPCWSTR szMDPath,
  162. BOOL fRecursive,
  163. BOOL fRecoverable,
  164. BOOL fRemoveAppPool
  165. )
  166. {
  167. HRESULT hr = NOERROR;
  168. DWORD dwAppMode;
  169. WamRegMetabaseConfig MDConfig;
  170. LPWSTR pwszFormattedPath = NULL;
  171. if (szMDPath == NULL)
  172. {
  173. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  174. }
  175. //
  176. // Refer to function comment of FormatMetabasePath.
  177. //
  178. hr = FormatMetabasePath(szMDPath, &pwszFormattedPath);
  179. if (FAILED(hr))
  180. {
  181. return hr;
  182. }
  183. if (!g_WamRegGlobal.FAppPathAllowConfig(pwszFormattedPath))
  184. {
  185. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  186. }
  187. // Acquire a Lock
  188. g_WamRegGlobal.AcquireAdmWriteLock();
  189. if (!fRecursive)
  190. {
  191. hr = g_WamRegGlobal.DeleteApp(pwszFormattedPath, fRecoverable, fRemoveAppPool);
  192. if (hr == MD_ERROR_DATA_NOT_FOUND)
  193. {
  194. hr = NOERROR;
  195. }
  196. if (FAILED(hr))
  197. {
  198. DBGPRINTF((DBG_CONTEXT, "Failed to Delete on path %S, hr = %08x\n",
  199. szMDPath,
  200. hr));
  201. }
  202. }
  203. else
  204. {
  205. HRESULT hrT = NOERROR;
  206. DWORD dwSizePrefix;
  207. WCHAR* pbBufferTemp = NULL;
  208. DWORD dwBufferSizeTemp = 0;
  209. dwSizePrefix = wcslen(pwszFormattedPath);
  210. hr = MDConfig.MDGetPropPaths(pwszFormattedPath, MD_APP_ISOLATED, &pbBufferTemp, &dwBufferSizeTemp);
  211. if (SUCCEEDED(hr) && pbBufferTemp)
  212. {
  213. WCHAR* pszString = NULL;
  214. WCHAR* pszMetabasePath = NULL;
  215. for (pszString = (LPWSTR)pbBufferTemp;
  216. *pszString != (WCHAR)'\0' && SUCCEEDED(hr);
  217. pszString += (wcslen(pszString) + 1))
  218. {
  219. hr = g_WamRegGlobal.ConstructFullPath(pwszFormattedPath,
  220. dwSizePrefix,
  221. pszString,
  222. &pszMetabasePath
  223. );
  224. if (SUCCEEDED(hr))
  225. {
  226. if (!g_WamRegGlobal.FIsW3SVCRoot(pszMetabasePath))
  227. {
  228. hr = g_WamRegGlobal.DeleteApp(pszMetabasePath, fRecoverable, fRemoveAppPool);
  229. if (FAILED(hr))
  230. {
  231. DBGPRINTF((DBG_CONTEXT, "Failed to Delete on path %S, hr = %08x\n",
  232. pszString,
  233. hr));
  234. break;
  235. }
  236. }
  237. delete [] pszMetabasePath;
  238. pszMetabasePath = NULL;
  239. }
  240. else
  241. {
  242. DBGPRINTF((DBG_CONTEXT, "Failed to DeleteRecoverable, hr = %08x\n",
  243. pszString,
  244. hr));
  245. }
  246. }
  247. delete [] pbBufferTemp;
  248. pbBufferTemp = NULL;
  249. }
  250. else
  251. {
  252. DBGPRINTF((DBG_CONTEXT, "Delete: GetPropPaths failed hr = %08x\n", hr));
  253. }
  254. }
  255. // Release a Lock
  256. g_WamRegGlobal.ReleaseAdmWriteLock();
  257. if (pwszFormattedPath != szMDPath)
  258. {
  259. delete [] pwszFormattedPath;
  260. pwszFormattedPath = NULL;
  261. }
  262. return hr;
  263. }
  264. /*===================================================================
  265. CWamAdmin::AppUnLoad
  266. UnLoad an application on a Metabase Path. If there is no application running
  267. it returns NOERROR.
  268. For non-administrators we prevent them from unloading applications
  269. in the pool. If the recursive flag is set, we will silently
  270. ignore failures due to insufficient access.
  271. Parameter:
  272. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  273. fRecursive TRUE if wants to unload applications from all sub nodes of szMDPath,
  274. FALSE otherwise.
  275. Return: HRESULT
  276. ===================================================================*/
  277. STDMETHODIMP CWamAdmin::AppUnLoad(LPCWSTR szMDPath, BOOL fRecursive)
  278. {
  279. HRESULT hr = NOERROR;
  280. DWORD dwCallBack = 0;
  281. WamRegMetabaseConfig MDConfig;
  282. DWORD dwAppIsolated = 0;
  283. BOOL bIsAdmin = TRUE;
  284. if (szMDPath == NULL || *szMDPath == L'\0')
  285. {
  286. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  287. }
  288. bIsAdmin = MDConfig.HasAdminAccess();
  289. #ifdef _IIS_6_0
  290. DWORD dwMode;
  291. hr = GetProcessMode(&dwMode);
  292. if (FAILED(hr))
  293. {
  294. return hr;
  295. }
  296. #endif //_IIS_6_0
  297. // Acquire a Lock
  298. g_WamRegGlobal.AcquireAdmWriteLock();
  299. if (fRecursive)
  300. {
  301. DWORD dwSizePrefix = wcslen(szMDPath);;
  302. WCHAR* pbBufferTemp = NULL;
  303. DWORD dwBufferSizeTemp = 0;
  304. hr = MDConfig.MDGetPropPaths( szMDPath,
  305. MD_APP_ISOLATED,
  306. &pbBufferTemp,
  307. &dwBufferSizeTemp);
  308. if (SUCCEEDED(hr))
  309. {
  310. WCHAR* pszString = NULL;
  311. WCHAR* pszMetabasePath = NULL;
  312. BOOL bDoUnload;
  313. for( pszString = (LPWSTR)pbBufferTemp;
  314. *pszString != (WCHAR)'\0' && SUCCEEDED(hr);
  315. pszString += (wcslen(pszString) + 1))
  316. {
  317. bDoUnload = TRUE;
  318. hr = g_WamRegGlobal.ConstructFullPath(szMDPath,
  319. dwSizePrefix,
  320. pszString,
  321. &pszMetabasePath
  322. );
  323. if( SUCCEEDED(hr) && !bIsAdmin )
  324. {
  325. hr = MDConfig.MDGetDWORD( pszMetabasePath,
  326. MD_APP_ISOLATED,
  327. &dwAppIsolated );
  328. DBG_ASSERT( SUCCEEDED(hr) );
  329. if( SUCCEEDED(hr) && eAppRunOutProcInDefaultPool == dwAppIsolated )
  330. {
  331. // Do not unload
  332. bDoUnload = FALSE;
  333. DBGPRINTF((DBG_CONTEXT,
  334. "Insufficient Access to unload Application %S, hr = %08x\n",
  335. pszMetabasePath,
  336. hr));
  337. }
  338. }
  339. #ifdef _IIS_6_0
  340. if ( 1 == dwMode )
  341. {
  342. // we are in new mode on IIS6
  343. RecycleAppPoolContainingApp(pszMetabasePath);
  344. }
  345. // otherwise we are in old mode, therefore use the old mode code, below
  346. else
  347. #endif //_IIS_6_0
  348. if( SUCCEEDED(hr) && bDoUnload )
  349. {
  350. hr = g_WamRegGlobal.W3ServiceUtil( pszMetabasePath,
  351. APPCMD_UNLOAD,
  352. &dwCallBack);
  353. }
  354. if( pszMetabasePath )
  355. {
  356. delete [] pszMetabasePath;
  357. pszMetabasePath = NULL;
  358. }
  359. } // for each application
  360. }
  361. if (pbBufferTemp != NULL)
  362. {
  363. delete [] pbBufferTemp;
  364. pbBufferTemp = NULL;
  365. }
  366. }
  367. else
  368. {
  369. if( !bIsAdmin )
  370. {
  371. // Non recursive
  372. hr = MDConfig.MDGetDWORD( szMDPath,
  373. MD_APP_ISOLATED,
  374. &dwAppIsolated );
  375. if( SUCCEEDED(hr) && eAppRunOutProcInDefaultPool == dwAppIsolated )
  376. {
  377. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  378. DBGPRINTF((DBG_CONTEXT,
  379. "Insufficient Access to unload Application %S, hr = %08x\n",
  380. szMDPath,
  381. hr));
  382. }
  383. }
  384. #ifdef _IIS_6_0
  385. if ( 1 == dwMode )
  386. {
  387. // we are in new mode on IIS6
  388. RecycleAppPoolContainingApp(szMDPath);
  389. }
  390. // otherwise we are in old mode, therefore use the old mode code, below
  391. else
  392. #endif //_IIS_6_0
  393. if( SUCCEEDED(hr) )
  394. {
  395. hr = g_WamRegGlobal.W3ServiceUtil(szMDPath, APPCMD_UNLOAD, &dwCallBack);
  396. }
  397. }
  398. // Release a Lock
  399. g_WamRegGlobal.ReleaseAdmWriteLock();
  400. return hr;
  401. }
  402. /*===================================================================
  403. CWamAdmin::AppGetStatus
  404. GetStatus an application on a Metabase Path. If there is an application on the
  405. metabase path, and the application is currently running, the dwStatus is set to
  406. APPSTATUS_RUNNING, if the application is not running, the dwStatus is set to
  407. APPSTATUS_STOPPED, if there is no application defined on the metabase path, the
  408. dwStatus is set to APPSTATUS_NOTDEFINED.
  409. Parameter:
  410. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  411. pdwAppStatus pointer DWORD buffer contains status result.
  412. Return: HRESULT
  413. NOERROR if succeeded.
  414. ===================================================================*/
  415. STDMETHODIMP CWamAdmin::AppGetStatus(LPCWSTR szMDPath, DWORD* pdwAppStatus)
  416. {
  417. HRESULT hr = NOERROR;
  418. HRESULT hrT;
  419. DWORD dwCallBack = 0;
  420. WamRegMetabaseConfig MDConfig;
  421. if (szMDPath == NULL)
  422. {
  423. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  424. }
  425. // Acquire a Lock
  426. g_WamRegGlobal.AcquireAdmWriteLock();
  427. hrT = g_WamRegGlobal.W3ServiceUtil(szMDPath, APPCMD_GETSTATUS, &dwCallBack);
  428. if (dwCallBack == APPSTATUS_Running)
  429. {
  430. *pdwAppStatus = APPSTATUS_RUNNING;
  431. }
  432. else if (dwCallBack == APPSTATUS_Stopped)
  433. {
  434. *pdwAppStatus = APPSTATUS_STOPPED;
  435. }
  436. else
  437. {
  438. DWORD dwAppMode;
  439. hr = MDConfig.MDGetDWORD(szMDPath, MD_APP_ISOLATED, &dwAppMode);
  440. if (hr == MD_ERROR_DATA_NOT_FOUND)
  441. {
  442. *pdwAppStatus = APPSTATUS_NOTDEFINED;
  443. hr = NOERROR;
  444. }
  445. else if (hr == NOERROR)
  446. {
  447. *pdwAppStatus = APPSTATUS_STOPPED;
  448. hr = NOERROR;
  449. }
  450. }
  451. // Release a Lock
  452. g_WamRegGlobal.ReleaseAdmWriteLock();
  453. return hr;
  454. }
  455. /*===================================================================
  456. CWamAdmin::AppDeleteRecoverable
  457. Delete an application on a Metabase Path. If there is no application existed
  458. before, it is no-op. It leaves AppIsolated untouched, because, this value is
  459. needed in Recover operation.
  460. Parameter:
  461. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  462. fRecursive TRUE if wants to deleteRecoverable applications from all sub nodes of szMDPath,
  463. FALSE otherwise.
  464. Return: HRESULT
  465. ===================================================================*/
  466. STDMETHODIMP CWamAdmin::AppDeleteRecoverable(LPCWSTR szMDPath, BOOL fRecursive)
  467. {
  468. return PrivateDeleteApplication(szMDPath,
  469. fRecursive,
  470. TRUE, // Recoverable?
  471. FALSE); // RemoveAppPool?
  472. }
  473. /*===================================================================
  474. CWamAdmin::AppRecover
  475. Recover an application on a Metabase Path. Based on the AppIsolated value
  476. on the metabase path, this function recreates an application.
  477. Parameter:
  478. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  479. fRecursive TRUE if wants to Recover applications from all sub nodes of szMDPath,
  480. FALSE otherwise.
  481. Return: HRESULT
  482. NOERROR if succeeds
  483. ===================================================================*/
  484. STDMETHODIMP CWamAdmin::AppRecover(LPCWSTR szMDPath, BOOL fRecursive)
  485. {
  486. HRESULT hr = NOERROR;
  487. WamRegMetabaseConfig MDConfig;
  488. LPWSTR pwszFormattedPath = NULL;
  489. if (szMDPath == NULL)
  490. {
  491. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  492. }
  493. // Refer to function comment.
  494. hr = FormatMetabasePath(szMDPath, &pwszFormattedPath);
  495. if (FAILED(hr))
  496. {
  497. return hr;
  498. }
  499. //
  500. // Grab the Lock
  501. //
  502. g_WamRegGlobal.AcquireAdmWriteLock();
  503. if (fRecursive)
  504. {
  505. DWORD dwSizePrefix;
  506. WCHAR* pbBufferTemp = 0;
  507. DWORD dwBufferSizeTemp;
  508. dwSizePrefix = wcslen(pwszFormattedPath);
  509. hr = MDConfig.MDGetPropPaths(pwszFormattedPath, MD_APP_ISOLATED, &pbBufferTemp, &dwBufferSizeTemp);
  510. if (SUCCEEDED(hr) && pbBufferTemp)
  511. {
  512. WCHAR *pszString = NULL;
  513. WCHAR *pszMetabasePath = NULL;
  514. for (pszString = (LPWSTR)pbBufferTemp;
  515. *pszString != (WCHAR)'\0' && SUCCEEDED(hr);
  516. pszString += (wcslen(pszString) + 1))
  517. {
  518. hr = g_WamRegGlobal.ConstructFullPath(pwszFormattedPath,
  519. dwSizePrefix,
  520. pszString,
  521. &pszMetabasePath
  522. );
  523. if (SUCCEEDED(hr))
  524. {
  525. if (!g_WamRegGlobal.FIsW3SVCRoot(pszMetabasePath))
  526. {
  527. hr = g_WamRegGlobal.RecoverApp(pszMetabasePath, TRUE);
  528. if (FAILED(hr))
  529. {
  530. DBGPRINTF((DBG_CONTEXT, "Failed to Recover on path %S, hr = %08x\n",
  531. pszMetabasePath,
  532. hr));
  533. break;
  534. }
  535. }
  536. delete [] pszMetabasePath;
  537. pszMetabasePath = NULL;
  538. }
  539. else
  540. {
  541. DBGPRINTF((DBG_CONTEXT, "Failed to Recover, hr = %08x\n",
  542. pszString,
  543. hr));
  544. }
  545. }
  546. }
  547. else
  548. {
  549. DBGPRINTF((DBG_CONTEXT, "Recover: GetPropPaths failed hr = %08x\n", hr));
  550. }
  551. if (pbBufferTemp != NULL)
  552. {
  553. delete [] pbBufferTemp;
  554. pbBufferTemp = NULL;
  555. }
  556. }
  557. else
  558. {
  559. hr = g_WamRegGlobal.RecoverApp(pwszFormattedPath, TRUE);
  560. if (FAILED(hr))
  561. {
  562. DBGPRINTF((DBG_CONTEXT, "Failed to Recover on path %S, hr = %08x\n",
  563. szMDPath,
  564. hr));
  565. }
  566. }
  567. if (SUCCEEDED(hr))
  568. {
  569. MDConfig.SaveData();
  570. }
  571. //
  572. // Release the Lock
  573. //
  574. g_WamRegGlobal.ReleaseAdmWriteLock();
  575. if (pwszFormattedPath != szMDPath)
  576. {
  577. delete [] pwszFormattedPath;
  578. pwszFormattedPath = NULL;
  579. }
  580. return hr;
  581. }
  582. /*==================================================================
  583. CWamAdmin::AppCreate2
  584. Create an application on szMDPath. The dwAppMode indicates whether the
  585. result application is in-proc or out-proc in a default pool or out proc isolated.
  586. If the application exists with the desired mode, it will be a no op. Otherwise,
  587. registration is done.
  588. Parameter:
  589. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  590. dwAppMode
  591. Return: HRESULT
  592. ===================================================================*/
  593. STDMETHODIMP CWamAdmin::AppCreate2(LPCWSTR szMDPath, DWORD dwAppModeIn)
  594. {
  595. HRESULT hr = NOERROR;
  596. DWORD dwAppMode = 0;
  597. BOOL fCreateNewApp = FALSE;
  598. BOOL fDeleteOldApp = FALSE;
  599. WamRegMetabaseConfig MDConfig;
  600. LPWSTR pwszFormattedPath = NULL;
  601. if (szMDPath == NULL)
  602. {
  603. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  604. }
  605. //
  606. // See FormatMetabasePath comment
  607. //
  608. hr = FormatMetabasePath(szMDPath, &pwszFormattedPath);
  609. if (FAILED(hr))
  610. {
  611. return hr;
  612. }
  613. if (!g_WamRegGlobal.FAppPathAllowConfig(pwszFormattedPath))
  614. {
  615. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  616. }
  617. // Acquire a Lock
  618. g_WamRegGlobal.AcquireAdmWriteLock();
  619. hr = MDConfig.MDGetDWORD(pwszFormattedPath, MD_APP_ISOLATED, &dwAppMode);
  620. if (hr == MD_ERROR_DATA_NOT_FOUND)
  621. {
  622. fCreateNewApp = TRUE;
  623. hr = NOERROR;
  624. }
  625. else if (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))
  626. {
  627. hr = MDConfig.MDCreatePath(NULL, pwszFormattedPath);
  628. fCreateNewApp = TRUE;
  629. if(FAILED(hr))
  630. {
  631. DBGPRINTF((DBG_CONTEXT, "Failed to create metabase path %S, hr = %08x",
  632. szMDPath,
  633. hr));
  634. }
  635. }
  636. else if (SUCCEEDED(hr))
  637. {
  638. //
  639. // if the input application mode is not the same as defined
  640. // in the metabase, we need to delete the old application as
  641. // defined in the metabase and create a new application as
  642. // specified by dwAppModeIn, the in parameter.
  643. //
  644. if (dwAppMode != dwAppModeIn)
  645. {
  646. fDeleteOldApp = TRUE;
  647. fCreateNewApp = TRUE;
  648. }
  649. }
  650. else
  651. {
  652. DBGPRINTF((DBG_CONTEXT, "Failed to get DWORD on metabase path %S, hr = %08x",
  653. szMDPath,
  654. hr));
  655. }
  656. if (SUCCEEDED(hr))
  657. {
  658. if (fDeleteOldApp)
  659. {
  660. DBG_ASSERT(fCreateNewApp);
  661. hr = g_WamRegGlobal.DeleteApp(pwszFormattedPath, FALSE, FALSE);
  662. if (FAILED(hr))
  663. {
  664. DBGPRINTF((DBG_CONTEXT, "Failed to delete old application on path %S, hr = 08x\n",
  665. szMDPath,
  666. hr));
  667. }
  668. }
  669. if (fCreateNewApp)
  670. {
  671. if (dwAppModeIn == eAppRunOutProcInDefaultPool)
  672. {
  673. hr = g_WamRegGlobal.CreatePooledApp(pwszFormattedPath, FALSE);
  674. }
  675. else if (dwAppModeIn == eAppRunInProc)
  676. {
  677. hr = g_WamRegGlobal.CreatePooledApp(pwszFormattedPath, TRUE);
  678. }
  679. else
  680. {
  681. hr = g_WamRegGlobal.CreateOutProcApp(pwszFormattedPath);
  682. }
  683. if (FAILED(hr))
  684. {
  685. DBGPRINTF((DBG_CONTEXT, "Failed to create new application on path %S, hr = 08x\n",
  686. szMDPath,
  687. hr));
  688. }
  689. }
  690. }
  691. // Release a Lock
  692. g_WamRegGlobal.ReleaseAdmWriteLock();
  693. //
  694. // if pwszFormattedPath is not same as szMDPath
  695. // then FormatMetabasePath() did a memory allocation.
  696. //
  697. if (pwszFormattedPath != szMDPath)
  698. {
  699. delete [] pwszFormattedPath;
  700. pwszFormattedPath = NULL;
  701. }
  702. return hr;
  703. }
  704. //===============================================================================
  705. // Wam Admin Replication implementation
  706. //
  707. //===============================================================================
  708. /*===================================================================
  709. CWamAdmin::GetSignature
  710. Get signature of application configurations. A signature in WAMREG is a checksum from
  711. all the metabase paths that define application.
  712. Parameter:
  713. Return: HRESULT
  714. NOERROR if succeeds
  715. ===================================================================*/
  716. STDMETHODIMP CWamAdmin::GetSignature
  717. (
  718. /* [in] */ DWORD dwBufferSize,
  719. /* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer,
  720. /* [out */ DWORD __RPC_FAR *pdwMDRequiredBufferSize
  721. )
  722. {
  723. HRESULT hr = NOERROR;
  724. WCHAR *pbBufferTemp = NULL;
  725. DWORD dwBufferSizeTemp = 0;
  726. DWORD dwSignature = 0;
  727. DWORD dwRequiredSize = 0;
  728. WamRegMetabaseConfig MDConfig;
  729. //
  730. // Grab the Lock
  731. //
  732. g_WamRegGlobal.AcquireAdmWriteLock();
  733. hr = MDConfig.MDGetPropPaths(WamRegGlobal::g_szMDW3SVCRoot, MD_APP_ISOLATED, &pbBufferTemp, &dwBufferSizeTemp);
  734. if (SUCCEEDED(hr))
  735. {
  736. WCHAR *pszString = NULL;
  737. WCHAR *pszMetabasePath = NULL;
  738. DWORD dwSignatureofPath = 0;
  739. for (pszString = (LPWSTR)pbBufferTemp;
  740. *pszString != (WCHAR)'\0' && SUCCEEDED(hr);
  741. pszString += (wcslen(pszString) + 1))
  742. {
  743. dwRequiredSize += sizeof(DWORD);
  744. if (dwRequiredSize <= dwBufferSize)
  745. {
  746. hr = g_WamRegGlobal.ConstructFullPath(WamRegGlobal::g_szMDW3SVCRoot,
  747. WamRegGlobal::g_cchMDW3SVCRoot,
  748. pszString,
  749. &pszMetabasePath
  750. );
  751. if (SUCCEEDED(hr))
  752. {
  753. dwSignatureofPath = 0;
  754. hr = MDConfig.GetSignatureOnPath(pszMetabasePath, &dwSignatureofPath);
  755. if (SUCCEEDED(hr))
  756. {
  757. // Add Signature
  758. *(DWORD*)pbBuffer = dwSignatureofPath;
  759. pbBuffer += sizeof(DWORD);
  760. DBGPRINTF((DBG_CONTEXT, "Get Signature on path %S, signature = %08x\n",
  761. pszMetabasePath,
  762. dwSignatureofPath));
  763. }
  764. else
  765. {
  766. DBGPRINTF((DBG_CONTEXT, "Failed to get signature on path %S, hr = %08x\n",
  767. pszString,
  768. hr));
  769. DBG_ASSERT(hr);
  770. }
  771. delete [] pszMetabasePath;
  772. pszMetabasePath = NULL;
  773. }
  774. }
  775. }
  776. if (dwRequiredSize > dwBufferSize)
  777. {
  778. *pdwMDRequiredBufferSize = dwRequiredSize;
  779. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  780. }
  781. }
  782. else
  783. {
  784. DBGPRINTF((DBG_CONTEXT, "GetSignature: GetPropPaths failed hr = %08x\n", hr));
  785. }
  786. if (SUCCEEDED(hr))
  787. {
  788. *pdwMDRequiredBufferSize = dwRequiredSize;
  789. }
  790. if (pbBufferTemp != NULL)
  791. {
  792. delete [] pbBufferTemp;
  793. }
  794. //
  795. // Release the Lock
  796. //
  797. g_WamRegGlobal.ReleaseAdmWriteLock();
  798. return hr;
  799. }
  800. /*===================================================================
  801. CWamAdmin::Propagate
  802. Unused in WAMREG. NOOP.
  803. Parameter:
  804. Return: HRESULT
  805. NOERROR if succeeds
  806. ===================================================================*/
  807. STDMETHODIMP CWamAdmin::Propagate
  808. (
  809. /* [in] */ DWORD dwBufferSize,
  810. /* [size_is][in] */ unsigned char __RPC_FAR *pszBuffer
  811. )
  812. {
  813. return NOERROR;
  814. }
  815. /*===================================================================
  816. CWamAdmin::Propagate2
  817. This function is called after IIS replication, and triggers MTS to start
  818. replication pakcages, it calls IISComputerToComputer.
  819. Parameter:
  820. Return: HRESULT
  821. NOERROR if succeeds
  822. ===================================================================*/
  823. STDMETHODIMP CWamAdmin::Propagate2
  824. (
  825. /* [in] */ DWORD dwBufferSize,
  826. /* [size_is][in] */ unsigned char __RPC_FAR *pszBuffer,
  827. /* [in] */ DWORD dwSignatureMismatch
  828. )
  829. {
  830. //
  831. // IISComputerToComputer can not be called from inetinfo.exe, because IISComputerToComputer will
  832. // make cross-machine RPC call, and inetinfo is set to Local system, therefore, IISComputerToComputer
  833. // will fail at the authentication level.
  834. // move IISComputerToComputer to iissync.exe. Where iissync.exe has some user account & password.
  835. //
  836. return NOERROR;
  837. }
  838. /*===================================================================
  839. CWamAdmin::Serialize
  840. This function packs all neccessary infomation (path + WAMCLSID) for a target
  841. machine to prepare replication(DeSerialize).
  842. The only applications that we really care about are isolated applications.
  843. We need the path + WAMCLSID + APPID.
  844. CODEWORK
  845. See NT Bug 378371
  846. Replication of IIS COM+ applications has been broken for a long time
  847. but the all of the fixes I considered have some serious drawbacks.
  848. 1. Don't use comrepl to move the IIS applications. Serialize/Deserialize
  849. all the data needed to create the isolated applications and then delete
  850. and recreate them on the target. The problem here is that the packages
  851. may in fact be modified by the user and these modifications should be
  852. preserved.
  853. 2. Use comrepl as it is and replicate the IWAM_* account. This seems like
  854. a bad idea. The IWAM_ account should ideally never exist on multiple
  855. machines. Another issue is handling the password and account privileges.
  856. 3. Use a modified comrepl (or let comrepl fail and leave the package identity
  857. as "interactive user"). Then do a fixup of the activation identity.
  858. This doesn't work, because the Propogate/Propogate2 protocol is
  859. essentially useless. Changing this protocol on the next release
  860. is absolutely something that should be considered, although AppCenter
  861. probably makes it a moot point.
  862. The current implementation is option 1.
  863. Parameter:
  864. Return: HRESULT
  865. NOERROR if succeeds
  866. ===================================================================*/
  867. STDMETHODIMP CWamAdmin::Serialize
  868. (
  869. /* [in] */ DWORD dwBufferSize,
  870. /* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer,
  871. /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize
  872. )
  873. {
  874. HRESULT hr = NOERROR;
  875. WCHAR *pbBufferTemp = NULL;
  876. DWORD dwBufSizePath = 0;
  877. DWORD dwSizeForReturn = sizeof(DWORD);
  878. WamRegMetabaseConfig MDConfig;
  879. //
  880. // Grab the Lock
  881. //
  882. g_WamRegGlobal.AcquireAdmWriteLock();
  883. hr = MDConfig.MDGetPropPaths( WamRegGlobal::g_szMDW3SVCRoot,
  884. MD_APP_WAM_CLSID,
  885. &pbBufferTemp,
  886. &dwBufSizePath
  887. );
  888. if (SUCCEEDED(hr))
  889. {
  890. WCHAR *pszString = NULL;
  891. WCHAR *pszMetabasePath = NULL;
  892. WCHAR *pszAppName = NULL;
  893. WCHAR szWAMCLSID[uSizeCLSID];
  894. WCHAR szAppId[uSizeCLSID];
  895. DWORD dwSizeofRecord;
  896. DWORD cSizeMetabasePath = 0;
  897. DWORD cSizeAppName = 0;
  898. DWORD dwAppIsolated;
  899. for( pszString = (LPWSTR)pbBufferTemp;
  900. *pszString != (WCHAR)'\0';
  901. pszString += (wcslen(pszString) + 1))
  902. {
  903. // Clean up allocations
  904. if( pszMetabasePath != NULL )
  905. {
  906. delete [] pszMetabasePath;
  907. pszMetabasePath = NULL;
  908. }
  909. if( pszAppName != NULL )
  910. {
  911. delete [] pszAppName;
  912. pszAppName = NULL;
  913. }
  914. hr = g_WamRegGlobal.ConstructFullPath(
  915. WamRegGlobal::g_szMDW3SVCRoot,
  916. WamRegGlobal::g_cchMDW3SVCRoot,
  917. pszString,
  918. &pszMetabasePath
  919. );
  920. if( FAILED(hr) )
  921. {
  922. DBGERROR(( DBG_CONTEXT,
  923. "ConstructFullPath failed for base (%S) "
  924. "partial (%S) hr=%08x\n",
  925. WamRegGlobal::g_szMDW3SVCRoot,
  926. pszString,
  927. hr
  928. ));
  929. break;
  930. }
  931. if( g_WamRegGlobal.FIsW3SVCRoot( pszMetabasePath ) )
  932. {
  933. // Don't consider the root application
  934. continue;
  935. }
  936. hr = MDConfig.MDGetDWORD( pszMetabasePath,
  937. MD_APP_ISOLATED,
  938. &dwAppIsolated
  939. );
  940. if( FAILED(hr) )
  941. {
  942. DBGERROR(( DBG_CONTEXT,
  943. "Failed to get MD_APP_ISOLATED, hr=%08x\n",
  944. hr
  945. ));
  946. break;
  947. }
  948. if( dwAppIsolated != eAppRunOutProcIsolated )
  949. {
  950. // Don't consider non-isolated applications
  951. continue;
  952. }
  953. hr = MDConfig.MDGetIDs( pszMetabasePath,
  954. szWAMCLSID,
  955. szAppId,
  956. dwAppIsolated
  957. );
  958. if( FAILED(hr) )
  959. {
  960. DBGERROR(( DBG_CONTEXT,
  961. "Failed to get IDs for %S, hr = %08x\n",
  962. pszMetabasePath,
  963. hr
  964. ));
  965. break;
  966. }
  967. hr = MDConfig.MDGetAppName( pszMetabasePath,
  968. &pszAppName
  969. );
  970. if( FAILED(hr) )
  971. {
  972. DBGERROR(( DBG_CONTEXT,
  973. "Failed to get AppName for %S, hr = %08x\n",
  974. pszMetabasePath,
  975. hr
  976. ));
  977. break;
  978. }
  979. cSizeMetabasePath = wcslen(pszMetabasePath) + 1;
  980. cSizeAppName = wcslen(pszAppName) + 1;
  981. dwSizeofRecord = sizeof(DWORD) +
  982. ((2 * uSizeCLSID) * sizeof(WCHAR)) +
  983. (cSizeMetabasePath * sizeof(WCHAR)) +
  984. (cSizeAppName * sizeof(WCHAR));
  985. dwSizeForReturn += dwSizeofRecord;
  986. if (dwSizeForReturn <= dwBufferSize)
  987. {
  988. // Size
  989. *(DWORD *)pbBuffer = dwSizeofRecord;
  990. pbBuffer += sizeof(DWORD);
  991. // WAMCLSID
  992. memcpy( pbBuffer, szWAMCLSID, sizeof(WCHAR) * uSizeCLSID );
  993. pbBuffer += sizeof(WCHAR) * uSizeCLSID;
  994. // APPID
  995. memcpy( pbBuffer, szAppId, sizeof(WCHAR) * uSizeCLSID );
  996. pbBuffer += sizeof(WCHAR) * uSizeCLSID;
  997. // PATH
  998. memcpy( pbBuffer, pszMetabasePath, cSizeMetabasePath * sizeof(WCHAR) );
  999. pbBuffer += cSizeMetabasePath * sizeof(WCHAR);
  1000. // APPNAME
  1001. memcpy( pbBuffer, pszAppName, cSizeAppName * sizeof(WCHAR) );
  1002. pbBuffer += cSizeAppName * sizeof(WCHAR);
  1003. }
  1004. }
  1005. if (SUCCEEDED(hr))
  1006. {
  1007. if (dwSizeForReturn <= dwBufferSize)
  1008. {
  1009. *(DWORD*)pbBuffer = 0x0; // Ending Signature
  1010. }
  1011. else
  1012. {
  1013. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1014. }
  1015. *pdwMDRequiredBufferSize = dwSizeForReturn;
  1016. }
  1017. // Clean up allocations
  1018. if( pszMetabasePath != NULL )
  1019. {
  1020. delete [] pszMetabasePath;
  1021. pszMetabasePath = NULL;
  1022. }
  1023. if( pszAppName != NULL )
  1024. {
  1025. delete [] pszAppName;
  1026. pszAppName = NULL;
  1027. }
  1028. }
  1029. else
  1030. {
  1031. DBGERROR(( DBG_CONTEXT,
  1032. "Serialize: GetPropPaths failed hr = %08x\n",
  1033. hr
  1034. ));
  1035. }
  1036. //
  1037. // Release the Lock
  1038. //
  1039. g_WamRegGlobal.ReleaseAdmWriteLock();
  1040. if (pbBufferTemp)
  1041. {
  1042. delete [] pbBufferTemp;
  1043. }
  1044. return hr;
  1045. }
  1046. /*===================================================================
  1047. CWamAdmin::DeSerialize
  1048. This function unpacks all neccessary infomation (path + WAMCLSID) on a target
  1049. machine to prepare replication(DeSerialize).
  1050. The only applications that we really care about with replication are
  1051. isolated apps. This routine removes the existing out of process apps
  1052. and then recreates the applications that are sent over in pbBuffer.
  1053. CODEWORK - See comments in Serialize
  1054. Return: HRESULT
  1055. NOERROR if succeeds
  1056. ===================================================================*/
  1057. STDMETHODIMP CWamAdmin::DeSerialize
  1058. (
  1059. /* [in] */ DWORD dwBufferSize,
  1060. /* [size_is][in] */ unsigned char __RPC_FAR *pbBuffer
  1061. )
  1062. {
  1063. DWORD dwBufferSizeTemp= 0;
  1064. WCHAR* pbBufferTemp = NULL;
  1065. HRESULT hr = NOERROR;
  1066. WamRegMetabaseConfig MDConfig;
  1067. g_WamRegGlobal.AcquireAdmWriteLock();
  1068. hr = MDConfig.MDGetPropPaths( WamRegGlobal::g_szMDW3SVCRoot,
  1069. MD_APP_WAM_CLSID,
  1070. &pbBufferTemp,
  1071. &dwBufferSizeTemp
  1072. );
  1073. if (SUCCEEDED(hr))
  1074. {
  1075. //
  1076. // Remove all the existing isolated applications.
  1077. //
  1078. WCHAR * pszString = NULL;
  1079. WCHAR * pszMetabasePath = NULL;
  1080. DWORD dwAppIsolated;
  1081. for ( pszString = (LPWSTR)pbBufferTemp;
  1082. *pszString != (WCHAR)'\0';
  1083. pszString += (wcslen(pszString) + 1))
  1084. {
  1085. if( pszMetabasePath != NULL )
  1086. {
  1087. delete [] pszMetabasePath;
  1088. pszMetabasePath = NULL;
  1089. }
  1090. hr = g_WamRegGlobal.ConstructFullPath(
  1091. WamRegGlobal::g_szMDW3SVCRoot,
  1092. WamRegGlobal::g_cchMDW3SVCRoot,
  1093. pszString,
  1094. &pszMetabasePath
  1095. );
  1096. if( FAILED(hr) )
  1097. {
  1098. // This failure is fatal
  1099. DBGERROR(( DBG_CONTEXT,
  1100. "ConstructFullPath failed for base (%S) "
  1101. "partial (%S) hr=%08x\n",
  1102. WamRegGlobal::g_szMDW3SVCRoot,
  1103. pszString,
  1104. hr
  1105. ));
  1106. break;
  1107. }
  1108. hr = MDConfig.MDGetDWORD( pszMetabasePath,
  1109. MD_APP_ISOLATED,
  1110. &dwAppIsolated
  1111. );
  1112. if( FAILED(hr) )
  1113. {
  1114. DBGWARN(( DBG_CONTEXT,
  1115. "Failed to get MD_APP_ISOLATED at (%S) hr=%08x\n",
  1116. pszMetabasePath,
  1117. hr
  1118. ));
  1119. hr = NOERROR;
  1120. continue;
  1121. }
  1122. if( dwAppIsolated == eAppRunOutProcIsolated )
  1123. {
  1124. hr = g_WamRegGlobal.DeleteApp( pszMetabasePath, FALSE, FALSE );
  1125. if (FAILED(hr))
  1126. {
  1127. DBGWARN(( DBG_CONTEXT,
  1128. "Unable to delete app at %S, hr = %08x\n",
  1129. pszMetabasePath,
  1130. hr
  1131. ));
  1132. hr = NOERROR;
  1133. continue;
  1134. }
  1135. }
  1136. }
  1137. if( pszMetabasePath != NULL )
  1138. {
  1139. delete [] pszMetabasePath;
  1140. pszMetabasePath = NULL;
  1141. }
  1142. }
  1143. //
  1144. // Now go through the serialized data and create the
  1145. // necessary new applications.
  1146. //
  1147. BYTE * pbTemp = pbBuffer;
  1148. DWORD cTotalBytes = 0;
  1149. DWORD cRecBytes = 0;
  1150. WCHAR * szWAMCLSID = NULL;
  1151. WCHAR * szPath = NULL;
  1152. WCHAR * szAppId = NULL;
  1153. WCHAR * szAppName = NULL;
  1154. DBGPRINTF(( DBG_CONTEXT,
  1155. "DeSerialize: buffer size %d, \n",
  1156. dwBufferSize
  1157. ));
  1158. while( *((DWORD*)pbTemp) != 0x0 )
  1159. {
  1160. // SIZE
  1161. cRecBytes = *((DWORD*)pbTemp);
  1162. pbTemp += sizeof(DWORD);
  1163. // CLSID
  1164. szWAMCLSID = (WCHAR *)pbTemp;
  1165. pbTemp += uSizeCLSID * sizeof(WCHAR);
  1166. // APPID
  1167. szAppId = (WCHAR *)pbTemp;
  1168. pbTemp += uSizeCLSID * sizeof(WCHAR);
  1169. // PATH
  1170. szPath = (WCHAR *)pbTemp;
  1171. pbTemp += (wcslen(szPath) + 1) * sizeof(WCHAR);
  1172. // APPNAME
  1173. szAppName = (WCHAR *)pbTemp;
  1174. pbTemp += (wcslen(szAppName) + 1) * sizeof(WCHAR);
  1175. // TODO - This should really be output based on a flag
  1176. DBGPRINTF(( DBG_CONTEXT,
  1177. "Deserialize path = %S, WAMCLSID = %S.\n",
  1178. szPath,
  1179. szWAMCLSID
  1180. ));
  1181. // Should never serialize the w3svc root
  1182. DBG_ASSERT( !g_WamRegGlobal.FIsW3SVCRoot(szPath) );
  1183. hr = g_WamRegGlobal.CreateOutProcAppReplica( szPath,
  1184. szAppName,
  1185. szWAMCLSID,
  1186. szAppId
  1187. );
  1188. if( FAILED(hr) )
  1189. {
  1190. DBGERROR(( DBG_CONTEXT,
  1191. "Failed to create COM application. Path(%S) "
  1192. "Clsid(%S) AppId(%S). hr=%08x\n",
  1193. szPath,
  1194. szWAMCLSID,
  1195. szAppId,
  1196. hr
  1197. ));
  1198. // ??? Should we be continuing here ???
  1199. // Don't report an error if we are continuing
  1200. hr = NOERROR;
  1201. }
  1202. }
  1203. if (pbBufferTemp)
  1204. {
  1205. delete [] pbBufferTemp;
  1206. }
  1207. //
  1208. // Release the Lock
  1209. //
  1210. g_WamRegGlobal.ReleaseAdmWriteLock();
  1211. return hr;
  1212. }
  1213. /*===================================================================
  1214. CWamAdmin::FormatMetabasePath
  1215. This function format the input metabase path. If the metabase path has an
  1216. ending '/', this function will allocate a memory block and make a new string
  1217. without the ending '/'. This function will return a pointer to newly allocated
  1218. memory block. Otherwise, the function will return the pointer to
  1219. the input metabase path.
  1220. Parameter:
  1221. pwszMetabasePathIn input metabase path
  1222. ppwszMetabasePathOut pointer to the resulting pointer that contains the formatted
  1223. metabase path.
  1224. Return: HRESULT
  1225. NOERROR if succeeds
  1226. NOTE: if ppwszMetabasePathOut == pwszMetabasePathIn, then no memory allocation.
  1227. Otherwise, there is a memory allocation happened, and caller needs to free the
  1228. memory block passed out in ppwszMetabasePathOut.
  1229. ===================================================================*/
  1230. STDMETHODIMP CWamAdmin::FormatMetabasePath
  1231. (
  1232. /* [in] */ LPCWSTR pwszMetabasePathIn,
  1233. /* [out] */ LPWSTR *ppwszMetabasePathOut
  1234. )
  1235. {
  1236. HRESULT hr = NOERROR;
  1237. LPWSTR pResult = NULL;
  1238. DBG_ASSERT(pwszMetabasePathIn);
  1239. DBG_ASSERT(ppwszMetabasePathOut);
  1240. LONG cch = wcslen(pwszMetabasePathIn);
  1241. if (pwszMetabasePathIn[cch-1] == L'\\' ||
  1242. pwszMetabasePathIn[cch-1] == L'/')
  1243. {
  1244. //
  1245. // Need to start up with a new string, can not do it with old string.
  1246. //
  1247. pResult = new WCHAR[cch];
  1248. if (pResult != NULL)
  1249. {
  1250. wcsncpy(pResult, pwszMetabasePathIn, cch);
  1251. pResult[cch-1] = L'\0';
  1252. }
  1253. else
  1254. {
  1255. hr = HRESULT_FROM_WIN32(GetLastError());
  1256. DBGPRINTF((DBG_CONTEXT, "FormatMetabasePath, failed to allocate memory. hr = %08x\n",
  1257. hr));
  1258. }
  1259. if (pResult != NULL)
  1260. {
  1261. *ppwszMetabasePathOut = pResult;
  1262. }
  1263. }
  1264. else
  1265. {
  1266. *ppwszMetabasePathOut = (LPWSTR)pwszMetabasePathIn;
  1267. }
  1268. return hr;
  1269. }
  1270. //===============================================================================
  1271. //
  1272. // IIISApplicationAdmin implementation
  1273. //
  1274. //===============================================================================
  1275. #ifdef _IIS_6_0
  1276. /*===================================================================
  1277. DoesAppPoolExist
  1278. Determine whether the AppPool passed exists
  1279. Parameter:
  1280. szAppPoolId a AppPoolId
  1281. pfRet where to place whether or not the appPool exists
  1282. Return: HRESULT
  1283. ===================================================================*/
  1284. HRESULT
  1285. DoesAppPoolExist
  1286. (
  1287. LPCWSTR szAppPoolId,
  1288. BOOL * pfRet
  1289. )
  1290. {
  1291. DBG_ASSERT(pfRet);
  1292. WamRegMetabaseConfig MDConfig;
  1293. HRESULT hr = E_FAIL;
  1294. STACK_STRU(szPoolBuf, 64);
  1295. hr = szPoolBuf.Append(APPPOOLPATH);
  1296. if (FAILED(hr))
  1297. {
  1298. goto done;
  1299. }
  1300. hr = szPoolBuf.Append(szAppPoolId);
  1301. if (FAILED(hr))
  1302. {
  1303. goto done;
  1304. }
  1305. (*pfRet) = MDConfig.MDDoesPathExist(NULL, szPoolBuf.QueryStr());
  1306. hr = S_OK;
  1307. done:
  1308. return hr;
  1309. }
  1310. /*===================================================================
  1311. CWamAdmin::CreateApplication
  1312. Create an application on szMDPath, and add it to szAppPoolId AppPool.
  1313. Optionally create szAppPoolId
  1314. Parameter:
  1315. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  1316. dwAppMode mode to create application in
  1317. szAppPoolId AppPool to setup app in.
  1318. fCreatePool Whether or not to create the pool
  1319. Return: HRESULT
  1320. ===================================================================*/
  1321. STDMETHODIMP
  1322. CWamAdmin::CreateApplication
  1323. (
  1324. LPCWSTR szMDPath,
  1325. DWORD dwAppMode,
  1326. LPCWSTR szAppPoolId,
  1327. BOOL fCreatePool
  1328. )
  1329. {
  1330. HRESULT hr = S_OK;
  1331. WamRegMetabaseConfig MDConfig;
  1332. LPWSTR pwszFormattedPath = NULL;
  1333. if (NULL == szMDPath)
  1334. {
  1335. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1336. goto done;
  1337. }
  1338. //
  1339. // See FormatMetabasePath comment
  1340. //
  1341. hr = FormatMetabasePath(szMDPath, &pwszFormattedPath);
  1342. if (FAILED(hr))
  1343. {
  1344. goto done;
  1345. }
  1346. // BUGBUG: Do We need locking around all of this? Why is locking present in other places?
  1347. hr = AppCreate2(pwszFormattedPath, dwAppMode);
  1348. if (FAILED(hr))
  1349. {
  1350. goto done;
  1351. }
  1352. if (FALSE == fCreatePool && NULL == szAppPoolId)
  1353. {
  1354. //
  1355. // We weren't told to create an application pool
  1356. // and NULL was passed as the application pool,
  1357. // therefore do nothing wil the application pool
  1358. //
  1359. hr = S_OK;
  1360. goto done;
  1361. }
  1362. if (TRUE == fCreatePool)
  1363. {
  1364. //
  1365. // create the application pool that we were passed
  1366. //
  1367. hr = CreateApplicationPool(szAppPoolId);
  1368. if (FAILED(hr) &&
  1369. HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) != hr)
  1370. {
  1371. goto done;
  1372. }
  1373. }
  1374. else
  1375. {
  1376. //
  1377. // We weren't told to create the application pool,
  1378. // but one was passed in. Verify that it exists.
  1379. //
  1380. DBG_ASSERT(NULL != szAppPoolId);
  1381. BOOL fRet;
  1382. hr = DoesAppPoolExist(szAppPoolId, &fRet);
  1383. if (FAILED(hr))
  1384. {
  1385. goto done;
  1386. }
  1387. if (FALSE == fRet)
  1388. {
  1389. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  1390. goto done;
  1391. }
  1392. }
  1393. hr = MDConfig.MDSetStringProperty(NULL,
  1394. pwszFormattedPath,
  1395. MD_APP_APPPOOL_ID,
  1396. szAppPoolId,
  1397. IIS_MD_UT_SERVER,
  1398. METADATA_INHERIT);
  1399. if (FAILED(hr))
  1400. {
  1401. goto done;
  1402. }
  1403. hr = S_OK;
  1404. done:
  1405. //
  1406. // if pwszFormattedPath is not same as szMDPath
  1407. // then FormatMetabasePath() did a memory allocation.
  1408. //
  1409. if (pwszFormattedPath != szMDPath)
  1410. {
  1411. delete [] pwszFormattedPath;
  1412. pwszFormattedPath = NULL;
  1413. }
  1414. return hr;
  1415. }
  1416. /*===================================================================
  1417. CWamAdmin::DeleteApplication
  1418. Delete an application on a Metabase Path.
  1419. Parameter:
  1420. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  1421. fRecursive TRUE if wants to deleteRecoverable applications from all sub nodes of szMDPath,
  1422. FALSE otherwise.
  1423. Return: HRESULT
  1424. ===================================================================*/
  1425. STDMETHODIMP
  1426. CWamAdmin::DeleteApplication
  1427. (
  1428. LPCWSTR szMDPath,
  1429. BOOL fRecursive
  1430. )
  1431. {
  1432. return PrivateDeleteApplication(szMDPath,
  1433. fRecursive,
  1434. FALSE, // Recoverable?
  1435. TRUE); // RemoveAppPool?
  1436. }
  1437. /*===================================================================
  1438. CWamAdmin::CreateApplicationPool
  1439. Delete an application on a Metabase Path. If there is no application existed
  1440. before, it is no-op. It leaves AppIsolated untouched, because, this value is
  1441. needed in Recover operation.
  1442. Parameter:
  1443. szAppPool Application Pool to create
  1444. Return: HRESULT
  1445. ===================================================================*/
  1446. STDMETHODIMP
  1447. CWamAdmin::CreateApplicationPool
  1448. (
  1449. LPCWSTR szAppPool
  1450. )
  1451. {
  1452. HRESULT hr = S_OK;
  1453. WamRegMetabaseConfig MDConfig;
  1454. STACK_STRU(szBuf, 64);
  1455. // Acquire a Lock
  1456. g_WamRegGlobal.AcquireAdmWriteLock();
  1457. if (NULL == szAppPool)
  1458. {
  1459. hr = E_INVALIDARG;
  1460. goto done;
  1461. }
  1462. // concatenate the path into a buffer
  1463. hr = szBuf.Append(APPPOOLPATH);
  1464. if (FAILED(hr))
  1465. {
  1466. goto done;
  1467. }
  1468. hr = szBuf.Append(szAppPool);
  1469. if (FAILED(hr))
  1470. {
  1471. goto done;
  1472. }
  1473. hr = MDConfig.MDCreatePath(NULL, szBuf.QueryStr());
  1474. if (FAILED(hr))
  1475. {
  1476. goto done;
  1477. }
  1478. hr = MDConfig.MDSetKeyType(NULL, szBuf.QueryStr(), L"IIsApplicationPool");
  1479. if (FAILED(hr))
  1480. {
  1481. goto done;
  1482. }
  1483. done:
  1484. // Release a Lock
  1485. g_WamRegGlobal.ReleaseAdmWriteLock();
  1486. return hr;
  1487. }
  1488. /*===================================================================
  1489. CWamAdmin::DeleteApplicationPool
  1490. Delete an application pool. First check to see if ApplicationPool is empty.
  1491. If not, return ERROR_NOT_EMPTY. Otherwise, remove apppool.
  1492. Parameter:
  1493. szAppPool Application Pool to remove
  1494. Return: HRESULT
  1495. ===================================================================*/
  1496. STDMETHODIMP
  1497. CWamAdmin::DeleteApplicationPool
  1498. (
  1499. LPCWSTR szAppPool
  1500. )
  1501. {
  1502. HRESULT hr = S_OK;
  1503. UINT cchBstr = 0;
  1504. BOOL fRet = FALSE;
  1505. BSTR bstr = NULL;
  1506. WamRegMetabaseConfig MDConfig;
  1507. // BUGBUG: need locking around this?
  1508. if (NULL == szAppPool)
  1509. {
  1510. hr = E_INVALIDARG;
  1511. goto done;
  1512. }
  1513. hr = DoesAppPoolExist(szAppPool, &fRet);
  1514. if (FAILED(hr))
  1515. {
  1516. goto done;
  1517. }
  1518. if (FALSE == fRet)
  1519. {
  1520. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  1521. goto done;
  1522. }
  1523. hr = EnumerateApplicationsInPool(szAppPool, &bstr);
  1524. if (FAILED(hr))
  1525. {
  1526. goto done;
  1527. }
  1528. cchBstr = SysStringLen(bstr);
  1529. // were there two terminating NULLs to be written into out buffer?
  1530. if (!(cchBstr >= 2 && '\0' == bstr[0] && '\0' == bstr[1]))
  1531. {
  1532. hr = HRESULT_FROM_WIN32(ERROR_NOT_EMPTY);
  1533. goto done;
  1534. }
  1535. hr = MDConfig.MDDeleteKey(NULL, APPPOOLPATH, szAppPool);
  1536. if (FAILED(hr))
  1537. {
  1538. goto done;
  1539. }
  1540. hr = S_OK;
  1541. done:
  1542. if (bstr)
  1543. {
  1544. SysFreeString(bstr);
  1545. }
  1546. return hr;
  1547. }
  1548. /*===================================================================
  1549. DoesBeginWithLMW3SVCNRoot
  1550. Determine whether the string passed in starts with
  1551. /lm/w3svc/NNNN/root
  1552. where NNNN is greater than 0.
  1553. Parameter:
  1554. pszApp an metabase application path
  1555. pdwCharsAfter [OPTIONAL] - storage for the number of characters following /root
  1556. Return: BOOL
  1557. ===================================================================*/
  1558. const WCHAR MB_W3SVC[] = L"/lm/w3svc/";
  1559. const int LEN_MB_W3SVC = (sizeof(MB_W3SVC) / sizeof(WCHAR)) - 1;
  1560. const WCHAR MB_W3SVC_1_ROOT[] = L"/LM/W3SVC/1/ROOT";
  1561. const int LEN_MB_W3SVC_1_ROOT = (sizeof(MB_W3SVC_1_ROOT) / sizeof(WCHAR)) - 1;
  1562. const WCHAR MB_ROOT[] = L"/Root";
  1563. const int LEN_MB_ROOT = (sizeof(MB_ROOT) / sizeof(WCHAR)) - 1;
  1564. BOOL
  1565. DoesBeginWithLMW3SVCNRoot
  1566. (
  1567. LPCWSTR pszApp,
  1568. DWORD * pdwCharsAfter = NULL
  1569. )
  1570. {
  1571. DBG_ASSERT(pszApp);
  1572. BOOL fRet = FALSE;
  1573. WCHAR pBuf[256] = {0};
  1574. int iSite;
  1575. // must have at least this many characters to have a chance
  1576. if (wcslen(pszApp) < LEN_MB_W3SVC_1_ROOT)
  1577. {
  1578. goto done;
  1579. }
  1580. // Applications must have \lm\w3svc\ at the front
  1581. if (0 != _wcsnicmp(MB_W3SVC, pszApp, LEN_MB_W3SVC))
  1582. {
  1583. goto done;
  1584. }
  1585. // Advance the pointer by enough characters
  1586. pszApp += LEN_MB_W3SVC;
  1587. // _wtoi returns as many characters as possible in a string before hitting a non-number or NULL
  1588. // if there is no number, the return is 0.
  1589. iSite = _wtoi(pszApp);
  1590. // Applications must then have a number that is >=1
  1591. if (0 == iSite)
  1592. {
  1593. goto done;
  1594. }
  1595. // get the count of numbers read from the string
  1596. _itow(iSite, pBuf, 10);
  1597. // advance the pointer by enough characters.
  1598. pszApp += wcslen(pBuf);
  1599. // Applications must them have "/Root"
  1600. if (0 != _wcsnicmp(pszApp, MB_ROOT, LEN_MB_ROOT))
  1601. {
  1602. goto done;
  1603. }
  1604. // if caller wants a count of characters following /Root
  1605. if (pdwCharsAfter)
  1606. {
  1607. // advance the pointer by enough characters
  1608. pszApp += LEN_MB_ROOT;
  1609. // get the remaining length
  1610. *pdwCharsAfter = wcslen(pszApp);
  1611. }
  1612. fRet = TRUE;
  1613. done:
  1614. return fRet;
  1615. }
  1616. /*===================================================================
  1617. IsRootApplication
  1618. Determine whether the string passed in is of the form:
  1619. /lm/w3svc/NNNN/root/
  1620. where NNNN is greater than 0.
  1621. And no additional characters following
  1622. Parameter:
  1623. pszApp an metabase application path
  1624. Return: BOOL
  1625. ===================================================================*/
  1626. BOOL
  1627. IsRootApplication
  1628. (
  1629. LPCWSTR pszApp
  1630. )
  1631. {
  1632. DWORD dwCharsAfter = 0;
  1633. // Root applications must begin with /lm/w3svc/nnn/root
  1634. if (!DoesBeginWithLMW3SVCNRoot(pszApp, &dwCharsAfter))
  1635. {
  1636. return FALSE;
  1637. }
  1638. // we expect at most a trailing '/' after /lm/w3svc/nnn/root.
  1639. // If there is more, this was not a root application
  1640. if(1 < dwCharsAfter)
  1641. {
  1642. return FALSE;
  1643. }
  1644. return TRUE;
  1645. }
  1646. /*===================================================================
  1647. IsApplication
  1648. Determine whether or not APP_ISOLATED is set at the passed in path
  1649. Parameter:
  1650. pszApp an metabase application path
  1651. pfIsApp If this node is an application
  1652. Return: HRESULT
  1653. ===================================================================*/
  1654. HRESULT
  1655. IsApplication
  1656. (
  1657. LPCWSTR pszApp,
  1658. BOOL *pfIsApp
  1659. )
  1660. {
  1661. HRESULT hr = S_OK;
  1662. WamRegMetabaseConfig MDConfig;
  1663. DWORD dwData;
  1664. DBG_ASSERT(pfIsApp);
  1665. *pfIsApp = FALSE;
  1666. if ( !DoesBeginWithLMW3SVCNRoot(pszApp) )
  1667. {
  1668. goto done;
  1669. }
  1670. hr = MDConfig.MDGetDWORD(pszApp, MD_APP_ISOLATED, &dwData);
  1671. if (HRESULT_FROM_WIN32(MD_ERROR_DATA_NOT_FOUND) == hr)
  1672. {
  1673. hr = S_OK;
  1674. goto done;
  1675. }
  1676. if (FAILED(hr))
  1677. {
  1678. goto done;
  1679. }
  1680. // MD_APP_ISOLATED was present at this node, not inherited
  1681. *pfIsApp = TRUE;
  1682. hr = S_OK;
  1683. done:
  1684. return hr;
  1685. }
  1686. /*===================================================================
  1687. IsAppInAppPool
  1688. Determine whether the App is in Pool
  1689. Parameter:
  1690. pszApp an metabase application path
  1691. pszPool an applicationPool ID
  1692. Return: BOOL
  1693. ===================================================================*/
  1694. BOOL
  1695. IsAppInAppPool
  1696. (
  1697. LPCWSTR pszApp,
  1698. LPCWSTR pszPool
  1699. )
  1700. {
  1701. DBG_ASSERT(pszApp);
  1702. DBG_ASSERT(pszPool);
  1703. HRESULT hr = E_FAIL;
  1704. BOOL fRet = FALSE;
  1705. LPWSTR pBuf = NULL;
  1706. WamRegMetabaseConfig MDConfig;
  1707. hr = MDConfig.MDGetStringAttribute(pszApp, MD_APP_APPPOOL_ID, &pBuf);
  1708. if (FAILED(hr) || NULL == pBuf)
  1709. {
  1710. goto done;
  1711. }
  1712. if (0 == _wcsicmp(pBuf, pszPool))
  1713. {
  1714. fRet = TRUE;
  1715. }
  1716. done:
  1717. delete [] pBuf;
  1718. return fRet;
  1719. }
  1720. /*===================================================================
  1721. CWamAdmin::EnumerateApplicationsInPool
  1722. Determine what applications are setup to point to the given pool.
  1723. Parameter:
  1724. szPool Application Pool enumerate
  1725. pbstrBuffer Where to store the pointer to allocated memory for application paths
  1726. Return: HRESULT
  1727. S_OK if buffer filled with a MULTISZ - if empty, double NULL at beginning
  1728. ===================================================================*/
  1729. STDMETHODIMP
  1730. CWamAdmin::EnumerateApplicationsInPool
  1731. (
  1732. LPCWSTR szPool,
  1733. BSTR* pbstrBuffer
  1734. )
  1735. {
  1736. HRESULT hr = E_FAIL;
  1737. WamRegMetabaseConfig MDConfig;
  1738. MULTISZ mszApplicationsInPool;
  1739. WCHAR * pBuffer = NULL;
  1740. UINT cchMulti = 0;
  1741. DWORD dwBufferSize = 0;
  1742. if (NULL == szPool ||
  1743. NULL == pbstrBuffer
  1744. )
  1745. {
  1746. hr = E_INVALIDARG;
  1747. goto done;
  1748. }
  1749. *pbstrBuffer = NULL;
  1750. // First get all of the root applications
  1751. {
  1752. hr = MDConfig.MDGetAllSiteRoots(&pBuffer);
  1753. if (FAILED(hr))
  1754. {
  1755. goto done;
  1756. }
  1757. const WCHAR * pTestBuf = pBuffer;
  1758. while(pTestBuf && pTestBuf[0])
  1759. {
  1760. DBG_ASSERT(IsRootApplication(pTestBuf));
  1761. if ( IsAppInAppPool(pTestBuf, szPool) )
  1762. {
  1763. if (FALSE == mszApplicationsInPool.Append(pTestBuf))
  1764. {
  1765. hr = E_OUTOFMEMORY;
  1766. goto done;
  1767. }
  1768. }
  1769. // move pTestBuf beyond end of this string, including NULL terminator.
  1770. pTestBuf += wcslen(pTestBuf) + 1;
  1771. }
  1772. delete [] pBuffer;
  1773. pBuffer = NULL;
  1774. }
  1775. // now get any other applications that have APPISOLATED set
  1776. {
  1777. hr = MDConfig.MDGetPropPaths(NULL,
  1778. MD_APP_ISOLATED,
  1779. &pBuffer,
  1780. &dwBufferSize
  1781. );
  1782. if (FAILED(hr))
  1783. {
  1784. goto done;
  1785. }
  1786. {
  1787. const WCHAR * pTestBuf = pBuffer;
  1788. while (pTestBuf && pTestBuf[0])
  1789. {
  1790. // root applications have already been added
  1791. // the path needs to be an application
  1792. // and the application needs to be in the app pool
  1793. if ( !IsRootApplication(pTestBuf) &&
  1794. DoesBeginWithLMW3SVCNRoot(pTestBuf) &&
  1795. IsAppInAppPool(pTestBuf, szPool) )
  1796. {
  1797. if (FALSE == mszApplicationsInPool.Append(pTestBuf))
  1798. {
  1799. hr = E_OUTOFMEMORY;
  1800. goto done;
  1801. }
  1802. }
  1803. // move pTestBuf beyond end of this string, including NULL terminator.
  1804. pTestBuf += wcslen(pTestBuf) + 1;
  1805. }
  1806. }
  1807. }
  1808. // now get any keys that have APPPOOLID set
  1809. {
  1810. hr = MDConfig.MDGetPropPaths(NULL,
  1811. MD_APP_APPPOOL_ID,
  1812. &pBuffer,
  1813. &dwBufferSize
  1814. );
  1815. if (FAILED(hr))
  1816. {
  1817. goto done;
  1818. }
  1819. {
  1820. const WCHAR * pTestBuf = pBuffer;
  1821. while (pTestBuf && pTestBuf[0])
  1822. {
  1823. BOOL fIsApplication = FALSE;
  1824. // root applications have already been added
  1825. // the path needs to be an application
  1826. // and the application needs to be in the app pool
  1827. hr = IsApplication(pTestBuf, &fIsApplication);
  1828. if (FAILED(hr))
  1829. {
  1830. goto done;
  1831. }
  1832. if ( !IsRootApplication(pTestBuf) &&
  1833. DoesBeginWithLMW3SVCNRoot(pTestBuf) &&
  1834. !fIsApplication &&
  1835. IsAppInAppPool(pTestBuf, szPool) )
  1836. {
  1837. if (FALSE == mszApplicationsInPool.Append(pTestBuf))
  1838. {
  1839. hr = E_OUTOFMEMORY;
  1840. goto done;
  1841. }
  1842. }
  1843. // move pTestBuf beyond end of this string, including NULL terminator.
  1844. pTestBuf += wcslen(pTestBuf) + 1;
  1845. }
  1846. }
  1847. }
  1848. // have the data in a MULTISZ - move it to the outgoing BSTR
  1849. cchMulti = mszApplicationsInPool.QueryCCH();
  1850. *pbstrBuffer = SysAllocStringLen(NULL, cchMulti);
  1851. if (NULL == *pbstrBuffer)
  1852. {
  1853. hr = E_OUTOFMEMORY;
  1854. goto done;
  1855. }
  1856. dwBufferSize = cchMulti;
  1857. mszApplicationsInPool.CopyToBuffer(*pbstrBuffer, &dwBufferSize);
  1858. hr = S_OK;
  1859. done:
  1860. delete [] pBuffer;
  1861. pBuffer = NULL;
  1862. return hr;
  1863. }
  1864. /*===================================================================
  1865. QueryW3SVCStatus
  1866. Using the ServiceControlManager, determine the current state of W3SVC
  1867. pfRunning return bool value - TRUE if running, otherwise FALSE
  1868. Return: HRESULT
  1869. S_OK if able to read status. HRESULT_FROM_WIN32 error otherwise
  1870. ===================================================================*/
  1871. HRESULT
  1872. QueryW3SVCStatus
  1873. (
  1874. BOOL * pfRunning
  1875. )
  1876. {
  1877. DBG_ASSERT(pfRunning);
  1878. *pfRunning = FALSE;
  1879. HRESULT hr = E_FAIL;
  1880. BOOL fRet = FALSE;
  1881. SC_HANDLE hSCM = 0;
  1882. SC_HANDLE hService = 0;
  1883. SERVICE_STATUS ssStatus;
  1884. ZeroMemory(&ssStatus, sizeof(ssStatus));
  1885. // first, get the service control manager
  1886. hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  1887. if (NULL == hSCM)
  1888. {
  1889. hr = HRESULT_FROM_WIN32(GetLastError());
  1890. goto done;
  1891. }
  1892. // now get the w3svc service
  1893. hService = OpenService(hSCM, "W3SVC", SERVICE_QUERY_STATUS);
  1894. if (NULL == hService)
  1895. {
  1896. hr = HRESULT_FROM_WIN32(GetLastError());
  1897. goto done;
  1898. }
  1899. // now ask for the status
  1900. fRet = QueryServiceStatus(hService, &ssStatus);
  1901. if (FALSE == fRet)
  1902. {
  1903. hr = HRESULT_FROM_WIN32(GetLastError());
  1904. goto done;
  1905. }
  1906. if (SERVICE_RUNNING == ssStatus.dwCurrentState)
  1907. {
  1908. *pfRunning = TRUE;
  1909. }
  1910. hr = S_OK;
  1911. done:
  1912. if (0 != hService)
  1913. {
  1914. CloseServiceHandle(hService);
  1915. }
  1916. if (0 != hSCM)
  1917. {
  1918. CloseServiceHandle(hSCM);
  1919. }
  1920. return hr;
  1921. }
  1922. /*===================================================================
  1923. GetWASIfRunning
  1924. Get a pointer to WAS iff w3svc is already running.
  1925. ppiW3Control where to store the addref'ed pointer if it can be gotten
  1926. Return: HRESULT
  1927. S_OK if pointer retrieved
  1928. HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE) if W3SVC is not up
  1929. +other error codes
  1930. ===================================================================*/
  1931. HRESULT
  1932. GetWASIfRunning
  1933. (
  1934. IW3Control ** ppiW3Control
  1935. )
  1936. {
  1937. DBG_ASSERT(ppiW3Control);
  1938. *ppiW3Control = NULL;
  1939. HRESULT hr = E_FAIL;
  1940. //
  1941. // Note we used to have to first check if WAS was running
  1942. // before doing this call, to avoid starting it up by accident.
  1943. // However, now that we have fixed the launch permission acl
  1944. // correctly, we no longer need to do this check. This should
  1945. // explain the name of this procedure.
  1946. //
  1947. hr = CoCreateInstance(CLSID_W3Control,
  1948. NULL,
  1949. CLSCTX_ALL,
  1950. IID_IW3Control,
  1951. reinterpret_cast<void**>(ppiW3Control));
  1952. if (FAILED(hr))
  1953. {
  1954. goto done;
  1955. }
  1956. hr = S_OK;
  1957. done:
  1958. return hr;
  1959. }
  1960. /*===================================================================
  1961. ValidateAccessToMetabaseKey
  1962. Determine whether the caller has write access to the given metabase key
  1963. pPath - path to check write access on
  1964. dwAccess - access to check for
  1965. Return: HRESULT
  1966. S_OK if access allowed
  1967. otherwise failure
  1968. ===================================================================*/
  1969. HRESULT
  1970. ValidateAccessToMetabaseKey(LPCWSTR pPath, DWORD dwAccess)
  1971. {
  1972. HRESULT hr = S_OK;
  1973. IMSAdminBase * pIMSAdminBase = NULL;
  1974. METADATA_HANDLE hMB = NULL;
  1975. METADATA_RECORD mdr;
  1976. DWORD dwTemp = 0x1234;
  1977. BOOL fImpersonated = FALSE;
  1978. hr = CoCreateInstance(
  1979. CLSID_MSAdminBase, // CLSID
  1980. NULL, // controlling unknown
  1981. CLSCTX_SERVER, // desired context
  1982. IID_IMSAdminBase, // IID
  1983. ( VOID * * ) ( &pIMSAdminBase ) // returned interface
  1984. );
  1985. if (FAILED(hr))
  1986. {
  1987. goto done;
  1988. }
  1989. hr = CoImpersonateClient();
  1990. if (RPC_E_CALL_COMPLETE == hr)
  1991. {
  1992. hr = S_OK;
  1993. goto done;
  1994. }
  1995. if (FAILED(hr))
  1996. {
  1997. goto done;
  1998. }
  1999. fImpersonated = TRUE;
  2000. hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  2001. pPath,
  2002. dwAccess,
  2003. 1, // no need to actually get the handle - therefore set a low timeout. Access check occurs before the attempt to get the handle
  2004. &hMB );
  2005. if ( hr == HRESULT_FROM_WIN32( ERROR_PATH_BUSY ) )
  2006. {
  2007. hr = S_OK;
  2008. hMB = NULL;
  2009. }
  2010. if ( FAILED(hr) )
  2011. {
  2012. goto done;
  2013. }
  2014. hr = S_OK;
  2015. done:
  2016. if ( fImpersonated )
  2017. {
  2018. // ignore the return value on purpose
  2019. CoRevertToSelf();
  2020. }
  2021. if ( hMB )
  2022. {
  2023. DBG_ASSERT( NULL != pIMSAdminBase );
  2024. DBG_REQUIRE( pIMSAdminBase->CloseKey( hMB ) == S_OK );
  2025. hMB = NULL;
  2026. }
  2027. if (pIMSAdminBase)
  2028. {
  2029. pIMSAdminBase->Release();
  2030. pIMSAdminBase = NULL;
  2031. }
  2032. return hr;
  2033. }
  2034. /*===================================================================
  2035. ValidateAccessToAppPool
  2036. Determine whether the caller has write access to the given apppool
  2037. szAppPool - AppPool to check access on
  2038. Return: HRESULT
  2039. S_OK if access allowed
  2040. otherwise failure
  2041. ===================================================================*/
  2042. HRESULT
  2043. ValidateAccessToAppPool(LPCWSTR pAppPool)
  2044. {
  2045. HRESULT hr = S_OK;
  2046. STACK_STRU( strPath, 128 );
  2047. hr = strPath.Copy(L"\\LM\\W3SVC\\AppPools\\");
  2048. if (FAILED(hr))
  2049. {
  2050. goto done;
  2051. }
  2052. hr = strPath.Append(pAppPool);
  2053. if (FAILED(hr))
  2054. {
  2055. goto done;
  2056. }
  2057. hr = ValidateAccessToMetabaseKey(strPath.QueryStr(), METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE);
  2058. if (FAILED(hr))
  2059. {
  2060. goto done;
  2061. }
  2062. hr = S_OK;
  2063. done:
  2064. return hr;
  2065. }
  2066. /*===================================================================
  2067. CWamAdmin::RecycleApplicationPool
  2068. Restart the given application pool
  2069. szAppPool - AppPool to restart.
  2070. Return: HRESULT
  2071. S_OK if restarted
  2072. HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE) if W3SVC is not up
  2073. +other error codes
  2074. ===================================================================*/
  2075. STDMETHODIMP
  2076. CWamAdmin::RecycleApplicationPool
  2077. (
  2078. LPCWSTR szAppPool
  2079. )
  2080. {
  2081. HRESULT hr = E_FAIL;
  2082. IW3Control* piW3Control = NULL;
  2083. if (NULL == szAppPool)
  2084. {
  2085. hr = E_INVALIDARG;
  2086. goto done;
  2087. }
  2088. hr = ValidateAccessToAppPool(szAppPool);
  2089. if (FAILED(hr))
  2090. {
  2091. goto done;
  2092. }
  2093. hr = GetWASIfRunning(&piW3Control);
  2094. if (FAILED(hr))
  2095. {
  2096. goto done;
  2097. }
  2098. hr = piW3Control->RecycleAppPool(szAppPool);
  2099. if (FAILED(hr))
  2100. {
  2101. goto done;
  2102. }
  2103. hr = S_OK;
  2104. done:
  2105. ReleaseInterface(piW3Control);
  2106. return hr;
  2107. }
  2108. /*===================================================================
  2109. CWamAdmin::GetProcessMode
  2110. Retrieve the current process mode
  2111. pdwMode - where to store the mode
  2112. Populated with 1 if we are in new mode, 0 if we are in old mode
  2113. Return: HRESULT
  2114. S_OK if retrieved
  2115. HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE) if W3SVC is not up
  2116. +other error codes
  2117. ===================================================================*/
  2118. STDMETHODIMP
  2119. CWamAdmin::GetProcessMode
  2120. (
  2121. DWORD * pdwMode
  2122. )
  2123. {
  2124. HRESULT hr = E_FAIL;
  2125. IW3Control* piW3Control = NULL;
  2126. if (NULL == pdwMode)
  2127. {
  2128. hr = E_INVALIDARG;
  2129. goto done;
  2130. }
  2131. hr = ValidateAccessToMetabaseKey(L"\\LM\\W3SVC", METADATA_PERMISSION_READ);
  2132. if (FAILED(hr))
  2133. {
  2134. goto done;
  2135. }
  2136. if ( IsSSLReportingBackwardCompatibilityMode() )
  2137. {
  2138. *pdwMode = 0;
  2139. }
  2140. else
  2141. {
  2142. *pdwMode = 1;
  2143. }
  2144. hr = S_OK;
  2145. done:
  2146. ReleaseInterface(piW3Control);
  2147. return hr;
  2148. }
  2149. /*===================================================================
  2150. CWamAdmin::RecycleAppPoolContainingApp
  2151. Recycles the application pool associated with a given application
  2152. Parameter:
  2153. szMDPath a Metabase Path, in format of "/LM/W3SVC/..."
  2154. Return: HRESULT
  2155. ===================================================================*/
  2156. HRESULT
  2157. CWamAdmin::RecycleAppPoolContainingApp(LPCWSTR szPath)
  2158. {
  2159. DBG_ASSERT(szPath);
  2160. HRESULT hr = S_OK;
  2161. WamRegMetabaseConfig MDConfig;
  2162. // We want to recycle the apppool associated with this application
  2163. LPWSTR pszAppPool = NULL;
  2164. // first get the apppool
  2165. hr = MDConfig.MDGetStringAttribute( szPath,
  2166. MD_APP_APPPOOL_ID,
  2167. &pszAppPool);
  2168. if (SUCCEEDED(hr))
  2169. {
  2170. hr = RecycleApplicationPool(pszAppPool);
  2171. delete [] pszAppPool;
  2172. pszAppPool = NULL;
  2173. }
  2174. return hr;
  2175. }
  2176. #endif // _IIS_6_0
  2177. /*
  2178. CWamAdminFactory: Class Factory IUnknown Implementation
  2179. */
  2180. /*===================================================================
  2181. CWamAdminFactory::CWamAdminFactory
  2182. Parameter:
  2183. Return: HRESULT
  2184. NOERROR if succeeds
  2185. ===================================================================*/
  2186. CWamAdminFactory::CWamAdminFactory()
  2187. : m_cRef(1)
  2188. {
  2189. InterlockedIncrement((long *)&g_dwRefCount);
  2190. }
  2191. /*===================================================================
  2192. CWamAdminFactory::~CWamAdminFactory
  2193. Parameter:
  2194. Return: HRESULT
  2195. NOERROR if succeeds
  2196. ===================================================================*/
  2197. CWamAdminFactory::~CWamAdminFactory()
  2198. {
  2199. InterlockedDecrement((long *)&g_dwRefCount);
  2200. }
  2201. /*===================================================================
  2202. CWamAdminFactory::QueryInterface
  2203. Parameter:
  2204. Return: HRESULT
  2205. NOERROR if succeeds
  2206. ===================================================================*/
  2207. STDMETHODIMP CWamAdminFactory::QueryInterface(REFIID riid, void ** ppv)
  2208. {
  2209. if (riid==IID_IUnknown || riid == IID_IClassFactory)
  2210. {
  2211. *ppv = static_cast<IClassFactory *>(this);
  2212. AddRef();
  2213. }
  2214. else
  2215. {
  2216. *ppv = NULL;
  2217. return E_NOINTERFACE;
  2218. }
  2219. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  2220. return NOERROR;
  2221. }
  2222. /*===================================================================
  2223. CWamAdminFactory::AddRef
  2224. Parameter:
  2225. Return: HRESULT
  2226. NOERROR if succeeds
  2227. ===================================================================*/
  2228. STDMETHODIMP_(ULONG) CWamAdminFactory::AddRef( )
  2229. {
  2230. DWORD dwRefCount;
  2231. dwRefCount = InterlockedIncrement((long *)&m_cRef);
  2232. return dwRefCount;
  2233. }
  2234. /*===================================================================
  2235. CWamAdminFactory::Release
  2236. Parameter:
  2237. Return: HRESULT
  2238. NOERROR if succeeds
  2239. ===================================================================*/
  2240. STDMETHODIMP_(ULONG) CWamAdminFactory::Release( )
  2241. {
  2242. DWORD dwRefCount;
  2243. dwRefCount = InterlockedDecrement((long *)&m_cRef);
  2244. return dwRefCount;
  2245. }
  2246. /*===================================================================
  2247. CWamAdminFactory::CreateInstance
  2248. Parameter:
  2249. Return: HRESULT
  2250. NOERROR if succeeds
  2251. ===================================================================*/
  2252. STDMETHODIMP CWamAdminFactory::CreateInstance(IUnknown * pUnknownOuter, REFIID riid, void ** ppv)
  2253. {
  2254. if (pUnknownOuter != NULL)
  2255. {
  2256. return CLASS_E_NOAGGREGATION;
  2257. }
  2258. CWamAdmin *pWamAdmin = new CWamAdmin;
  2259. if (pWamAdmin == NULL)
  2260. {
  2261. return E_OUTOFMEMORY;
  2262. }
  2263. HRESULT hrReturn = pWamAdmin->QueryInterface(riid, ppv);
  2264. pWamAdmin->Release();
  2265. return hrReturn;
  2266. }
  2267. /*===================================================================
  2268. CWamAdminFactory::LockServer
  2269. Parameter:
  2270. Return: HRESULT
  2271. NOERROR if succeeds
  2272. ===================================================================*/
  2273. STDMETHODIMP CWamAdminFactory::LockServer(BOOL fLock)
  2274. {
  2275. if (fLock)
  2276. {
  2277. InterlockedIncrement((long *)&g_dwRefCount);
  2278. }
  2279. else
  2280. {
  2281. InterlockedDecrement((long *)&g_dwRefCount);
  2282. }
  2283. return NOERROR;
  2284. }
  2285. #if 0
  2286. // OBSOLETE - This fix (335422) was implemented in script but
  2287. // some of the code is general enough that it might be worth
  2288. // keeping around for a while.
  2289. STDMETHODIMP CWamAdmin::SynchWamAccountAll()
  2290. /*+
  2291. Routine Description:
  2292. Updates all out of process packages with the current IWAM_ account
  2293. values stored in the metabase.
  2294. There are a number of ways that the IWAM_ account information can get
  2295. out of sync between the metabase/sam/com+. The metabase contains code
  2296. to repair the IWAM_ and IUSR_ accounts on startup if there is a disconnect
  2297. with the SAM. If there is a disconnect with com+ calling this method will
  2298. repair it.
  2299. If the IWAM_ account does not match what is stored in the com catalog the
  2300. following error's will happen:
  2301. CoCreateInstance for WAM object returns CO_E_RUNAS_CREATEPROCESS_FAILURE
  2302. Event Log - DCOM 10004 - "Logon error"
  2303. Arguments:
  2304. None
  2305. Returns:
  2306. HRESULT
  2307. -*/
  2308. {
  2309. HRESULT hr = NOERROR;
  2310. // Get WAM user info from the metabase
  2311. WamRegMetabaseConfig mb;
  2312. // These are way too big...
  2313. WCHAR wszIWamUser[MAX_PATH];
  2314. WCHAR wszIWamPass[MAX_PATH];
  2315. hr = mb.MDGetIdentity( wszIWamUser,
  2316. sizeof(wszIWamUser),
  2317. wszIWamPass,
  2318. sizeof(wszIWamPass)
  2319. );
  2320. if( FAILED(hr) ) return hr;
  2321. // Init the com admin interface
  2322. WamRegPackageConfig comAdmin;
  2323. hr = comAdmin.CreateCatalog();
  2324. if( FAILED(hr) ) return hr;
  2325. //
  2326. // For each of the out of process applications,
  2327. // get the package and reset the metabase identity.
  2328. //
  2329. // After this failures cause a goto exit, which will release the lock
  2330. g_WamRegGlobal.AcquireAdmWriteLock();
  2331. WCHAR * wszPropPaths = NULL;
  2332. DWORD cbPropPaths = 0;
  2333. WCHAR * pwszPartialPath;
  2334. WCHAR * wszFullPath = NULL;
  2335. DWORD dwAppMode;
  2336. WCHAR wszWamClsid[uSizeCLSID];
  2337. WCHAR wszAppPackageId[uSizeCLSID];
  2338. // Reset the properties for the pooled package
  2339. hr = comAdmin.ResetPackageActivation(
  2340. g_WamRegGlobal.g_szIISOOPPoolPackageID,
  2341. wszIWamUser,
  2342. wszIWamPass
  2343. );
  2344. if( FAILED(hr) )
  2345. {
  2346. DBGPRINTF(( DBG_CONTEXT,
  2347. "comAdmin.ResetPackageActivation FAILED(%08x) on (%S)\n",
  2348. hr,
  2349. g_WamRegGlobal.g_szIISOOPPoolPackageID
  2350. ));
  2351. goto exit;
  2352. }
  2353. // Reset the properties for each isolated application
  2354. hr = mb.MDGetPropPaths( g_WamRegGlobal.g_szMDW3SVCRoot,
  2355. MD_APP_ISOLATED,
  2356. &wszPropPaths,
  2357. &cbPropPaths
  2358. );
  2359. if( FAILED(hr) )
  2360. {
  2361. DBGPRINTF(( DBG_CONTEXT,
  2362. "mb.MDGetPropPaths FAILED(%08x)\n",
  2363. hr
  2364. ));
  2365. goto exit;
  2366. }
  2367. if( SUCCEEDED(hr) )
  2368. {
  2369. for( pwszPartialPath = wszPropPaths;
  2370. *pwszPartialPath != L'\0';
  2371. pwszPartialPath += ( wcslen( pwszPartialPath ) + 1 )
  2372. )
  2373. {
  2374. if( wszFullPath )
  2375. {
  2376. delete [] wszFullPath;
  2377. wszFullPath = NULL;
  2378. }
  2379. hr = g_WamRegGlobal.ConstructFullPath(
  2380. WamRegGlobal::g_szMDW3SVCRoot,
  2381. WamRegGlobal::g_cchMDW3SVCRoot,
  2382. pwszPartialPath,
  2383. &wszFullPath
  2384. );
  2385. if( FAILED(hr) ) goto exit;
  2386. hr = mb.MDGetDWORD( wszFullPath, MD_APP_ISOLATED, &dwAppMode );
  2387. if( FAILED(hr) ) goto exit;
  2388. if( dwAppMode == eAppRunOutProcIsolated )
  2389. {
  2390. hr = mb.MDGetIDs( wszFullPath, wszWamClsid, wszAppPackageId, dwAppMode );
  2391. if( FAILED(hr) )
  2392. {
  2393. DBGPRINTF(( DBG_CONTEXT,
  2394. "mb.MDGetIDs FAILED(%08x) on (%S)\n",
  2395. hr,
  2396. wszFullPath
  2397. ));
  2398. continue;
  2399. }
  2400. hr = comAdmin.ResetPackageActivation( wszAppPackageId, wszIWamUser, wszIWamPass );
  2401. if( FAILED(hr) )
  2402. {
  2403. DBGPRINTF(( DBG_CONTEXT,
  2404. "comAdmin.ResetPackageActivation FAILED(%08x) on (%S)\n",
  2405. hr,
  2406. wszFullPath
  2407. ));
  2408. continue;
  2409. }
  2410. }
  2411. }
  2412. }
  2413. // goto exit on catastrophic failures, but if there is just
  2414. // an individual malformed application continue
  2415. exit:
  2416. g_WamRegGlobal.ReleaseAdmWriteLock();
  2417. if( FAILED(hr) )
  2418. {
  2419. DBGPRINTF(( DBG_CONTEXT,
  2420. "CWamAdmin::SynchWamAccountAll FAILED(%08x)\n",
  2421. hr
  2422. ));
  2423. }
  2424. if( wszPropPaths ) delete [] wszPropPaths;
  2425. if( wszFullPath ) delete [] wszFullPath;
  2426. return hr;
  2427. }
  2428. // OBSOLETE
  2429. #endif