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.

1621 lines
37 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. acwebsvc.cxx
  5. Abstract:
  6. This dll is the IIS app compat shim. Its purpose is
  7. to create appropriate metabase entries in the
  8. WebSvcExtRestrictionList and ApplicationDependencies
  9. properties.
  10. Author:
  11. Wade A. Hilmo (WadeH) 30-Apr-2002
  12. Project:
  13. AcWebSvc.dll
  14. --*/
  15. #include "precomp.hxx"
  16. #include <stdio.h>
  17. typedef VOID (WINAPI *_pfn_ExitProcess)(UINT uExitCode);
  18. #define WRITE_BUFFER_SIZE 1024
  19. //
  20. // Global Data
  21. //
  22. DECLARE_DEBUG_PRINTS_OBJECT();
  23. DECLARE_PLATFORM_TYPE();
  24. STRU g_strAppName;
  25. STRU g_strBasePath;
  26. STRU g_strPathType;
  27. STRU g_strWebSvcExtensions;
  28. STRU g_strGroupID;
  29. STRU g_strGroupDesc;
  30. STRU g_strEnableExtGroups;
  31. STRU g_strIndicatorFile;
  32. STRU g_strCookedBasePath;
  33. STRU g_strHonorDisabled;
  34. LIST_ENTRY g_Head;
  35. IMSAdminBase * g_pMetabase = NULL;
  36. BOOL g_fCoInitialized = FALSE;
  37. //
  38. // The DBG build of shimlib.lib introduces some
  39. // problems at both build time and run time. For
  40. // now, we'll just defeat DBG code. This project
  41. // has no dependencies on the DBG stuff anyway.
  42. //
  43. #ifdef DBG
  44. #undef DBG
  45. #define DBG_DISABLED
  46. #endif
  47. #include "ShimHook.h"
  48. HRESULT
  49. GetStringDataFromAppCompatDB(
  50. const PDB pdb,
  51. const TAGID TagId,
  52. LPCWSTR szName,
  53. STRU * pstrValue
  54. );
  55. using namespace ShimLib;
  56. IMPLEMENT_SHIM_STANDALONE(AcWebSvc)
  57. #include "ShimHookMacro.h"
  58. #ifdef DBG_DISABLED
  59. #undef DBG_DISABLED
  60. #define DBG
  61. #endif
  62. DECLARE_SHIM(AcWebSvc)
  63. APIHOOK_ENUM_BEGIN
  64. APIHOOK_ENUM_ENTRY(ExitProcess)
  65. APIHOOK_ENUM_END
  66. //
  67. // Function implementations
  68. //
  69. VOID
  70. APIHOOK(ExitProcess)(
  71. UINT uExitCode
  72. )
  73. {
  74. HRESULT hr;
  75. WriteDebug( L"EnableIIS shim notified of ExitProcess.\r\n" );
  76. hr = InitMetabase();
  77. if ( SUCCEEDED( hr ) )
  78. {
  79. DoWork( COMMAND_LINE );
  80. UninitMetabase();
  81. }
  82. ORIGINAL_API(ExitProcess)(uExitCode);
  83. }
  84. BOOL
  85. NOTIFY_FUNCTION(
  86. DWORD fdwReason)
  87. /*++
  88. Routine Description:
  89. AppCompat calls into this function at several points.
  90. For this shim, we are only interested in DLL_PROCESS_DETACH,
  91. which gets called when the shimmed process terminates.
  92. *** Note that DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH may
  93. look like DllMain entries. They are not. Please refer to
  94. the AppCompat documentation and other resources before making
  95. assumptions about the loader lock or any other process state.
  96. Arguments:
  97. fdwReason - The reason this function was called.
  98. Return Value:
  99. TRUE on success
  100. --*/
  101. {
  102. HRESULT hr;
  103. DWORD dwThreadId;
  104. //
  105. // Note that there are further cases besides attach and detach.
  106. //
  107. switch (fdwReason)
  108. {
  109. case DLL_PROCESS_ATTACH:
  110. break;
  111. case SHIM_STATIC_DLLS_INITIALIZED:
  112. break;
  113. case SHIM_PROCESS_DYING:
  114. break;
  115. default:
  116. break;
  117. }
  118. return TRUE;
  119. }
  120. /*++
  121. Register hooked functions
  122. --*/
  123. HOOK_BEGIN
  124. CALL_NOTIFY_FUNCTION
  125. APIHOOK_ENTRY(KERNEL32.DLL, ExitProcess)
  126. HOOK_END
  127. IMPLEMENT_SHIM_END
  128. BOOL
  129. DoWork(
  130. LPCSTR szCommandLine
  131. )
  132. {
  133. HRESULT hr;
  134. hr = ReadDataFromAppCompatDB( szCommandLine );
  135. if ( FAILED( hr ) )
  136. {
  137. goto Finished;
  138. }
  139. hr = BuildCookedBasePath( &g_strCookedBasePath );
  140. if ( FAILED( hr ) )
  141. {
  142. goto Finished;
  143. }
  144. hr = BuildListOfExtensions();
  145. if ( FAILED( hr ) )
  146. {
  147. goto Finished;
  148. }
  149. if ( IsApplicationInstalled() )
  150. {
  151. hr = InstallApplication();
  152. }
  153. else
  154. {
  155. hr = UninstallApplication();
  156. }
  157. Finished:
  158. if ( FAILED( hr ) )
  159. {
  160. WriteDebug( L"EnableIIS encountered errors performing lockdown "
  161. L"for application '%s'.\r\n",
  162. *g_strAppName.QueryStr() != L'\0' ? g_strAppName.QueryStr() : L"unknown" );
  163. SetLastError( WIN32_FROM_HRESULT( hr ) );
  164. }
  165. else
  166. {
  167. WriteDebug( L"EnableIIS shim completed successfully completed "
  168. L"lockdown registration for application '%s'.\r\n",
  169. g_strAppName.QueryStr() );
  170. }
  171. return SUCCEEDED( hr );
  172. }
  173. HRESULT
  174. ReadDataFromAppCompatDB(
  175. LPCSTR szCommandLine
  176. )
  177. {
  178. STRU strDatabasePath;
  179. LPSTR pGuid;
  180. LPSTR pTagId;
  181. LPSTR pCursor;
  182. GUID guid;
  183. PDB pdb;
  184. TAGID TagId;
  185. BOOL fResult;
  186. DWORD dwError;
  187. RPC_STATUS status;
  188. HRESULT hr = S_OK;
  189. //
  190. // Parse the command line
  191. //
  192. // Note that we are heavily dependent on the exact
  193. // syntax that app compat uses to call into us. This
  194. // code is based on their sample code, and it is
  195. // supposed to be the correct way to parse it...
  196. //
  197. pCursor = strstr( szCommandLine, "-d{" );
  198. if ( pCursor == NULL )
  199. {
  200. WriteDebug( L"Error parsing command line. Option '-d' not found.\r\n" );
  201. return E_FAIL;
  202. }
  203. pGuid = pCursor + 3;
  204. pCursor = strchr( pGuid, '}' );
  205. if ( pCursor == NULL )
  206. {
  207. WriteDebug( L"Error parsing command line. Option '-d' malformed.\r\n" );
  208. return E_FAIL;
  209. }
  210. *pCursor = NULL;
  211. pCursor++;
  212. pTagId = strstr( pCursor, "-t" );
  213. if ( pTagId == NULL )
  214. {
  215. WriteDebug( L"Error parsing command line. Option '-t' not found.\r\n" );
  216. return E_FAIL;
  217. }
  218. pTagId += 2;
  219. //
  220. // Get the GUID for the app compat database
  221. //
  222. status = UuidFromStringA( (unsigned char *)pGuid, &guid );
  223. if ( status != RPC_S_OK )
  224. {
  225. dwError = status;
  226. WriteDebug( L"Error %d occurred getting GUID from command line.\r\n",
  227. dwError );
  228. return HRESULT_FROM_WIN32( dwError );
  229. }
  230. hr = strDatabasePath.Resize( MAX_PATH );
  231. if ( FAILED( hr ) )
  232. {
  233. return hr;
  234. }
  235. fResult = SdbResolveDatabase( NULL,
  236. &guid,
  237. NULL,
  238. strDatabasePath.QueryStr(),
  239. MAX_PATH );
  240. if ( !fResult )
  241. {
  242. dwError = GetLastError();
  243. WriteDebug( L"Error %d occurred resolving AppCompat database.\r\n",
  244. dwError );
  245. return HRESULT_FROM_WIN32( dwError );
  246. }
  247. //
  248. // Open the database
  249. //
  250. pdb = SdbOpenDatabase( strDatabasePath.QueryStr(), DOS_PATH );
  251. if ( pdb == NULL )
  252. {
  253. dwError = GetLastError();
  254. WriteDebug( L"Error %d occurred opending AppCompat database.\r\n",
  255. dwError );
  256. return HRESULT_FROM_WIN32( dwError );
  257. }
  258. TagId = (TAGID)strtoul( pTagId, NULL, 0 );
  259. if ( TagId == TAGID_NULL )
  260. {
  261. WriteDebug( L"The shimref is invalid.\r\n" );
  262. return E_FAIL;
  263. }
  264. //
  265. // Read the data we need from the app compat database
  266. //
  267. // AppName is required. There are scenarios where any
  268. // of the others might be absent.
  269. //
  270. hr = GetStringDataFromAppCompatDB( pdb,
  271. TagId,
  272. L"AppName",
  273. &g_strAppName );
  274. if ( FAILED( hr ) )
  275. {
  276. WriteDebug( L"Error 0x%08x occurred getting 'AppName' from "
  277. L"AppCompat database.\r\n",
  278. hr );
  279. return hr;
  280. }
  281. hr = GetStringDataFromAppCompatDB( pdb,
  282. TagId,
  283. L"BasePath",
  284. &g_strBasePath );
  285. if ( FAILED( hr ) )
  286. {
  287. if ( FAILED( hr = g_strBasePath.Copy( L"" ) ) )
  288. {
  289. return hr;
  290. }
  291. }
  292. hr = GetStringDataFromAppCompatDB( pdb,
  293. TagId,
  294. L"PathType",
  295. &g_strPathType );
  296. if ( FAILED( hr ) )
  297. {
  298. if ( FAILED( hr = g_strPathType.Copy( L"" ) ) )
  299. {
  300. return hr;
  301. }
  302. }
  303. hr = GetStringDataFromAppCompatDB( pdb,
  304. TagId,
  305. L"WebSvcExtensions",
  306. &g_strWebSvcExtensions );
  307. if ( FAILED( hr ) )
  308. {
  309. if ( FAILED( hr = g_strWebSvcExtensions.Copy( L"" ) ) )
  310. {
  311. return hr;
  312. }
  313. }
  314. hr = GetStringDataFromAppCompatDB( pdb,
  315. TagId,
  316. L"GroupID",
  317. &g_strGroupID );
  318. if ( FAILED( hr ) )
  319. {
  320. if ( FAILED( hr = g_strGroupID.Copy( L"" ) ) )
  321. {
  322. return hr;
  323. }
  324. }
  325. hr = GetStringDataFromAppCompatDB( pdb,
  326. TagId,
  327. L"GroupDesc",
  328. &g_strGroupDesc );
  329. if ( FAILED( hr ) )
  330. {
  331. if ( FAILED( hr = g_strGroupDesc.Copy( L"" ) ) )
  332. {
  333. return hr;
  334. }
  335. }
  336. hr = GetStringDataFromAppCompatDB( pdb,
  337. TagId,
  338. L"EnableExtGroups",
  339. &g_strEnableExtGroups );
  340. if ( FAILED( hr ) )
  341. {
  342. if ( FAILED( hr = g_strEnableExtGroups.Copy( L"" ) ) )
  343. {
  344. return hr;
  345. }
  346. }
  347. hr = GetStringDataFromAppCompatDB( pdb,
  348. TagId,
  349. L"SetupIndicatorFile",
  350. &g_strIndicatorFile );
  351. if ( FAILED( hr ) )
  352. {
  353. if ( FAILED( hr = g_strIndicatorFile.Copy( L"" ) ) )
  354. {
  355. return hr;
  356. }
  357. }
  358. hr = GetStringDataFromAppCompatDB( pdb,
  359. TagId,
  360. L"HonorDisabledExtensionsAndDependencies",
  361. &g_strHonorDisabled );
  362. if ( FAILED( hr ) )
  363. {
  364. if ( FAILED( hr = g_strHonorDisabled.Copy( L"TRUE" ) ) )
  365. {
  366. return hr;
  367. }
  368. }
  369. return hr;
  370. }
  371. HRESULT
  372. GetStringDataFromAppCompatDB(
  373. const PDB pdb,
  374. const TAGID TagId,
  375. LPCWSTR szName,
  376. STRU * pstrValue
  377. )
  378. {
  379. DWORD dwError;
  380. DWORD dwDataType;
  381. DWORD cbData = 0;
  382. HRESULT hr = S_OK;
  383. //
  384. // Call the database with a NULL buffer to get the
  385. // necessary size.
  386. //
  387. dwError = SdbQueryDataExTagID( pdb,
  388. TagId,
  389. szName,
  390. &dwDataType,
  391. NULL,
  392. &cbData,
  393. NULL );
  394. if ( dwError != ERROR_INSUFFICIENT_BUFFER )
  395. {
  396. //
  397. // Don't write for ERROR_NOT_FOUND
  398. //
  399. if ( dwError != ERROR_NOT_FOUND )
  400. {
  401. WriteDebug( L"Error %d occurred getting '%s' from "
  402. L"AppCompat database.\r\n",
  403. dwError,
  404. szName );
  405. }
  406. return HRESULT_FROM_WIN32( dwError );
  407. }
  408. //
  409. // Resize the buffer and call it for real.
  410. //
  411. hr = pstrValue->Resize( cbData );
  412. if ( FAILED( hr ) )
  413. {
  414. return hr;
  415. }
  416. dwError = SdbQueryDataExTagID( pdb,
  417. TagId,
  418. szName,
  419. &dwDataType,
  420. pstrValue->QueryStr(),
  421. &cbData,
  422. NULL );
  423. if ( dwError != ERROR_SUCCESS )
  424. {
  425. return HRESULT_FROM_WIN32( dwError );
  426. }
  427. return hr;
  428. }
  429. HRESULT
  430. BuildListOfExtensions(
  431. VOID
  432. )
  433. {
  434. LPWSTR pExtension;
  435. LPWSTR pNext;
  436. EXTENSION_IMAGE * pRecord;
  437. HRESULT hr;
  438. InitializeListHead( &g_Head );
  439. pExtension = g_strWebSvcExtensions.QueryStr();
  440. //
  441. // If there are no extensions in the list,
  442. // we should just return now.
  443. //
  444. if ( *pExtension == L'\0' )
  445. {
  446. return S_OK;
  447. }
  448. //
  449. // Parse the list of extensions
  450. //
  451. while ( pExtension )
  452. {
  453. pNext = wcschr( pExtension, ',' );
  454. if ( pNext )
  455. {
  456. *pNext = L'\0';
  457. pNext++;
  458. }
  459. pRecord = new EXTENSION_IMAGE;
  460. if ( pRecord == NULL )
  461. {
  462. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  463. }
  464. hr = pRecord->strPath.Copy( g_strCookedBasePath.QueryStr() );
  465. if ( FAILED( hr ) )
  466. {
  467. delete pRecord;
  468. return hr;
  469. }
  470. hr = pRecord->strPath.Append( pExtension );
  471. if ( FAILED( hr ) )
  472. {
  473. delete pRecord;
  474. return hr;
  475. }
  476. InsertTailList( &g_Head, &pRecord->le );
  477. pExtension = pNext;
  478. }
  479. return hr;
  480. }
  481. HRESULT
  482. BuildCookedBasePath(
  483. STRU * pstrCookedBasePath
  484. )
  485. {
  486. STRU strBasePathFromReg;
  487. LPWSTR pCursor;
  488. LPWSTR pKeyName;
  489. LPWSTR pValueName;
  490. HKEY hRootKey;
  491. HKEY hKey;
  492. DWORD dwError;
  493. DWORD cbData;
  494. DWORD dwType;
  495. HRESULT hr;
  496. //
  497. // If the base path is a reg key, then get it now
  498. //
  499. if ( wcscmp( g_strPathType.QueryStr(), L"1" ) == 0 )
  500. {
  501. //
  502. // Get the root key
  503. //
  504. if ( _wcsnicmp( g_strBasePath.QueryStr(), L"HKEY_LOCAL_MACHINE", 18 ) == 0 )
  505. {
  506. hRootKey = HKEY_LOCAL_MACHINE;
  507. pKeyName = g_strBasePath.QueryStr() + 19;
  508. }
  509. else if ( _wcsnicmp( g_strBasePath.QueryStr(), L"HKEY_CURRENT_USER", 17 ) == 0 )
  510. {
  511. hRootKey = HKEY_CURRENT_USER;
  512. pKeyName = g_strBasePath.QueryStr() + 18;
  513. }
  514. else if ( _wcsnicmp( g_strBasePath.QueryStr(), L"HKEY_CLASSES_ROOT", 17 ) == 0 )
  515. {
  516. hRootKey = HKEY_CLASSES_ROOT;
  517. pKeyName = g_strBasePath.QueryStr() + 18;
  518. }
  519. else if ( _wcsnicmp( g_strBasePath.QueryStr(), L"HKEY_USERS", 10 ) == 0 )
  520. {
  521. hRootKey = HKEY_USERS;
  522. pKeyName = g_strBasePath.QueryStr() + 11;
  523. }
  524. else if ( _wcsnicmp( g_strBasePath.QueryStr(), L"HKEY_CURRENT_CONFIG", 19 ) == 0 )
  525. {
  526. hRootKey = HKEY_CURRENT_CONFIG;
  527. pKeyName = g_strBasePath.QueryStr() + 20;
  528. }
  529. else
  530. {
  531. WriteDebug( L"Registry key '%s' unknown.\r\n",
  532. g_strBasePath.QueryStr() );
  533. return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  534. }
  535. //
  536. // Split off the value name from the key name
  537. //
  538. pValueName = wcsrchr( pKeyName, '\\' );
  539. if ( pValueName == NULL )
  540. {
  541. return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  542. }
  543. *pValueName = L'\0';
  544. pValueName++;
  545. //
  546. // Ok, now get it from the registry
  547. //
  548. dwError = RegOpenKeyW( hRootKey,
  549. pKeyName,
  550. &hKey);
  551. if ( dwError != ERROR_SUCCESS )
  552. {
  553. return HRESULT_FROM_WIN32( dwError );
  554. }
  555. //
  556. // Get the data from the registry
  557. //
  558. cbData = strBasePathFromReg.QueryCB();
  559. dwError = RegQueryValueExW( hKey,
  560. pValueName,
  561. NULL,
  562. &dwType,
  563. (LPBYTE)strBasePathFromReg.QueryStr(),
  564. &cbData );
  565. if ( dwError == ERROR_MORE_DATA )
  566. {
  567. //
  568. // Resize the buffer and try again
  569. //
  570. hr = strBasePathFromReg.Resize( cbData );
  571. if ( FAILED( hr ) )
  572. {
  573. RegCloseKey( hKey );
  574. return hr;
  575. }
  576. dwError = RegQueryValueExW( hKey,
  577. pValueName,
  578. NULL,
  579. &dwType,
  580. (LPBYTE)strBasePathFromReg.QueryStr(),
  581. &cbData );
  582. }
  583. RegCloseKey( hKey );
  584. //
  585. // If we still don't have it, or if the key type
  586. // is wrong, then fail.
  587. //
  588. if ( dwError != ERROR_SUCCESS ||
  589. dwType != REG_SZ )
  590. {
  591. WriteDebug( L"Value '%s' not found in key '%s'.\r\n",
  592. pValueName,
  593. pKeyName );
  594. return HRESULT_FROM_WIN32( ERROR_NOT_FOUND );
  595. }
  596. //
  597. // Now set the base path from the registry into
  598. // the global
  599. //
  600. hr = g_strBasePath.Copy( strBasePathFromReg.QueryStr() );
  601. if ( FAILED( hr ) )
  602. {
  603. return hr;
  604. }
  605. }
  606. //
  607. // Ok, at this point, we can expand the global base path
  608. // into the return variable.
  609. //
  610. // Note that in testing, I found that calling ExpandEnvironmentStrings
  611. // twice, with the first call getting the size would cause AV's
  612. // with pageheap on the second call. So to work around the issue,
  613. // I'm just resizing the buffer to 16K, which should accommodate
  614. // any reasonable path.
  615. //
  616. hr = pstrCookedBasePath->Resize( 16384 );
  617. if ( FAILED( hr ) )
  618. {
  619. return hr;
  620. }
  621. cbData = ExpandEnvironmentStrings( g_strBasePath.QueryStr(),
  622. pstrCookedBasePath->QueryStr(),
  623. 16384 );
  624. return S_OK;
  625. }
  626. BOOL
  627. IsApplicationInstalled(
  628. VOID
  629. )
  630. {
  631. STRU strCookedIndicatorFile;
  632. LIST_ENTRY * ple;
  633. EXTENSION_IMAGE * pImage;
  634. HRESULT hr;
  635. BOOL fUseIndicator = FALSE;
  636. BOOL fResult = FALSE;
  637. //
  638. // If we have a setup indicator file, use it's presence to
  639. // determine in installation has occured.
  640. //
  641. if ( *g_strIndicatorFile.QueryStr() != L'\0' )
  642. {
  643. fUseIndicator = TRUE;
  644. hr = strCookedIndicatorFile.Copy( g_strCookedBasePath.QueryStr() );
  645. if ( FAILED( hr ) )
  646. {
  647. //
  648. // On error, assume not installed
  649. //
  650. return FALSE;
  651. }
  652. hr = strCookedIndicatorFile.Append( g_strIndicatorFile.QueryStr() );
  653. if ( FAILED( hr ) )
  654. {
  655. return FALSE;
  656. }
  657. fResult = DoesFileExist( strCookedIndicatorFile.QueryStr() );
  658. }
  659. //
  660. // No indicator file. Check for the existence of any ISAPI extensions
  661. // associated with the hooked application.
  662. //
  663. ple = g_Head.Flink;
  664. while ( ple != &g_Head )
  665. {
  666. pImage = CONTAINING_RECORD( ple,
  667. EXTENSION_IMAGE,
  668. le );
  669. if ( DoesFileExist( pImage->strPath.QueryStr() ) )
  670. {
  671. pImage->fExists = TRUE;
  672. if ( !fUseIndicator )
  673. {
  674. fResult = TRUE;
  675. }
  676. }
  677. else
  678. {
  679. pImage->fExists = FALSE;
  680. }
  681. ple = ple->Flink;
  682. }
  683. return fResult;
  684. }
  685. HRESULT
  686. InstallApplication(
  687. VOID
  688. )
  689. {
  690. HRESULT hr;
  691. WriteDebug( L"EnableIIS shim doing install for application '%s'.\r\n",
  692. g_strAppName.QueryStr() );
  693. //
  694. // Enable the application's extensions. Note that the
  695. // AddExtensionsToMetabase function will only add extensions
  696. // that are not already present in the metabase.
  697. //
  698. hr = AddExtensionsToMetabase();
  699. if ( FAILED( hr ) )
  700. {
  701. goto Finished;
  702. }
  703. //
  704. // Check to see if we already have an ApplicationDependencies
  705. // entry for this application. If we do, we should assume that
  706. // installation has already been done and we should take no
  707. // further action.
  708. //
  709. if ( IsApplicationAlreadyInstalled() )
  710. {
  711. WriteDebug( L"Application '%s' already registered "
  712. L"in metabase ApplicationDependencies key. "
  713. L"No changes will be made.",
  714. g_strAppName.QueryStr() );
  715. hr = S_OK;
  716. goto Finished;
  717. }
  718. //
  719. // Set the application's dependencies in the
  720. // metabase
  721. //
  722. hr = AddDependenciesToMetabase();
  723. if ( FAILED( hr ) )
  724. {
  725. goto Finished;
  726. }
  727. Finished:
  728. if ( FAILED( hr ) )
  729. {
  730. //
  731. // If we failed, then we should try to undo
  732. // our work so that we don't leave the application
  733. // in a bogus state.
  734. //
  735. WriteDebug( L"EnableIIS shim will undo work done so far.\r\n" );
  736. UninstallApplication();
  737. }
  738. else
  739. {
  740. WriteDebug( L"EnableIIS shim successfully registered lockdown "
  741. L"information for application '%s'.\r\n",
  742. g_strAppName.QueryStr() );
  743. }
  744. return hr;
  745. }
  746. HRESULT
  747. UninstallApplication(
  748. VOID
  749. )
  750. {
  751. HRESULT hr;
  752. WriteDebug( L"EnableIIS shim performing uninstall of application '%s'.\r\n",
  753. g_strAppName.QueryStr() );
  754. //
  755. // Remove the application's extensions from the
  756. // metabase.
  757. //
  758. hr = RemoveExtensionsFromMetabase();
  759. if ( FAILED( hr ) )
  760. {
  761. //
  762. // Report the failure, but let the function
  763. // continue to run. No action needs to be taken.
  764. //
  765. }
  766. //
  767. // Remove the application dependencies from the metabase
  768. //
  769. hr = RemoveDependenciesFromMetabase();
  770. if ( FAILED( hr ) )
  771. {
  772. //
  773. // Report the failure, but let the function
  774. // continue to run. No action needs to be taken.
  775. //
  776. }
  777. WriteDebug( L"EnableIIS uninstall of application '%s' completed.\r\n",
  778. g_strAppName.QueryStr() );
  779. return hr;
  780. }
  781. HRESULT
  782. InitMetabase(
  783. VOID
  784. )
  785. {
  786. HRESULT hr = S_OK;
  787. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  788. if ( SUCCEEDED( hr ) )
  789. {
  790. g_fCoInitialized = TRUE;
  791. }
  792. hr = CoCreateInstance( CLSID_MSAdminBase,
  793. NULL,
  794. CLSCTX_SERVER,
  795. IID_IMSAdminBase,
  796. (LPVOID *)&(g_pMetabase) );
  797. if ( FAILED( hr ) )
  798. {
  799. WriteDebug( L"Error 0x%0x8 occurred initializing metabase.\r\n" );
  800. UninitMetabase();
  801. }
  802. return hr;
  803. }
  804. HRESULT
  805. UninitMetabase(
  806. VOID
  807. )
  808. {
  809. if ( g_pMetabase != NULL )
  810. {
  811. g_pMetabase->Release();
  812. g_pMetabase = NULL;
  813. }
  814. if ( g_fCoInitialized )
  815. {
  816. CoUninitialize();
  817. g_fCoInitialized = FALSE;
  818. }
  819. return S_OK;
  820. }
  821. BOOL
  822. IsApplicationAlreadyInstalled(
  823. VOID
  824. )
  825. {
  826. LPWSTR pCursor;
  827. LPWSTR pAppList = NULL;
  828. DWORD cbAppList;
  829. HRESULT hr;
  830. BOOL fResult;
  831. DBG_ASSERT( g_pMetabase );
  832. CSecConLib SecHelper( g_pMetabase );
  833. //
  834. // We should return TRUE on any errors. This
  835. // will tell the caller that no shim work needs
  836. // to be done on install.
  837. //
  838. fResult = TRUE;
  839. //
  840. // Get app list from the metabase
  841. //
  842. hr = SecHelper.ListApplications( L"/LM/w3svc",
  843. &pAppList,
  844. &cbAppList );
  845. if ( FAILED( hr ) )
  846. {
  847. goto Finished;
  848. }
  849. pCursor = pAppList;
  850. //
  851. // Loop through the list from the metabase and
  852. // set fResult to FALSE if not present
  853. //
  854. fResult = FALSE;
  855. while ( *pCursor != L'\0' )
  856. {
  857. if ( _wcsicmp( pCursor, g_strAppName.QueryStr() ) == 0 )
  858. {
  859. fResult = TRUE;
  860. goto Finished;
  861. }
  862. pCursor += wcslen( pCursor ) + 1;
  863. }
  864. Finished:
  865. if ( pAppList != NULL )
  866. {
  867. delete [] pAppList;
  868. pAppList = NULL;
  869. }
  870. return fResult;
  871. }
  872. HRESULT
  873. AddExtensionsToMetabase(
  874. VOID
  875. )
  876. {
  877. LIST_ENTRY * ple;
  878. EXTENSION_IMAGE * pImage;
  879. HRESULT hr;
  880. DBG_ASSERT( g_pMetabase );
  881. CSecConLib SecHelper( g_pMetabase );
  882. WriteDebug( L"Adding extensions for '%s' to the metabase "
  883. L"WebSvcExtRestrictionList entry.\r\n",
  884. g_strAppName.QueryStr() );
  885. ple = g_Head.Flink;
  886. while ( ple != &g_Head )
  887. {
  888. pImage = CONTAINING_RECORD( ple,
  889. EXTENSION_IMAGE,
  890. le );
  891. //
  892. // Only add extensions that actually exist on the drive and
  893. // don't already exist in the restrictionlist.
  894. //
  895. if ( pImage->fExists )
  896. {
  897. if ( IsExtensionInMetabase( pImage->strPath.QueryStr() ) )
  898. {
  899. //
  900. // Already in metabase. Skip it.
  901. //
  902. WriteDebug( L" Skipping '%s' because it's already listed.\r\n",
  903. pImage->strPath.QueryStr() );
  904. }
  905. else
  906. {
  907. //
  908. // Need to add it to metabase.
  909. //
  910. WriteDebug( L" Adding '%s'.\r\n",
  911. pImage->strPath.QueryStr() );
  912. hr = SecHelper.AddExtensionFile( pImage->strPath.QueryStr(),
  913. TRUE, // Image should be enabled
  914. g_strGroupID.QueryStr(),
  915. FALSE, // Not UI deletable
  916. g_strGroupDesc.QueryStr(),
  917. L"/LM/w3svc" );
  918. if ( FAILED( hr ) )
  919. {
  920. //
  921. // A failure here shouldn't be fatal,
  922. // but we'll dump some debugger output for it
  923. //
  924. WriteDebug( L" Error 0x%08x occurred adding '%s' to "
  925. L"WebSvcExtRestrictionList.\r\n",
  926. hr,
  927. pImage->strPath.QueryStr() );
  928. }
  929. }
  930. }
  931. else
  932. {
  933. //
  934. // Hmm. The file must not exist any more.
  935. //
  936. if ( IsExtensionInMetabase( pImage->strPath.QueryStr() ) )
  937. {
  938. //
  939. // Need to remove it, since it's apparently been uninstalled.
  940. //
  941. WriteDebug( L" Removing '%s' because it's not on the disk.\r\n",
  942. pImage->strPath.QueryStr() );
  943. hr = SecHelper.DeleteExtensionFileRecord( pImage->strPath.QueryStr(),
  944. L"/LM/w3svc" );
  945. //
  946. // Don't consider 0x800cc801 (MD_ERROR_DATA_NOT_FOUND)
  947. // an error.
  948. //
  949. if ( hr == 0x800cc801 )
  950. {
  951. hr = S_OK;
  952. }
  953. if ( FAILED( hr ) )
  954. {
  955. //
  956. // A failure here shouldn't be fatal,
  957. // but we'll dump some debugger output for it
  958. //
  959. WriteDebug( L" Error 0x%08x occurred removing '%s' from "
  960. L"WebSvcExtRestrictionList.\r\n",
  961. hr,
  962. pImage->strPath.QueryStr() );
  963. }
  964. }
  965. else
  966. {
  967. WriteDebug( L" Skipping '%s' because it is not on the disk.\r\n",
  968. pImage->strPath.QueryStr() );
  969. }
  970. }
  971. ple = ple->Flink;
  972. }
  973. WriteDebug( L"Finished adding extensions for '%s'.\r\n",
  974. g_strAppName.QueryStr() );
  975. return S_OK;
  976. }
  977. HRESULT
  978. AddDependenciesToMetabase(
  979. VOID
  980. )
  981. {
  982. HRESULT hr;
  983. LPWSTR pGroupID;
  984. LPWSTR pCursor;
  985. LPWSTR pNext;
  986. DBG_ASSERT( g_pMetabase );
  987. CSecConLib SecHelper( g_pMetabase );
  988. WriteDebug( L"Adding dependencies for application '%s' to "
  989. L"metabase ApplicationDependencies list.\r\n",
  990. g_strAppName.QueryStr() );
  991. //
  992. // If the application depends on its own group,
  993. // add it now.
  994. //
  995. pGroupID = g_strGroupID.QueryStr();
  996. if ( *pGroupID != L'\0' )
  997. {
  998. WriteDebug( L" Adding '%s'...\r\n",
  999. pGroupID );
  1000. hr = SecHelper.AddDependency( g_strAppName.QueryStr(),
  1001. pGroupID,
  1002. L"/LM/w3svc" );
  1003. if ( FAILED( hr ) )
  1004. {
  1005. WriteDebug( L" Error 0x%08x occurred adding '%s' "
  1006. L"as a dependency of '%s'.\r\n",
  1007. hr,
  1008. pGroupID,
  1009. g_strAppName.QueryStr() );
  1010. return hr;
  1011. }
  1012. }
  1013. //
  1014. // If the application has outside dependencies,
  1015. // add them now
  1016. //
  1017. pGroupID = g_strEnableExtGroups.QueryStr();
  1018. while ( pGroupID )
  1019. {
  1020. pCursor = wcschr( pGroupID, L',' );
  1021. if ( pCursor )
  1022. {
  1023. *pCursor = '\0';
  1024. pNext = pCursor + 1;
  1025. }
  1026. else
  1027. {
  1028. pNext = NULL;
  1029. }
  1030. WriteDebug( L" Adding '%s'...\r\n",
  1031. pGroupID );
  1032. hr = SecHelper.AddDependency( g_strAppName.QueryStr(),
  1033. pGroupID,
  1034. L"/LM/w3svc" );
  1035. if ( FAILED( hr ) )
  1036. {
  1037. WriteDebug( L" Error 0x%08x occurred adding '%s' "
  1038. L"as a dependency of '%s'.\r\n",
  1039. hr,
  1040. pGroupID,
  1041. g_strAppName.QueryStr() );
  1042. return hr;
  1043. }
  1044. pGroupID = pNext;
  1045. }
  1046. WriteDebug( L"Finished adding application dependencies for '%s'.\r\n",
  1047. g_strAppName.QueryStr() );
  1048. //
  1049. // If we're going to throw caution to the wind and enable
  1050. // every extension and dependency of this application
  1051. // (regardless of whether the administrator disabled it for
  1052. // a good reason), do so now.
  1053. //
  1054. if ( _wcsicmp( g_strHonorDisabled.QueryStr(), L"false" ) == 0)
  1055. {
  1056. WriteDebug( L"Enabling all dependencies of '%s'. Please "
  1057. L"review the IIS lockdown status.\r\n",
  1058. g_strAppName.QueryStr() );
  1059. hr = SecHelper.EnableApplication( g_strAppName.QueryStr(),
  1060. L"/LM/w3svc" );
  1061. if ( FAILED( hr ) )
  1062. {
  1063. //
  1064. // This error is not fatal, but should be reported.
  1065. //
  1066. WriteDebug( L" Error %d occurred enabling dependencies of '%s'.\r\n",
  1067. hr,
  1068. g_strAppName.QueryStr() );
  1069. }
  1070. }
  1071. return S_OK;
  1072. }
  1073. HRESULT
  1074. RemoveExtensionsFromMetabase(
  1075. VOID
  1076. )
  1077. {
  1078. LIST_ENTRY * ple;
  1079. EXTENSION_IMAGE * pImage;
  1080. HRESULT hr;
  1081. DBG_ASSERT( g_pMetabase );
  1082. CSecConLib SecHelper( g_pMetabase );
  1083. WriteDebug( L"Removing extensions for '%s' from the metabase "
  1084. L"WebSvcExtRestrictionList entry.\r\n",
  1085. g_strAppName.QueryStr() );
  1086. ple = g_Head.Flink;
  1087. while ( ple != &g_Head )
  1088. {
  1089. pImage = CONTAINING_RECORD( ple,
  1090. EXTENSION_IMAGE,
  1091. le );
  1092. if ( IsExtensionInMetabase( pImage->strPath.QueryStr() ) )
  1093. {
  1094. WriteDebug( L" Removing '%s'...\r\n",
  1095. pImage->strPath.QueryStr() );
  1096. hr = SecHelper.DeleteExtensionFileRecord( pImage->strPath.QueryStr(),
  1097. L"/LM/w3svc" );
  1098. //
  1099. // Don't consider 0x800cc801 (MD_ERROR_DATA_NOT_FOUND)
  1100. // an error.
  1101. //
  1102. if ( hr == 0x800cc801 )
  1103. {
  1104. hr = S_OK;
  1105. }
  1106. if ( FAILED( hr ) )
  1107. {
  1108. //
  1109. // A failure here shouldn't be fatal,
  1110. // but we'll dump some debugger output for it
  1111. //
  1112. WriteDebug( L" Error 0x%08x occurred removing '%s' from "
  1113. L"WebSvcExtRestrictionList.\r\n",
  1114. hr,
  1115. pImage->strPath.QueryStr() );
  1116. }
  1117. }
  1118. else
  1119. {
  1120. WriteDebug( L" Skipping '%s' because it was not listed.\r\n",
  1121. pImage->strPath.QueryStr() );
  1122. }
  1123. ple = ple->Flink;
  1124. }
  1125. WriteDebug( L"Finished removing extensions for '%s' from the metabase.\r\n",
  1126. g_strAppName.QueryStr() );
  1127. return S_OK;
  1128. }
  1129. HRESULT
  1130. RemoveDependenciesFromMetabase(
  1131. VOID
  1132. )
  1133. {
  1134. HRESULT hr;
  1135. DBG_ASSERT( g_pMetabase );
  1136. CSecConLib SecHelper( g_pMetabase );
  1137. WriteDebug( L"Removing dependencies for '%s' from the metabase "
  1138. L"ApplicationDependencies entry.\r\n",
  1139. g_strAppName.QueryStr() );
  1140. hr = SecHelper.RemoveApplication( g_strAppName.QueryStr(),
  1141. L"/LM/w3svc" );
  1142. //
  1143. // Don't consider 0x800cc801 (MD_ERROR_DATA_NOT_FOUND)
  1144. // to be an error
  1145. //
  1146. if ( hr == 0x800cc801 )
  1147. {
  1148. hr = S_OK;
  1149. }
  1150. if ( FAILED( hr ) )
  1151. {
  1152. WriteDebug( L" Error 0x%08x occurred removing '%s' from "
  1153. L"ApplicationDependencies.\r\n",
  1154. hr,
  1155. g_strAppName.QueryStr() );
  1156. }
  1157. WriteDebug( L"Finished removing application dependencies for '%s'.\r\n",
  1158. g_strAppName.QueryStr() );
  1159. return hr;
  1160. }
  1161. BOOL
  1162. IsExtensionInMetabase(
  1163. LPWSTR szImagePath
  1164. )
  1165. {
  1166. HRESULT hr;
  1167. DWORD cbData;
  1168. LPWSTR pExtensionList = NULL;
  1169. LPWSTR pCursor;
  1170. BOOL fRet = FALSE;
  1171. DBG_ASSERT( g_pMetabase );
  1172. CSecConLib SecHelper( g_pMetabase );
  1173. hr = SecHelper.ListExtensionFiles( L"/LM/w3svc",
  1174. &pExtensionList,
  1175. &cbData );
  1176. if ( FAILED( hr ) )
  1177. {
  1178. WriteDebug( L"Error 0x%08x occurred reading WebSvcExtRestrictionList "
  1179. L"from metabase.\r\n",
  1180. hr );
  1181. //
  1182. // If we fail to get the list, assume that
  1183. // the extension is on it.
  1184. //
  1185. fRet = TRUE;
  1186. goto Finished;
  1187. }
  1188. //
  1189. // Walk the list
  1190. //
  1191. pCursor = pExtensionList;
  1192. while ( pCursor && *pCursor != L'\0' )
  1193. {
  1194. if ( _wcsicmp( pCursor, szImagePath ) == NULL )
  1195. {
  1196. fRet = TRUE;
  1197. goto Finished;
  1198. }
  1199. pCursor += wcslen( pCursor ) + 1;
  1200. }
  1201. Finished:
  1202. if ( pExtensionList )
  1203. {
  1204. delete [] pExtensionList;
  1205. pExtensionList = NULL;
  1206. }
  1207. return fRet;
  1208. }
  1209. BOOL
  1210. DoesFileExist(
  1211. LPWSTR szImagePath
  1212. )
  1213. {
  1214. return ( GetFileAttributesW( szImagePath ) != 0xffffffff );
  1215. }
  1216. VOID
  1217. WriteDebug(
  1218. LPWSTR szFormat,
  1219. ...
  1220. )
  1221. {
  1222. WCHAR szBuffer[WRITE_BUFFER_SIZE];
  1223. LPWSTR pCursor;
  1224. DWORD cbToWrite;
  1225. INT nWritten;
  1226. va_list args;
  1227. if ( WRITE_BUFFER_SIZE < 3 )
  1228. {
  1229. //
  1230. // This is just too small to deal with...
  1231. //
  1232. return;
  1233. }
  1234. //
  1235. // Inject the module name tag into the buffer
  1236. //
  1237. nWritten = _snwprintf( szBuffer,
  1238. WRITE_BUFFER_SIZE,
  1239. L"[AcWebSvc.dll] " );
  1240. if ( nWritten == -1 )
  1241. {
  1242. return;
  1243. }
  1244. pCursor = szBuffer + nWritten;
  1245. cbToWrite = WRITE_BUFFER_SIZE - nWritten;
  1246. va_start( args, szFormat );
  1247. nWritten = _vsnwprintf( pCursor,
  1248. cbToWrite,
  1249. szFormat,
  1250. args );
  1251. va_end( args );
  1252. if ( nWritten == -1 )
  1253. {
  1254. szBuffer[WRITE_BUFFER_SIZE-3] = '\r';
  1255. szBuffer[WRITE_BUFFER_SIZE-2] = '\n';
  1256. }
  1257. szBuffer[WRITE_BUFFER_SIZE-1] = '\0';
  1258. OutputDebugString( szBuffer );
  1259. }