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.

692 lines
18 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. w3ssl_config.cxx
  5. Abstract:
  6. IIS Services IISADMIN Extension
  7. adjust HTTPFilter service imagepath based on IIS mode (old vs new)
  8. Author:
  9. Jaroslav Dunajsky (11/05/2001)
  10. --*/
  11. #include <cominc.hxx>
  12. #include <string.h>
  13. #include "w3ssl_config.hxx"
  14. //static
  15. int W3SSL_CONFIG::s_fConfigTerminationRequested = FALSE;
  16. //static
  17. HANDLE W3SSL_CONFIG::s_hConfigChangeThread = NULL;
  18. //static
  19. LPWSTR W3SSL_CONFIG::s_pszImagePathInetinfo = NULL;
  20. //static
  21. LPWSTR W3SSL_CONFIG::s_pszImagePathLsass = NULL;
  22. //static
  23. LPWSTR W3SSL_CONFIG::s_pszImagePathSvchost = NULL;
  24. //static
  25. HRESULT
  26. W3SSL_CONFIG::SetHTTPFilterImagePath(
  27. BOOL fIIS5IsolationModeEnabled,
  28. BOOL fStartInSvchost
  29. )
  30. /*++
  31. Routine Description:
  32. Configure image path of the service to point either
  33. lsass.exe or inetinfo.exe based on the IIS Application
  34. Mode
  35. Arguments:
  36. fIIS5IsolationModeEnabled - TRUE if IIS runs in old mode
  37. FALSE if it runs in new mode
  38. fStartInSvchost - preferred location for HTTPFilter is svchost.exe
  39. Return Value:
  40. HRESULT
  41. --*/
  42. {
  43. SC_LOCK scLock = NULL;
  44. SC_HANDLE schSCManager = NULL;
  45. SC_HANDLE schHTTPFilterService = NULL;
  46. LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
  47. DWORD dwBytesNeeded = 0;
  48. HRESULT hr = E_FAIL;
  49. // Open a handle to the SC Manager database.
  50. schSCManager = OpenSCManagerW(
  51. NULL, // local machine
  52. NULL, // ServicesActive database
  53. SC_MANAGER_ALL_ACCESS ); // full access rights
  54. if ( schSCManager == NULL )
  55. {
  56. hr = HRESULT_FROM_WIN32( GetLastError() );
  57. goto Finished;
  58. }
  59. schHTTPFilterService = OpenServiceW(
  60. schSCManager, // SCM database
  61. HTTPFILTER_SERVICE_NAME, // service name
  62. SERVICE_ALL_ACCESS);
  63. if ( schHTTPFilterService == NULL )
  64. {
  65. hr = HRESULT_FROM_WIN32( GetLastError() );
  66. goto Finished;
  67. }
  68. //
  69. // Get the configuration information.
  70. // - to find out the current image path of the
  71. // HTTPFilter service
  72. //
  73. if ( !QueryServiceConfigW(
  74. schHTTPFilterService,
  75. pServiceConfig,
  76. 0,
  77. &dwBytesNeeded ) )
  78. {
  79. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  80. {
  81. pServiceConfig = reinterpret_cast<LPQUERY_SERVICE_CONFIG> (
  82. new char[dwBytesNeeded] );
  83. if ( pServiceConfig == NULL )
  84. {
  85. hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  86. goto Finished;
  87. }
  88. if ( !QueryServiceConfigW(
  89. schHTTPFilterService,
  90. pServiceConfig,
  91. dwBytesNeeded,
  92. &dwBytesNeeded ) )
  93. {
  94. hr = HRESULT_FROM_WIN32( GetLastError() );
  95. goto Finished;
  96. }
  97. }
  98. else
  99. {
  100. hr = HRESULT_FROM_WIN32( GetLastError() );
  101. goto Finished;
  102. }
  103. }
  104. //
  105. // reconfigure image path of HTTPFilter if necessary
  106. //
  107. if ( ( fIIS5IsolationModeEnabled &&
  108. _wcsicmp( pServiceConfig->lpBinaryPathName,
  109. s_pszImagePathInetinfo ) != 0 ) ||
  110. ( !fIIS5IsolationModeEnabled &&
  111. _wcsicmp( pServiceConfig->lpBinaryPathName,
  112. s_pszImagePathLsass ) != 0 &&
  113. _wcsicmp( pServiceConfig->lpBinaryPathName,
  114. s_pszImagePathSvchost ) != 0 )
  115. )
  116. {
  117. //
  118. // figure out what image path to configure
  119. //
  120. WCHAR * pszImagePath = ( fIIS5IsolationModeEnabled )?
  121. s_pszImagePathInetinfo :
  122. ( ( fStartInSvchost )?
  123. s_pszImagePathSvchost:
  124. s_pszImagePathLsass );
  125. if ( fIIS5IsolationModeEnabled )
  126. {
  127. BOOL fSave = FALSE;
  128. //
  129. // check if we need to store image path information
  130. // before changing
  131. //
  132. if ( _wcsicmp( pServiceConfig->lpBinaryPathName,
  133. s_pszImagePathLsass ) == 0 &&
  134. fStartInSvchost )
  135. {
  136. fStartInSvchost = FALSE;
  137. fSave = TRUE;
  138. }
  139. if ( _wcsicmp( pServiceConfig->lpBinaryPathName,
  140. s_pszImagePathSvchost ) == 0 &&
  141. !fStartInSvchost )
  142. {
  143. fStartInSvchost = TRUE;
  144. fSave = TRUE;
  145. }
  146. if ( fSave )
  147. {
  148. //
  149. // let's flag in the registry which one lsass and svchost
  150. // was hosting the HTTPFilter service
  151. //
  152. DWORD dwValue = (DWORD) fStartInSvchost;
  153. DWORD dwErr;
  154. HKEY hKeyParam;
  155. if ( ( dwErr = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  156. HTTPFILTER_PARAMETERS_KEY,
  157. 0,
  158. KEY_WRITE,
  159. &hKeyParam ) ) == NO_ERROR )
  160. {
  161. dwErr = RegSetValueExW( hKeyParam,
  162. L"StartInSvchost",
  163. NULL,
  164. REG_DWORD,
  165. ( LPBYTE )&dwValue,
  166. sizeof( dwValue )
  167. );
  168. //
  169. // Ignore the error.
  170. //
  171. RegCloseKey( hKeyParam );
  172. }
  173. if ( dwErr != NO_ERROR )
  174. {
  175. DBGPRINTF(( DBG_CONTEXT,
  176. "Failed to write to registry to path %S (hr = %d)\n",
  177. HTTPFILTER_PARAMETERS_KEY,
  178. HRESULT_FROM_WIN32( dwErr )));
  179. }
  180. }
  181. }
  182. //
  183. // loop to acquire service database lock
  184. //
  185. for ( ; ; )
  186. {
  187. scLock = LockServiceDatabase( schSCManager );
  188. if ( scLock == NULL )
  189. {
  190. if ( GetLastError() == ERROR_SERVICE_DATABASE_LOCKED )
  191. {
  192. if ( s_fConfigTerminationRequested == TRUE )
  193. {
  194. //
  195. // if W3SSL_CONFIG::Terminate() is called
  196. // while this function is still waiting for service
  197. // to get locked, we simply bail out.
  198. // ImagePath will not be changed
  199. //
  200. hr = HRESULT_FROM_WIN32( ERROR_OPERATION_ABORTED );
  201. goto Finished;
  202. }
  203. Sleep( 1000 );
  204. continue;
  205. }
  206. else
  207. {
  208. hr = HRESULT_FROM_WIN32( GetLastError() );
  209. goto Finished;
  210. }
  211. }
  212. if ( s_fConfigTerminationRequested == TRUE )
  213. {
  214. //
  215. // if W3SSL_CONFIG::Terminate() is called
  216. // while this function is still waiting for service
  217. // to get locked, we simply bail out.
  218. // ImagePath will not be changed
  219. //
  220. hr = HRESULT_FROM_WIN32( ERROR_OPERATION_ABORTED );
  221. goto Finished;
  222. }
  223. break;
  224. }
  225. if ( !ChangeServiceConfigW(
  226. schHTTPFilterService, // handle of service
  227. SERVICE_NO_CHANGE, // service type
  228. SERVICE_NO_CHANGE, // change service start type
  229. SERVICE_NO_CHANGE, // error control
  230. pszImagePath, // binary path
  231. NULL, // load order group
  232. NULL, // tag ID
  233. NULL, // dependencies
  234. NULL, // account name
  235. NULL, // password
  236. NULL) ) // display name
  237. {
  238. hr = HRESULT_FROM_WIN32( GetLastError() );
  239. goto Finished;
  240. }
  241. UnlockServiceDatabase( scLock );
  242. scLock = NULL;
  243. }
  244. hr = S_OK;
  245. Finished:
  246. if ( pServiceConfig != NULL )
  247. {
  248. delete [] pServiceConfig;
  249. pServiceConfig = NULL;
  250. }
  251. if ( scLock != NULL )
  252. {
  253. UnlockServiceDatabase( scLock );
  254. scLock = NULL;
  255. }
  256. if ( schHTTPFilterService != NULL )
  257. {
  258. DBG_REQUIRE( CloseServiceHandle( schHTTPFilterService ) );
  259. schHTTPFilterService = NULL;
  260. }
  261. if ( schSCManager != NULL )
  262. {
  263. DBG_REQUIRE( CloseServiceHandle( schSCManager ) );
  264. schSCManager = NULL;
  265. }
  266. return hr;
  267. }
  268. //static
  269. HRESULT
  270. W3SSL_CONFIG::AdjustHTTPFilterImagePath(
  271. VOID
  272. )
  273. /*++
  274. Routine Description:
  275. Based on the metabase valuse
  276. configure image path of the service to point either
  277. lsass.exe or inetinfo.exe based on the IIS Application
  278. Mode
  279. Arguments:
  280. none
  281. Return Value:
  282. HRESULT
  283. --*/
  284. {
  285. HRESULT hr = E_FAIL;
  286. METADATA_RECORD mdrData;
  287. DWORD dwRequiredDataLen = 0;
  288. METADATA_HANDLE mhOpenHandle = 0;
  289. IMDCOM * pcCom = NULL;
  290. DWORD dwStandardModeEnabled = 1;
  291. DWORD dwType;
  292. DWORD nBytes;
  293. DWORD dwValue;
  294. DWORD dwErr;
  295. BOOL fStartInSvchost = FALSE;
  296. HKEY hKeyParam;
  297. //
  298. // read registry to find out if preferred location for HTTPFilter is svchost
  299. //
  300. if ( RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  301. HTTPFILTER_PARAMETERS_KEY,
  302. 0,
  303. KEY_READ,
  304. &hKeyParam ) == NO_ERROR )
  305. {
  306. nBytes = sizeof( dwValue );
  307. dwErr = RegQueryValueExW( hKeyParam,
  308. L"StartInSvchost",
  309. NULL,
  310. &dwType,
  311. ( LPBYTE )&dwValue,
  312. &nBytes
  313. );
  314. if ( ( dwErr == ERROR_SUCCESS ) && ( dwType == REG_DWORD ) )
  315. {
  316. fStartInSvchost = !!dwValue;
  317. }
  318. RegCloseKey( hKeyParam );
  319. }
  320. hr = CoCreateInstance( CLSID_MDCOM,
  321. NULL,
  322. CLSCTX_SERVER,
  323. IID_IMDCOM,
  324. (void**) &pcCom);
  325. if ( FAILED( hr ) )
  326. {
  327. goto Finished;
  328. }
  329. hr = pcCom->ComMDOpenMetaObject( METADATA_MASTER_ROOT_HANDLE,
  330. L"/lm/w3svc",
  331. METADATA_PERMISSION_READ,
  332. OPEN_TIMEOUT_VALUE,
  333. &mhOpenHandle );
  334. if ( FAILED( hr ) )
  335. {
  336. goto Finished;
  337. }
  338. else
  339. {
  340. MD_SET_DATA_RECORD_EXT( &mdrData,
  341. MD_GLOBAL_STANDARD_APP_MODE_ENABLED ,
  342. METADATA_NO_ATTRIBUTES,
  343. ALL_METADATA,
  344. DWORD_METADATA,
  345. sizeof( dwStandardModeEnabled ),
  346. (PBYTE) &dwStandardModeEnabled );
  347. hr = pcCom->ComMDGetMetaData( mhOpenHandle,
  348. NULL,
  349. &mdrData,
  350. &dwRequiredDataLen );
  351. if ( hr == MD_ERROR_DATA_NOT_FOUND )
  352. {
  353. //
  354. // Standard mode is enabled by default
  355. //
  356. dwStandardModeEnabled = 1;
  357. }
  358. else if ( FAILED ( hr ) )
  359. {
  360. //
  361. // Error different from not found
  362. // In this case simply bail out
  363. //
  364. goto Finished;
  365. }
  366. }
  367. //
  368. // Cleanup metabase object
  369. //
  370. pcCom->ComMDCloseMetaObject( mhOpenHandle );
  371. mhOpenHandle = 0;
  372. pcCom->Release();
  373. pcCom = NULL;
  374. hr = SetHTTPFilterImagePath( (BOOL) !!dwStandardModeEnabled, fStartInSvchost );
  375. if ( FAILED( hr ) )
  376. {
  377. goto Finished;
  378. }
  379. hr = S_OK;
  380. Finished:
  381. if ( mhOpenHandle != 0 )
  382. {
  383. pcCom->ComMDCloseMetaObject( mhOpenHandle );
  384. mhOpenHandle = 0;
  385. }
  386. if ( pcCom != NULL )
  387. {
  388. pcCom->Release();
  389. pcCom = NULL;
  390. }
  391. return hr;
  392. }
  393. //static
  394. HRESULT
  395. W3SSL_CONFIG::StartAsyncAdjustHTTPFilterImagePath(
  396. VOID
  397. )
  398. /*++
  399. Routine Description:
  400. Configure image path of the service to point either
  401. lsass.exe or inetinfo.exe based on the IIS Application
  402. Mode.
  403. The action is executed on separate thread
  404. Terminate() must be called to assure proper cleanup
  405. Arguments:
  406. none
  407. Return Value:
  408. HRESULT
  409. --*/
  410. {
  411. s_hConfigChangeThread =
  412. ::CreateThread(
  413. NULL, // default security descriptor
  414. 0, // default process stack size
  415. W3SSL_CONFIG::ConfigChangeThread,
  416. NULL, // thread argument - pointer to this class
  417. 0, // create running
  418. NULL // don't care for thread identifier
  419. );
  420. if ( s_hConfigChangeThread == NULL )
  421. {
  422. return HRESULT_FROM_WIN32( GetLastError() );
  423. }
  424. return S_OK;
  425. }
  426. HRESULT
  427. ExpandImagePath(
  428. const WCHAR * pszPath,
  429. WCHAR ** ppszExpandedPath
  430. )
  431. {
  432. DBG_ASSERT( *ppszExpandedPath == NULL );
  433. DWORD dwLen = ExpandEnvironmentStringsW( pszPath, NULL, 0 );
  434. * ppszExpandedPath = new WCHAR [dwLen];
  435. if ( * ppszExpandedPath == NULL )
  436. {
  437. return HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  438. }
  439. (* ppszExpandedPath)[0] = '\0';
  440. DWORD dwLen2 = ExpandEnvironmentStringsW( pszPath,
  441. *ppszExpandedPath,
  442. dwLen );
  443. if ( dwLen2 != dwLen )
  444. {
  445. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  446. }
  447. return S_OK;
  448. }
  449. //static
  450. HRESULT
  451. W3SSL_CONFIG::Initialize(
  452. VOID
  453. )
  454. /*++
  455. Routine Description:
  456. Initialization
  457. Arguments:
  458. none
  459. Return Value:
  460. VOID
  461. --*/
  462. {
  463. HRESULT hr = E_FAIL;
  464. //
  465. // Expand image path because QueryServiceConfig
  466. // already returns expanded ImagePath and
  467. // Image Paths will be compared few times
  468. //
  469. hr = ExpandImagePath( HTTPFILTER_SERVICE_IMAGEPATH_INETINFO,
  470. &s_pszImagePathInetinfo );
  471. if ( FAILED( hr ) )
  472. {
  473. goto Failed;
  474. }
  475. hr = ExpandImagePath( HTTPFILTER_SERVICE_IMAGEPATH_LSASS,
  476. &s_pszImagePathLsass );
  477. if ( FAILED( hr ) )
  478. {
  479. goto Failed;
  480. }
  481. hr = ExpandImagePath( HTTPFILTER_SERVICE_IMAGEPATH_SVCHOST,
  482. &s_pszImagePathSvchost );
  483. if ( FAILED( hr ) )
  484. {
  485. goto Failed;
  486. }
  487. return S_OK;
  488. Failed:
  489. Terminate();
  490. return hr;
  491. }
  492. //static
  493. VOID
  494. W3SSL_CONFIG::Terminate(
  495. VOID
  496. )
  497. /*++
  498. Routine Description:
  499. Quits the asynchronous change of HTTPFILTER image path (if any)
  500. and/or does final cleanup
  501. Arguments:
  502. none
  503. Return Value:
  504. VOID
  505. --*/
  506. {
  507. s_fConfigTerminationRequested = TRUE;
  508. if ( s_hConfigChangeThread != NULL )
  509. {
  510. DWORD dwRet = WaitForSingleObject( s_hConfigChangeThread,
  511. INFINITE );
  512. DBG_ASSERT( dwRet == WAIT_OBJECT_0 );
  513. // IVANPASH dwRet is used only in debug builds, so on /W4 there is
  514. // a warning, which is cheated by the next otherwise useless line.
  515. (VOID)dwRet;
  516. CloseHandle( s_hConfigChangeThread );
  517. s_hConfigChangeThread = NULL;
  518. }
  519. if ( s_pszImagePathInetinfo != NULL )
  520. {
  521. delete s_pszImagePathInetinfo;
  522. s_pszImagePathInetinfo = NULL;
  523. }
  524. if ( s_pszImagePathSvchost != NULL )
  525. {
  526. delete s_pszImagePathSvchost;
  527. s_pszImagePathSvchost = NULL;
  528. }
  529. if ( s_pszImagePathLsass != NULL )
  530. {
  531. delete s_pszImagePathLsass;
  532. s_pszImagePathLsass = NULL;
  533. }
  534. }
  535. //static
  536. DWORD
  537. W3SSL_CONFIG::ConfigChangeThread(
  538. LPVOID
  539. )
  540. /*++
  541. Routine Description:
  542. Worker thread function used to perform image path change asynchronously
  543. Arguments:
  544. none
  545. Return Value:
  546. VOID
  547. --*/
  548. {
  549. AdjustHTTPFilterImagePath();
  550. return ERROR_SUCCESS;
  551. }