Source code of Windows XP (NT5)
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.

2636 lines
76 KiB

  1. /*
  2. IisRestart.cpp
  3. Implementation of CIisRestart ( IIisServiceControl )
  4. FILE HISTORY:
  5. Phillich 06-Oct-1998 Created
  6. */
  7. #include "stdafx.h"
  8. #include "IisRsta.h"
  9. #include "IisRstam.h"
  10. #include "IisRestart.h"
  11. #include "common.h"
  12. #define MAX_TASKS 8
  13. //#define VERBOSE_DEBUG
  14. //
  15. // RETURNCODETOHRESULT() maps a return code to an HRESULT. If the return
  16. // code is a Win32 error (identified by a zero high word) then it is mapped
  17. // using the standard HRESULT_FROM_WIN32() macro. Otherwise, the return
  18. // code is assumed to already be an HRESULT and is returned unchanged.
  19. //
  20. #define RETURNCODETOHRESULT(rc) \
  21. (((rc) < 0x10000) \
  22. ? HRESULT_FROM_WIN32(rc) \
  23. : (rc))
  24. typedef BOOL (*PFNQUERYSERVICECONFIG2)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD) ;
  25. typedef BOOL (*PFNCHANGESERVICECONFIG2)(SC_HANDLE,DWORD,LPVOID);
  26. //
  27. // sample code for remote shutdown:
  28. // \\orville\razzle\src\ntreskit\source\shutgui\reboot.c
  29. //
  30. //
  31. // Global functions
  32. //
  33. BOOL
  34. W3SVCandW3SSL(
  35. DWORD currentIndex,
  36. ENUM_SERVICE_STATUS* pessRoot,
  37. DWORD dwNumServices
  38. );
  39. VOID EnableShutdownPrivilege(
  40. VOID
  41. );
  42. HRESULT
  43. EnumStartServices(
  44. SC_HANDLE schSCM,
  45. LPTSTR pszRoot,
  46. DWORD dwTargetState,
  47. LPBYTE abServiceList,
  48. DWORD dwInitializeServiceListSize,
  49. LPBYTE* ppbServiceList,
  50. LPDWORD pdwNumServices,
  51. BOOL fAddIisadmin
  52. );
  53. HRESULT
  54. SerializeEnumServiceBuffer(
  55. LPENUM_SERVICE_STATUS pessDependentServices,
  56. DWORD dwNumServices,
  57. LPBYTE pbBuffer,
  58. DWORD dwBufferSize,
  59. LPDWORD pdwMDRequiredBufferSize
  60. );
  61. BOOL
  62. IsEnableRemote(
  63. );
  64. HRESULT
  65. StopIIsAdmin(
  66. DWORD dwTimeoutMsecs
  67. );
  68. HRESULT
  69. StartStopAll(
  70. LPTSTR pszRoot,
  71. BOOL fStart,
  72. DWORD dwTimeoutMsecs
  73. );
  74. BOOL
  75. WaitForServiceStatus(
  76. SC_HANDLE schDependent,
  77. DWORD dwDesiredServiceState,
  78. DWORD dwTimeoutMsecs
  79. );
  80. HRESULT
  81. KillTaskByName(
  82. LPTSTR pname,
  83. LPSTR pszMandatoryModule
  84. );
  85. VOID
  86. ReportStatus(
  87. DWORD dwId,
  88. DWORD dwStatus
  89. );
  90. HRESULT
  91. SendControlToService(
  92. SC_HANDLE hServiceHandle,
  93. DWORD dwCmd,
  94. LPDWORD pdwTimeoutOutMsecs
  95. );
  96. StartStopAllRecursive(
  97. SC_HANDLE schSCM,
  98. ENUM_SERVICE_STATUS* pessRoot,
  99. DWORD dwNumServices,
  100. BOOL fStart,
  101. BOOL fForceDemandStart,
  102. LPDWORD pdwTimeoutMsecs
  103. );
  104. HRESULT
  105. WhoAmI(
  106. LPTSTR* pPrincipal
  107. );
  108. BOOL
  109. CloseSystemExceptionHandler(
  110. LPCTSTR pszWindowName
  111. );
  112. /////////////////////////////////////////////////////////////////////////////
  113. // CIisRestart
  114. STDMETHODIMP
  115. CIisRestart::Stop(
  116. DWORD dwTimeoutMsecs,
  117. DWORD dwForce
  118. )
  119. /*++
  120. Stop
  121. Stop all internet services ( services dependent on IISADMIN )
  122. first using SCM then optionaly using TerminateProcess if failure
  123. Arguments:
  124. dwTimeoutMsecs - timeout for status check ( in ms )
  125. dwForce - !0 to force TerminateProcess if failure to stop services using SCM
  126. Returns:
  127. ERROR_RESOURCE_DISABLED if remote access to IIisRestart disabled
  128. ERROR_SERVICE_REQUEST_TIMEOUT if timeout waiting for all internet services status
  129. to be stopped
  130. otherwise COM status
  131. --*/
  132. {
  133. HRESULT hres = S_OK;
  134. if ( !IsEnableRemote() )
  135. {
  136. hres = RETURNCODETOHRESULT( ERROR_RESOURCE_DISABLED );
  137. }
  138. else
  139. {
  140. #if defined(VERBOSE_DEBUG)
  141. OutputDebugString(_T("Attempt to kill dr watson\n"));
  142. #endif
  143. //
  144. // Always kill Dr Watson, as the Dr Watson window may be still present after inetinfo process
  145. // was terminated after an exception, and in this case the Dr Watson process apparently still owns
  146. // some sockets resources preventing inetinfo to properly restart ( specifically binding TCP/IP sockets
  147. // fails during inetinfo restart )
  148. //
  149. KillTaskByName(_T("drwtsn32"), NULL);
  150. hres = StartStopAll( _T("IISADMIN"), FALSE, dwTimeoutMsecs );
  151. if ( dwForce && FAILED( hres ) )
  152. {
  153. hres = Kill();
  154. }
  155. }
  156. ReportStatus( IRSTAM_STOP, hres );
  157. return hres;
  158. }
  159. STDMETHODIMP
  160. CIisRestart::Start(
  161. DWORD dwTimeoutMsecs
  162. )
  163. /*++
  164. Start
  165. Start all internet services ( services dependent on IISADMIN )
  166. using SCM
  167. Arguments:
  168. dwTimeoutMsecs - timeout for status check ( in ms )
  169. Returns:
  170. ERROR_RESOURCE_DISABLED if remote access to IIisRestart disabled
  171. ERROR_SERVICE_REQUEST_TIMEOUT if timeout waiting for all internet services status
  172. to be started
  173. otherwise COM status
  174. --*/
  175. {
  176. HRESULT hres = S_OK;
  177. if ( !IsEnableRemote() )
  178. {
  179. hres = RETURNCODETOHRESULT( ERROR_RESOURCE_DISABLED );
  180. }
  181. else
  182. {
  183. //
  184. // In 6.0 we will use IIS Reset /Start to bring up the
  185. // service again without stopping the services that can
  186. // keep running. We still want to kill any dr watson's
  187. // thou. This should be harmless on a regular start.
  188. //
  189. #if defined(VERBOSE_DEBUG)
  190. OutputDebugString(_T("Attempt to kill dr watson\n"));
  191. #endif
  192. //
  193. // Always kill Dr Watson, as the Dr Watson window may be still present after inetinfo process
  194. // was terminated after an exception, and in this case the Dr Watson process apparently still owns
  195. // some sockets resources preventing inetinfo to properly restart ( specifically binding TCP/IP sockets
  196. // fails during inetinfo restart )
  197. //
  198. KillTaskByName(_T("drwtsn32"), NULL);
  199. hres = StartStopAll( _T("IISADMIN"), TRUE, dwTimeoutMsecs );
  200. }
  201. ReportStatus( IRSTAM_START, hres );
  202. return hres;
  203. }
  204. STDMETHODIMP
  205. CIisRestart::Reboot(
  206. DWORD dwTimeoutMsecs,
  207. DWORD dwForceAppsClosed
  208. )
  209. /*++
  210. Reboot
  211. Reboot the computer
  212. Arguments:
  213. dwTimeoutMsecs - timeout for apps to be closed by user ( in ms )
  214. dwForceAppsClosed - force apps to be closed if hung
  215. Returns:
  216. ERROR_RESOURCE_DISABLED if remote access to IIisRestart disabled
  217. otherwise COM status
  218. --*/
  219. {
  220. HRESULT hres = S_OK;
  221. if ( !IsEnableRemote() )
  222. {
  223. hres = RETURNCODETOHRESULT( ERROR_RESOURCE_DISABLED );
  224. }
  225. else
  226. {
  227. //
  228. // If this fails then we will get an error back from ExitWindowsEx()
  229. //
  230. EnableShutdownPrivilege();
  231. //
  232. // Make sure we will always reboot even if process(es) stuck
  233. //
  234. #if 1
  235. TCHAR* pPrincipal;
  236. TCHAR* pBuf;
  237. //
  238. // Format message to operator, includes name of user requesting shutdown.
  239. //
  240. if ( SUCCEEDED( hres = WhoAmI( &pPrincipal ) ) )
  241. {
  242. if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  243. (LPCVOID)NULL, //GetModuleHandle(NULL),
  244. IRSTAM_SYSSHUT,
  245. 0,
  246. (LPTSTR)&pBuf,
  247. 1,
  248. (va_list *)&pPrincipal ) )
  249. {
  250. if (InitiateSystemShutdown( NULL,
  251. pBuf,
  252. dwTimeoutMsecs/1000, // timeout in seconds
  253. dwForceAppsClosed,
  254. TRUE ) == 0)
  255. {
  256. hres = RETURNCODETOHRESULT( GetLastError() );
  257. }
  258. LocalFree( (LPVOID)pBuf );
  259. }
  260. LocalFree( pPrincipal );
  261. }
  262. #else
  263. if ( !ExitWindowsEx( EWX_REBOOT|EWX_FORCE, 0 ) )
  264. {
  265. hres = RETURNCODETOHRESULT( GetLastError() );
  266. }
  267. #endif
  268. }
  269. ReportStatus( IRSTAM_REBOOT, hres );
  270. return hres;
  271. }
  272. STDMETHODIMP
  273. CIisRestart::Kill(
  274. )
  275. /*++
  276. Kill
  277. Kill all internet services ( services dependent on IISADMIN )
  278. using TerminateProcess()
  279. Arguments:
  280. None
  281. Returns:
  282. ERROR_RESOURCE_DISABLED if remote access to IIisRestart disabled
  283. otherwise COM status
  284. --*/
  285. {
  286. HRESULT hres = S_OK;
  287. HRESULT hresReapply;
  288. BYTE abServiceList[2048];
  289. LPBYTE pbServiceList = NULL;
  290. DWORD dwNumServices = 0;
  291. SC_HANDLE schSCM = NULL;
  292. SC_HANDLE schSrv;
  293. LPBYTE* ppInfo = NULL;
  294. LPENUM_SERVICE_STATUS pessDependentServices;
  295. DWORD dwNeeded;
  296. HINSTANCE hAdvapi;
  297. PFNQUERYSERVICECONFIG2 pfnQueryServiceConfig2 = NULL;
  298. PFNCHANGESERVICECONFIG2 pfnChangeServiceConfig2 = NULL;
  299. SERVICE_FAILURE_ACTIONS sfaNoAction;
  300. SC_ACTION saNoAction[3];
  301. DWORD i;
  302. BYTE abTemp[64]; // work-around for NT5 bug
  303. if ( !IsEnableRemote() )
  304. {
  305. return RETURNCODETOHRESULT( ERROR_RESOURCE_DISABLED );
  306. }
  307. //
  308. // Take a snapshot of Restart configuration
  309. // If unable to get ptr to service config2 API then consider this a success:
  310. // there is nothing to preserve.
  311. //
  312. if ( hAdvapi = LoadLibrary(_T("ADVAPI32.DLL")) )
  313. {
  314. pfnQueryServiceConfig2 = (PFNQUERYSERVICECONFIG2)GetProcAddress( hAdvapi, "QueryServiceConfig2W" );
  315. pfnChangeServiceConfig2 = (PFNCHANGESERVICECONFIG2)GetProcAddress( hAdvapi, "ChangeServiceConfig2W" );
  316. }
  317. if ( pfnQueryServiceConfig2
  318. && pfnChangeServiceConfig2 )
  319. {
  320. schSCM = OpenSCManager(NULL,
  321. NULL,
  322. SC_MANAGER_ALL_ACCESS);
  323. if ( schSCM == NULL )
  324. {
  325. hres = RETURNCODETOHRESULT( GetLastError() );
  326. }
  327. else
  328. {
  329. //
  330. // Setup control block for no restart action.
  331. // We will replace existing actions with this control block
  332. //
  333. sfaNoAction.dwResetPeriod = INFINITE;
  334. sfaNoAction.lpCommand = _T("");
  335. sfaNoAction.lpRebootMsg = _T("");
  336. sfaNoAction.cActions = 3;
  337. sfaNoAction.lpsaActions = saNoAction;
  338. saNoAction[0].Type = SC_ACTION_NONE;
  339. saNoAction[0].Delay = 0;
  340. saNoAction[1].Type = SC_ACTION_NONE;
  341. saNoAction[1].Delay = 0;
  342. saNoAction[2].Type = SC_ACTION_NONE;
  343. saNoAction[2].Delay = 0;
  344. //
  345. // Enumerate all services dependent on IISADMIN ( including itself )
  346. //
  347. hres = EnumStartServices( schSCM,
  348. _T("IISADMIN"),
  349. SERVICE_STATE_ALL,
  350. abServiceList,
  351. sizeof(abServiceList),
  352. &pbServiceList,
  353. &dwNumServices,
  354. TRUE );
  355. if ( SUCCEEDED( hres ) )
  356. {
  357. //
  358. // Store existing info in ppInfo array
  359. //
  360. ppInfo = (LPBYTE*)LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT, sizeof(LPBYTE) * dwNumServices );
  361. if ( ppInfo )
  362. {
  363. pessDependentServices = (LPENUM_SERVICE_STATUS)pbServiceList;
  364. for ( i = 0 ;
  365. (i < dwNumServices) && SUCCEEDED(hres) ;
  366. ++i )
  367. {
  368. schSrv = OpenService( schSCM,
  369. pessDependentServices[i].lpServiceName,
  370. SERVICE_ALL_ACCESS);
  371. if ( schSrv )
  372. {
  373. //
  374. // 1st query config size, then alloc buffer and retrieve
  375. // config. Note than ppInfo[] may be NULL is no config
  376. // associated with this service.
  377. //
  378. // WARNING: must specify ptr to writable buffer even if specified
  379. // buffer size is 0 due to bug in NT5 implementation of
  380. // QueryServiceConfig2. Not sure about minimum buffer size
  381. // ( sizeof(SERVICE_FAILURE_ACTIONS) ) ?
  382. //
  383. if ( !pfnQueryServiceConfig2( schSrv,
  384. SERVICE_CONFIG_FAILURE_ACTIONS,
  385. (LPBYTE)abTemp,
  386. 0,
  387. &dwNeeded ) )
  388. {
  389. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  390. {
  391. if ( ppInfo[i] = (LPBYTE)LocalAlloc( LMEM_FIXED, dwNeeded ) )
  392. {
  393. if ( !pfnQueryServiceConfig2( schSrv,
  394. SERVICE_CONFIG_FAILURE_ACTIONS,
  395. ppInfo[i],
  396. dwNeeded,
  397. &dwNeeded ) )
  398. {
  399. hres = RETURNCODETOHRESULT( GetLastError() );
  400. }
  401. }
  402. else
  403. {
  404. hres = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  405. }
  406. }
  407. else
  408. {
  409. hres = RETURNCODETOHRESULT( GetLastError() );
  410. }
  411. }
  412. if ( SUCCEEDED( hres ) )
  413. {
  414. #if defined(VERBOSE_DEBUG)
  415. OutputDebugString(_T("Got config for "));
  416. OutputDebugString(pessDependentServices[i].lpServiceName);
  417. OutputDebugString(_T("\n"));
  418. #endif
  419. if ( !pfnChangeServiceConfig2( schSrv,
  420. SERVICE_CONFIG_FAILURE_ACTIONS,
  421. &sfaNoAction ) )
  422. {
  423. hres = RETURNCODETOHRESULT( GetLastError() );
  424. }
  425. }
  426. CloseServiceHandle( schSrv );
  427. }
  428. else
  429. {
  430. hres = RETURNCODETOHRESULT( GetLastError() );
  431. }
  432. }
  433. }
  434. else
  435. {
  436. hres = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  437. }
  438. }
  439. CloseServiceHandle( schSCM );
  440. }
  441. }
  442. //
  443. // Graceful exit failed, kill the IIS processes.
  444. // First, kill inetinfo, then kill the WAM instances.
  445. //
  446. CloseSystemExceptionHandler( _T("inetinfo.exe") );
  447. //
  448. // Always kill Dr Watson, as the Dr Watson window may be still present after inetinfo process
  449. // was terminated after an exception, and in this case the Dr Watson process apparently still owns
  450. // some sockets resources preventing inetinfo to properly restart ( specifically binding TCP/IP sockets
  451. // fails during inetinfo restart )
  452. //
  453. KillTaskByName(_T("drwtsn32"), NULL);
  454. if ( SUCCEEDED( hres ) )
  455. {
  456. #if defined(VERBOSE_DEBUG)
  457. OutputDebugString(_T("Attempt to kill INETINFO\n"));
  458. #endif
  459. hres = KillTaskByName(_T("INETINFO"), NULL);
  460. }
  461. if ( SUCCEEDED( hres ) )
  462. {
  463. #if defined(VERBOSE_DEBUG)
  464. OutputDebugString(_T("Attempt to kill svhost\n"));
  465. #endif
  466. hres = KillTaskByName(_T("SVCHOST"), "iisw3adm.dll"); // MTS WAM containers
  467. }
  468. if ( SUCCEEDED( hres ) )
  469. {
  470. #if defined(VERBOSE_DEBUG)
  471. OutputDebugString(_T("Attempt to kill w3wp\n"));
  472. #endif
  473. hres = KillTaskByName(_T("W3WP"), NULL); // MTS WAM containers
  474. }
  475. if ( SUCCEEDED( hres ) )
  476. {
  477. #if defined(VERBOSE_DEBUG)
  478. OutputDebugString(_T("Attempt to kill MTX\n"));
  479. #endif
  480. hres = KillTaskByName(_T("MTX"), "wam.dll"); // MTS WAM containers
  481. }
  482. if ( SUCCEEDED( hres ) )
  483. {
  484. #if defined(VERBOSE_DEBUG)
  485. OutputDebugString(_T("Attempt to kill DLLHOST\n"));
  486. #endif
  487. hres = KillTaskByName(_T("DLLHOST"),"wam.dll"); // COM+ WAM Containers
  488. }
  489. if ( SUCCEEDED( hres ) )
  490. {
  491. #if defined(VERBOSE_DEBUG)
  492. OutputDebugString(_T("Attempt to kill XSPWP\n"));
  493. #endif
  494. hres = KillTaskByName(_T("XSPWP"), NULL); // ASP+ processes
  495. }
  496. // the following code will check the IISAdmin registry parameters for
  497. // a KillProcsOnFailure MULTI_SZ. Any process names in this list will
  498. // be killed.
  499. if ( SUCCEEDED( hres ) )
  500. {
  501. HKEY hKey;
  502. DWORD dwValue;
  503. DWORD dwType;
  504. DWORD dwSize;
  505. TCHAR achBuffer[1024];
  506. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  507. TEXT("system\\CurrentControlSet\\services\\IISAdmin"),
  508. 0,
  509. KEY_READ,
  510. &hKey ) == ERROR_SUCCESS )
  511. {
  512. dwSize = sizeof( achBuffer );
  513. if ( RegQueryValueEx( hKey,
  514. TEXT("KillProcsOnFailure"),
  515. 0,
  516. &dwType,
  517. (LPBYTE)achBuffer,
  518. &dwSize ) != ERROR_SUCCESS )
  519. {
  520. RegCloseKey( hKey );
  521. return FALSE;
  522. }
  523. TCHAR *pT = achBuffer;
  524. // parse the multisz. The format is NULL Terminated strings
  525. // with an extra null terminator after the list.
  526. while ((dwSize > 0) && *pT) {
  527. #if defined(VERBOSE_DEBUG)
  528. OutputDebugString(_T("Attempt to kill\n"));
  529. OutputDebugString(pT);
  530. #endif
  531. hres = KillTaskByName(pT, NULL);
  532. dwSize -= _tcsnbcnt(pT,_tcslen(pT)) + sizeof(TCHAR);
  533. pT += _tcslen(pT) + 1;
  534. }
  535. }
  536. }
  537. #if defined(VERBOSE_DEBUG)
  538. if ( FAILED(hres) )
  539. {
  540. OutputDebugString(_T("Kill failed\n"));
  541. }
  542. #endif
  543. hresReapply = S_OK;
  544. //
  545. // Reapply restart configuration
  546. //
  547. if ( ppInfo )
  548. {
  549. schSCM = OpenSCManager(NULL,
  550. NULL,
  551. SC_MANAGER_ALL_ACCESS);
  552. if ( schSCM == NULL )
  553. {
  554. hresReapply = RETURNCODETOHRESULT( GetLastError() );
  555. }
  556. else
  557. {
  558. for ( i = 0 ; i < dwNumServices ; ++i )
  559. {
  560. if ( ppInfo[i] )
  561. {
  562. schSrv = OpenService( schSCM,
  563. pessDependentServices[i].lpServiceName,
  564. SERVICE_ALL_ACCESS);
  565. if ( schSrv )
  566. {
  567. if ( !pfnChangeServiceConfig2( schSrv,
  568. SERVICE_CONFIG_FAILURE_ACTIONS,
  569. ppInfo[i] ) )
  570. {
  571. hresReapply = RETURNCODETOHRESULT( GetLastError() );
  572. }
  573. else
  574. {
  575. #if defined(VERBOSE_DEBUG)
  576. OutputDebugString(_T("Reapply config for "));
  577. OutputDebugString(pessDependentServices[i].lpServiceName);
  578. OutputDebugString(_T(" : "));
  579. TCHAR achErr[80];
  580. wsprintf( achErr, _T("%d actions "), ((SERVICE_FAILURE_ACTIONS*)ppInfo[i])->cActions );
  581. OutputDebugString(achErr);
  582. OutputDebugString(_T("\n"));
  583. #endif
  584. }
  585. CloseServiceHandle( schSrv );
  586. }
  587. else
  588. {
  589. hresReapply = RETURNCODETOHRESULT( GetLastError() );
  590. }
  591. }
  592. }
  593. CloseServiceHandle( schSCM );
  594. }
  595. }
  596. if ( SUCCEEDED(hres) && FAILED(hresReapply) )
  597. {
  598. hres = hresReapply;
  599. }
  600. ReportStatus( IRSTAM_KILL, hres );
  601. if ( hAdvapi )
  602. {
  603. FreeLibrary( hAdvapi );
  604. }
  605. //
  606. // cleanup
  607. //
  608. if ( ppInfo )
  609. {
  610. for ( i = 0 ; i < dwNumServices ; ++i )
  611. {
  612. if ( ppInfo[i] )
  613. {
  614. LocalFree( ppInfo[i] );
  615. }
  616. }
  617. LocalFree( ppInfo );
  618. }
  619. if ( pbServiceList != NULL
  620. && pbServiceList != abServiceList )
  621. {
  622. LocalFree( pbServiceList );
  623. }
  624. return hres;
  625. }
  626. //
  627. // Helper functions
  628. //
  629. VOID
  630. EnableShutdownPrivilege(
  631. VOID
  632. )
  633. /*++
  634. EnableShutdownPrivilege
  635. Enable shutdown privilege ( required to call ExitWindowsEx )
  636. Arguments:
  637. None
  638. Returns:
  639. Nothing. If error enabling the privilege the dependent operation
  640. will fail.
  641. --*/
  642. {
  643. HANDLE ProcessHandle;
  644. HANDLE TokenHandle = NULL;
  645. BOOL Result;
  646. LUID ShutdownValue;
  647. TOKEN_PRIVILEGES * TokenPrivileges;
  648. CHAR buf[ 5 * sizeof(TOKEN_PRIVILEGES) ];
  649. ProcessHandle = OpenProcess(
  650. PROCESS_QUERY_INFORMATION,
  651. FALSE,
  652. GetCurrentProcessId()
  653. );
  654. if ( ProcessHandle == NULL ) {
  655. //
  656. // This should not happen
  657. //
  658. goto Cleanup;
  659. }
  660. Result = OpenProcessToken (
  661. ProcessHandle,
  662. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  663. &TokenHandle
  664. );
  665. if ( !Result ) {
  666. //
  667. // This should not happen
  668. //
  669. goto Cleanup;
  670. }
  671. //
  672. // Find out the value of Shutdown privilege
  673. //
  674. Result = LookupPrivilegeValue(
  675. NULL,
  676. SE_SHUTDOWN_NAME,
  677. &ShutdownValue
  678. );
  679. if ( !Result ) {
  680. goto Cleanup;
  681. }
  682. //
  683. // Set up the privilege set we will need
  684. //
  685. TokenPrivileges = (TOKEN_PRIVILEGES *) buf;
  686. TokenPrivileges->PrivilegeCount = 1;
  687. TokenPrivileges->Privileges[0].Luid = ShutdownValue;
  688. TokenPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  689. (VOID) AdjustTokenPrivileges (
  690. TokenHandle,
  691. FALSE,
  692. TokenPrivileges,
  693. sizeof(buf),
  694. NULL,
  695. NULL
  696. );
  697. Cleanup:
  698. if ( TokenHandle )
  699. {
  700. CloseHandle( TokenHandle );
  701. }
  702. if ( ProcessHandle )
  703. {
  704. CloseHandle( ProcessHandle );
  705. }
  706. }
  707. #define SLEEP_INTERVAL 1000
  708. #if 0
  709. HRESULT
  710. StopIIsAdmin(
  711. DWORD dwTimeoutMsecs
  712. )
  713. /*++
  714. StopIIsAdmin
  715. Stop the IISADMIN service using SCM
  716. Arguments:
  717. dwTimeoutMsecs - timeout for status check ( in ms )
  718. Returns:
  719. COM status
  720. --*/
  721. {
  722. SC_HANDLE schSCM = NULL;
  723. SC_HANDLE schIISADMIN = NULL;
  724. HRESULT hresReturn = S_OK;
  725. SERVICE_STATUS ssServiceStop;
  726. schSCM = OpenSCManager( NULL,
  727. NULL,
  728. SC_MANAGER_ALL_ACCESS );
  729. if ( schSCM == NULL )
  730. {
  731. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  732. }
  733. else
  734. {
  735. schIISADMIN = OpenService( schSCM,
  736. TEXT("IISADMIN"),
  737. SERVICE_ALL_ACCESS);
  738. if (schIISADMIN != NULL)
  739. {
  740. ControlService( schIISADMIN, SERVICE_CONTROL_STOP, &ssServiceStop );
  741. if ( !WaitForServiceStatus(schIISADMIN, SERVICE_STOPPED, dwTimeoutMsecs) )
  742. {
  743. hresReturn = RETURNCODETOHRESULT( ERROR_SERVICE_REQUEST_TIMEOUT );
  744. }
  745. CloseServiceHandle( schIISADMIN );
  746. }
  747. else
  748. {
  749. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  750. }
  751. CloseServiceHandle( schSCM );
  752. }
  753. return hresReturn;
  754. }
  755. BOOL
  756. WaitForServiceStatus(
  757. SC_HANDLE schDependent,
  758. DWORD dwDesiredServiceState,
  759. DWORD dwTimeoutMsecs
  760. )
  761. /*++
  762. WaitForServiceStatus
  763. Wait for given state using timeout
  764. Arguments:
  765. schDependent - service to check
  766. dwDesiredServiceState - target state
  767. dwTimeoutMsecs - timeout for status check ( in ms )
  768. Returns:
  769. COM status
  770. --*/
  771. {
  772. DWORD dwSleepTotal = 0;
  773. DWORD dwSleepInterval = SLEEP_INTERVAL;
  774. SERVICE_STATUS ssDependent;
  775. BOOL fSt = FALSE;
  776. if ( dwTimeoutMsecs < dwSleepInterval && dwTimeoutMsecs )
  777. {
  778. dwSleepInterval = dwTimeoutMsecs;
  779. }
  780. for ( ;; )
  781. {
  782. if ( QueryServiceStatus(schDependent, &ssDependent) )
  783. {
  784. if ( ssDependent.dwCurrentState == dwDesiredServiceState )
  785. {
  786. fSt = TRUE;
  787. break;
  788. }
  789. else
  790. {
  791. //
  792. // Still pending...
  793. //
  794. if ( dwSleepTotal + dwSleepInterval > dwTimeoutMsecs )
  795. {
  796. break;
  797. }
  798. Sleep( dwSleepInterval );
  799. dwSleepTotal += dwSleepInterval;
  800. }
  801. }
  802. else
  803. {
  804. break;
  805. }
  806. }
  807. return fSt;
  808. }
  809. #endif
  810. HRESULT
  811. StartStopAll(
  812. LPTSTR pszRoot,
  813. BOOL fStart,
  814. DWORD dwTimeoutMsecs
  815. )
  816. /*++
  817. StartStopAll
  818. start or stop services dependency tree starting with specified root service
  819. Arguments:
  820. pszRoot - root of the service tree
  821. fStart - TRUE to start services, FALSE to stop
  822. dwTimeoutMsecs - timeout for status check ( in ms )
  823. Returns:
  824. COM status
  825. --*/
  826. {
  827. SC_HANDLE schSCM = NULL;
  828. SC_HANDLE schRoot = NULL;
  829. HRESULT hresReturn = S_OK;
  830. ENUM_SERVICE_STATUS ess;
  831. SERVICE_STATUS ServiceStatus;
  832. schSCM = OpenSCManager(NULL,
  833. NULL,
  834. SC_MANAGER_ALL_ACCESS);
  835. if ( schSCM == NULL )
  836. {
  837. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  838. }
  839. else
  840. {
  841. if ( schRoot = OpenService( schSCM, pszRoot, SERVICE_ALL_ACCESS ) )
  842. {
  843. if ( !QueryServiceStatus( schRoot, &ess.ServiceStatus ) )
  844. {
  845. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  846. }
  847. CloseServiceHandle( schRoot );
  848. if ( SUCCEEDED( hresReturn )
  849. && ( fStart
  850. || ess.ServiceStatus.dwCurrentState != SERVICE_STOPPED) )
  851. {
  852. ess.lpServiceName = pszRoot;
  853. // if it's stopped, then whack the dllhosts that have wam.dll loaded
  854. if (ess.ServiceStatus.dwCurrentState == SERVICE_STOPPED)
  855. {
  856. #if defined(VERBOSE_DEBUG)
  857. OutputDebugString(_T("Attempt to kill MTX\n"));
  858. #endif
  859. KillTaskByName(_T("MTX"), "wam.dll"); // MTS WAM containers
  860. #if defined(VERBOSE_DEBUG)
  861. OutputDebugString(_T("Attempt to kill DLLHOST\n"));
  862. #endif
  863. KillTaskByName(_T("DLLHOST"),"wam.dll"); // COM+ WAM Containers
  864. }
  865. hresReturn = StartStopAllRecursive( schSCM, &ess, 1, fStart, TRUE, &dwTimeoutMsecs );
  866. }
  867. // check out the current state of the service
  868. if ( schRoot = OpenService( schSCM, pszRoot, SERVICE_ALL_ACCESS ) )
  869. {
  870. if ( QueryServiceStatus( schRoot, &ess.ServiceStatus ) )
  871. {
  872. // if it's stopped, then whack the dllhosts that have wam.dll loaded
  873. if (ess.ServiceStatus.dwCurrentState == SERVICE_STOPPED)
  874. {
  875. #if defined(VERBOSE_DEBUG)
  876. OutputDebugString(_T("Attempt to kill MTX\n"));
  877. #endif
  878. KillTaskByName(_T("MTX"), "wam.dll"); // MTS WAM containers
  879. #if defined(VERBOSE_DEBUG)
  880. OutputDebugString(_T("Attempt to kill DLLHOST\n"));
  881. #endif
  882. KillTaskByName(_T("DLLHOST"),"wam.dll"); // COM+ WAM Containers
  883. }
  884. }
  885. CloseServiceHandle( schRoot );
  886. }
  887. }
  888. else
  889. {
  890. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  891. }
  892. CloseServiceHandle( schSCM );
  893. }
  894. return hresReturn;
  895. }
  896. StartStopAllRecursive(
  897. SC_HANDLE schSCM,
  898. ENUM_SERVICE_STATUS* pessRoot,
  899. DWORD dwNumServices,
  900. BOOL fStart,
  901. BOOL fForceDemandStart,
  902. LPDWORD pdwTimeoutMsecs
  903. )
  904. /*++
  905. StartStopAllRecursive
  906. start or stop services dependency tree starting with specified root service
  907. Arguments:
  908. schSCM - handle to SCM
  909. pessRoot - list of services to start/stop recursively
  910. fStart - TRUE to start services, FALSE to stop
  911. fForceDemandStart - for start requests: TRUE to force start
  912. if SERVICE_DEMAND_START. Otherwise only start if service
  913. is auto start ( including boot & system start )
  914. dwTimeoutMsecs - timeout for status check ( in ms )
  915. Returns:
  916. COM status
  917. --*/
  918. {
  919. DWORD dwBytesNeeded;
  920. DWORD dwNumRecServices = 0;
  921. HRESULT hresReturn = S_OK;
  922. BYTE abServiceList[2048];
  923. LPBYTE pbServiceList = NULL;
  924. BYTE abServiceConfig[1024];
  925. LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
  926. SC_HANDLE* phServiceHandle = NULL;
  927. DWORD i;
  928. DWORD dwServiceConfigSize;
  929. SERVICE_STATUS ServiceStatus;
  930. DWORD dwSleepTotal = 0;
  931. DWORD dwSleepInterval = SLEEP_INTERVAL;
  932. LPENUM_SERVICE_STATUS pessDependentServices;
  933. if ( (phServiceHandle = (SC_HANDLE*)LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT,
  934. dwNumServices * sizeof(SC_HANDLE) )) == NULL )
  935. {
  936. hresReturn = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  937. }
  938. if ( SUCCEEDED(hresReturn) )
  939. {
  940. //
  941. // All services will be started/stopped at once
  942. // then periodically checked for status until all of them are running/stopped
  943. // or some error occured or timeout
  944. //
  945. if ( dwNumServices != 0 )
  946. {
  947. pServiceConfig = (LPQUERY_SERVICE_CONFIG)abServiceConfig;
  948. dwServiceConfigSize = sizeof( abServiceConfig );
  949. //
  950. // Open handles and send service control start command
  951. //
  952. for ( i = 0 ;
  953. i < dwNumServices && SUCCEEDED(hresReturn) ;
  954. i++)
  955. {
  956. //
  957. // Send command to Services
  958. //
  959. #if defined(VERBOSE_DEBUG)
  960. WCHAR buffer[200];
  961. _snwprintf(buffer, 200, L"Working on the '%s' service\n", pessRoot[i].lpServiceName );
  962. buffer[199] = L'\0';
  963. OutputDebugString( buffer );
  964. #endif
  965. phServiceHandle[i] = OpenService( schSCM,
  966. pessRoot[i].lpServiceName,
  967. SERVICE_ALL_ACCESS );
  968. if ( phServiceHandle[i] != NULL )
  969. {
  970. if ( fStart )
  971. {
  972. //
  973. // Query service config to check if service should be started
  974. // based on its Start Type.
  975. //
  976. if ( !QueryServiceConfig( phServiceHandle[i],
  977. (LPQUERY_SERVICE_CONFIG)&abServiceConfig,
  978. dwServiceConfigSize,
  979. &dwBytesNeeded ) )
  980. {
  981. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  982. {
  983. if ( (pServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(
  984. LMEM_FIXED,
  985. dwBytesNeeded )) == NULL )
  986. {
  987. hresReturn = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  988. }
  989. else
  990. {
  991. dwServiceConfigSize = dwBytesNeeded;
  992. if ( !QueryServiceConfig( phServiceHandle[i],
  993. (LPQUERY_SERVICE_CONFIG)pServiceConfig,
  994. dwServiceConfigSize,
  995. &dwBytesNeeded ) )
  996. {
  997. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  998. }
  999. }
  1000. }
  1001. else
  1002. {
  1003. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  1004. }
  1005. }
  1006. if ( SUCCEEDED(hresReturn) )
  1007. {
  1008. //
  1009. // Check if service auto start except if fForceDemandStart
  1010. // specified. ForceDemandStart will only be specified for
  1011. // the service that the command is directly issued on. This
  1012. // means that it will only be specified for IISADMIN.
  1013. //
  1014. if ( ( fForceDemandStart && pServiceConfig->dwStartType == SERVICE_DEMAND_START )
  1015. || ( pServiceConfig->dwStartType == SERVICE_BOOT_START ||
  1016. pServiceConfig->dwStartType == SERVICE_SYSTEM_START ||
  1017. pServiceConfig->dwStartType == SERVICE_AUTO_START ) )
  1018. {
  1019. StartService( phServiceHandle[i], 0, NULL );
  1020. //
  1021. // Ask for only the services that are inactive. So, for instance,
  1022. // if we are attempting to restart the iisadmin service,
  1023. // and W3SVC is still active, we won't send it a command to restart.
  1024. //
  1025. hresReturn = EnumStartServices( schSCM,
  1026. pessRoot[i].lpServiceName,
  1027. SERVICE_INACTIVE,
  1028. abServiceList,
  1029. sizeof(abServiceList),
  1030. &pbServiceList,
  1031. &dwNumRecServices,
  1032. FALSE );
  1033. if ( SUCCEEDED( hresReturn ) )
  1034. {
  1035. hresReturn = StartStopAllRecursive( schSCM,
  1036. (ENUM_SERVICE_STATUS*)pbServiceList,
  1037. dwNumRecServices,
  1038. fStart,
  1039. FALSE,
  1040. pdwTimeoutMsecs );
  1041. if ( pbServiceList != NULL
  1042. && pbServiceList != abServiceList )
  1043. {
  1044. LocalFree( pbServiceList );
  1045. }
  1046. }
  1047. }
  1048. else
  1049. {
  1050. //
  1051. // Don't want to start this service, so mark it
  1052. // as already running
  1053. //
  1054. if (wcscmp(pessRoot[i].lpServiceName,_T("IISADMIN")) == 0)
  1055. {
  1056. hresReturn = RETURNCODETOHRESULT(ERROR_SERVICE_NOT_ACTIVE);
  1057. }
  1058. else
  1059. {
  1060. pessRoot[i].ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  1061. }
  1062. }
  1063. }
  1064. }
  1065. else // handle stopping the service
  1066. {
  1067. if ( W3SVCandW3SSL(i, pessRoot, dwNumServices) )
  1068. {
  1069. continue;
  1070. }
  1071. // Remember if the service was stopped to start with.
  1072. BOOL fServiceWasStoppedToStartWith = ( pessRoot[i].ServiceStatus.dwCurrentState == SERVICE_STOPPED );
  1073. // We will also need to stop dependent services if the are started all ready.
  1074. BOOL fHasDependentServices = FALSE;
  1075. if ( !fServiceWasStoppedToStartWith )
  1076. {
  1077. //
  1078. // if the service was not stopped to start with
  1079. // we need to tell the service to stop.
  1080. //
  1081. #if defined(VERBOSE_DEBUG)
  1082. WCHAR buffer[200];
  1083. _snwprintf(buffer, 200, L"Sending a stop to %s\n", pessRoot[i].lpServiceName );
  1084. buffer[199] = L'\0';
  1085. OutputDebugString( buffer );
  1086. #endif
  1087. hresReturn = SendControlToService( phServiceHandle[i],
  1088. SERVICE_CONTROL_STOP,
  1089. pdwTimeoutMsecs );
  1090. if ( hresReturn == RETURNCODETOHRESULT( ERROR_SERVICE_REQUEST_TIMEOUT ) )
  1091. {
  1092. //
  1093. // WARNING!
  1094. //
  1095. // We're in trouble. Service did not respond in a timely fashion,
  1096. // and further attempt to use this handle ( including closing it )
  1097. // will also hang, so cancel the handle and leak it
  1098. //
  1099. phServiceHandle[i] = NULL;
  1100. }
  1101. else if ( hresReturn == RETURNCODETOHRESULT( ERROR_DEPENDENT_SERVICES_RUNNING ) )
  1102. {
  1103. fHasDependentServices = TRUE;
  1104. }
  1105. }
  1106. //
  1107. // If it was stopped to start with, or if it was not but it couldn't
  1108. // be stopped because it has dependent services. Go ahead and stop
  1109. // the dependent services.
  1110. //
  1111. if ( fHasDependentServices || fServiceWasStoppedToStartWith )
  1112. {
  1113. #if defined(VERBOSE_DEBUG)
  1114. WCHAR buffer[200];
  1115. _snwprintf(buffer, 200, L"Enuming services for %s\n", pessRoot[i].lpServiceName );
  1116. buffer[199] = L'\0';
  1117. OutputDebugString( buffer );
  1118. #endif
  1119. //
  1120. // Get the services that are active because we
  1121. // are only interested in stopping services that
  1122. // are actually running.
  1123. //
  1124. hresReturn = EnumStartServices( schSCM,
  1125. pessRoot[i].lpServiceName,
  1126. SERVICE_ACTIVE,
  1127. abServiceList,
  1128. sizeof(abServiceList),
  1129. &pbServiceList,
  1130. &dwNumRecServices,
  1131. FALSE );
  1132. if ( SUCCEEDED( hresReturn ) )
  1133. {
  1134. hresReturn = StartStopAllRecursive( schSCM,
  1135. (ENUM_SERVICE_STATUS*)pbServiceList,
  1136. dwNumRecServices,
  1137. fStart,
  1138. FALSE,
  1139. pdwTimeoutMsecs );
  1140. if ( pbServiceList != NULL
  1141. && pbServiceList != abServiceList )
  1142. {
  1143. LocalFree( pbServiceList );
  1144. }
  1145. }
  1146. if ( SUCCEEDED( hresReturn ) )
  1147. {
  1148. //
  1149. // If the service itself is not all ready stopped, then stop
  1150. // the service. It could be that it is stopped ( due to a crash )
  1151. // and the other services that were dependent on them are still
  1152. // running.
  1153. //
  1154. if ( !fServiceWasStoppedToStartWith )
  1155. {
  1156. #if defined(VERBOSE_DEBUG)
  1157. WCHAR buffer[200];
  1158. _snwprintf(buffer, 200, L"Sending a 2nd stop to %s\n", pessRoot[i].lpServiceName );
  1159. buffer[199] = L'\0';
  1160. OutputDebugString( buffer );
  1161. #endif
  1162. hresReturn = SendControlToService( phServiceHandle[i],
  1163. SERVICE_CONTROL_STOP,
  1164. pdwTimeoutMsecs );
  1165. }
  1166. }
  1167. }
  1168. if ( FAILED( hresReturn ) )
  1169. {
  1170. #if defined(VERBOSE_DEBUG)
  1171. WCHAR buffer[200];
  1172. _snwprintf(buffer, 200, L"Failed to stop service %s with %x hresult\n", pessRoot[i].lpServiceName, hresReturn );
  1173. buffer[199] = L'\0';
  1174. OutputDebugString( buffer );
  1175. #endif
  1176. break;
  1177. }
  1178. } // end of stopping code
  1179. } // end of valid service handle
  1180. } // end of loop
  1181. //
  1182. // Check service running
  1183. //
  1184. if ( (*pdwTimeoutMsecs < dwSleepInterval) && *pdwTimeoutMsecs )
  1185. {
  1186. dwSleepInterval = *pdwTimeoutMsecs;
  1187. }
  1188. for ( ;
  1189. SUCCEEDED( hresReturn );
  1190. )
  1191. {
  1192. for ( i = 0 ;
  1193. i < dwNumServices;
  1194. i++)
  1195. {
  1196. //
  1197. // Only query status for services known to be not running
  1198. //
  1199. if ( pessRoot[i].ServiceStatus.dwCurrentState
  1200. != (DWORD)(fStart ? SERVICE_RUNNING : SERVICE_STOPPED) )
  1201. {
  1202. if ( QueryServiceStatus( phServiceHandle[i], &ServiceStatus ) )
  1203. {
  1204. //
  1205. // remember status
  1206. //
  1207. pessRoot[i].ServiceStatus.dwCurrentState = ServiceStatus.dwCurrentState;
  1208. if ( fStart && ServiceStatus.dwCurrentState == SERVICE_STOPPED )
  1209. {
  1210. //
  1211. // Service died during startup. no point keeping polling
  1212. // for service state : return an error
  1213. //
  1214. hresReturn = RETURNCODETOHRESULT( ERROR_SERVICE_NOT_ACTIVE );
  1215. break;
  1216. }
  1217. if ( ServiceStatus.dwCurrentState != (DWORD)(fStart ? SERVICE_RUNNING : SERVICE_STOPPED) )
  1218. {
  1219. //
  1220. // will keep looping waiting for target service state
  1221. //
  1222. break;
  1223. }
  1224. }
  1225. else
  1226. {
  1227. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  1228. break;
  1229. }
  1230. }
  1231. }
  1232. //
  1233. // if we did not checked all services then at least one of them
  1234. // is not running ( or some error occured )
  1235. //
  1236. if ( SUCCEEDED( hresReturn ) && i != dwNumServices )
  1237. {
  1238. if ( dwSleepInterval > *pdwTimeoutMsecs )
  1239. {
  1240. hresReturn = RETURNCODETOHRESULT( ERROR_SERVICE_REQUEST_TIMEOUT );
  1241. }
  1242. else
  1243. {
  1244. Sleep( dwSleepInterval );
  1245. *pdwTimeoutMsecs -= dwSleepInterval;
  1246. }
  1247. }
  1248. else
  1249. {
  1250. break;
  1251. }
  1252. }
  1253. //
  1254. // close service handles
  1255. //
  1256. for ( i = 0 ;
  1257. i < dwNumServices;
  1258. i++)
  1259. {
  1260. if ( phServiceHandle[i] != 0 )
  1261. {
  1262. CloseServiceHandle( phServiceHandle[i] );
  1263. }
  1264. }
  1265. }
  1266. LocalFree( phServiceHandle );
  1267. }
  1268. if ( pServiceConfig != NULL
  1269. && pServiceConfig != (LPQUERY_SERVICE_CONFIG)abServiceConfig )
  1270. {
  1271. LocalFree( pServiceConfig );
  1272. }
  1273. return hresReturn;
  1274. }
  1275. //
  1276. // control block for control command requests
  1277. //
  1278. typedef struct {
  1279. HRESULT hres;
  1280. LONG lRefCount;
  1281. DWORD dwCmd;
  1282. SC_HANDLE hServiceHandle;
  1283. } SERVICE_COMMAND_CONTROL_BLOCK;
  1284. extern "C"
  1285. DWORD WINAPI
  1286. ControlServiceThread(
  1287. LPVOID p
  1288. )
  1289. /*++
  1290. ControlServiceThread
  1291. Send a command to a service
  1292. Arguments:
  1293. p - ptr to SERVICE_COMMAND_CONTROL_BLOCK
  1294. Returns:
  1295. 0
  1296. --*/
  1297. {
  1298. SERVICE_STATUS ssStatus;
  1299. SERVICE_COMMAND_CONTROL_BLOCK* pCB = (SERVICE_COMMAND_CONTROL_BLOCK*)p;
  1300. if ( !ControlService( pCB->hServiceHandle, pCB->dwCmd, &ssStatus ) )
  1301. {
  1302. pCB->hres = RETURNCODETOHRESULT( GetLastError() );
  1303. }
  1304. else
  1305. {
  1306. pCB->hres = S_OK;
  1307. }
  1308. if ( InterlockedDecrement( &pCB->lRefCount ) == 0 )
  1309. {
  1310. delete pCB;
  1311. }
  1312. return 0;
  1313. }
  1314. HRESULT
  1315. SendControlToService(
  1316. SC_HANDLE hServiceHandle,
  1317. DWORD dwCmd,
  1318. LPDWORD pdwTimeoutMsecs
  1319. )
  1320. /*++
  1321. ControlServiceThread
  1322. Send a command to a service with timeout
  1323. Arguments:
  1324. hServiceHandle - service to control
  1325. dwCmd - command to send to service
  1326. pdwTimeoutMsecs - timeout ( in ms ). updated on output based on time
  1327. spent waiting for service status
  1328. Returns:
  1329. ERROR_SERVICE_REQUEST_TIMEOUT if timeout
  1330. otherwise COM status
  1331. --*/
  1332. {
  1333. HANDLE hT;
  1334. DWORD dwID;
  1335. DWORD dwBefore;
  1336. DWORD dwAfter;
  1337. SERVICE_COMMAND_CONTROL_BLOCK* pCB;
  1338. DWORD dwTimeoutMsecs = *pdwTimeoutMsecs;
  1339. HRESULT hres;
  1340. //
  1341. // Default timeout for ControlService is 120s, which is too long for us
  1342. // so we create a thread to call ControlService and wait for thread
  1343. // termination.
  1344. // Communication between threads is handled by a refcounted control block
  1345. //
  1346. if ( pCB = new SERVICE_COMMAND_CONTROL_BLOCK )
  1347. {
  1348. pCB->lRefCount = 2; // 1 for caller, 1 for callee
  1349. pCB->dwCmd = dwCmd;
  1350. pCB->hServiceHandle = hServiceHandle;
  1351. pCB->hres = S_OK;
  1352. dwBefore = GetTickCount();
  1353. if ( hT = CreateThread( NULL,
  1354. 0,
  1355. (LPTHREAD_START_ROUTINE)ControlServiceThread,
  1356. (LPVOID)pCB,
  1357. 0,
  1358. &dwID ) )
  1359. {
  1360. if ( WaitForSingleObject( hT, dwTimeoutMsecs ) == WAIT_OBJECT_0 )
  1361. {
  1362. hres = pCB->hres;
  1363. }
  1364. else
  1365. {
  1366. hres = RETURNCODETOHRESULT( ERROR_SERVICE_REQUEST_TIMEOUT );
  1367. }
  1368. CloseHandle( hT );
  1369. if ( InterlockedDecrement( &pCB->lRefCount ) == 0 )
  1370. {
  1371. delete pCB;
  1372. }
  1373. //
  1374. // Update caller's timeout
  1375. //
  1376. dwAfter = GetTickCount();
  1377. if ( dwAfter > dwBefore )
  1378. {
  1379. if ( dwAfter - dwBefore <= dwTimeoutMsecs )
  1380. {
  1381. *pdwTimeoutMsecs -= dwAfter - dwBefore;
  1382. }
  1383. else
  1384. {
  1385. *pdwTimeoutMsecs = 0;
  1386. }
  1387. }
  1388. }
  1389. else
  1390. {
  1391. delete pCB;
  1392. hres = RETURNCODETOHRESULT( GetLastError() );
  1393. }
  1394. }
  1395. else
  1396. {
  1397. hres = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  1398. }
  1399. return hres;
  1400. }
  1401. HRESULT
  1402. SerializeEnumServiceBuffer(
  1403. LPENUM_SERVICE_STATUS pessDependentServices,
  1404. DWORD dwNumServices,
  1405. LPBYTE pbBuffer,
  1406. DWORD dwBufferSize,
  1407. LPDWORD pdwMDRequiredBufferSize
  1408. )
  1409. /*++
  1410. SerializeEnumServiceBuffer
  1411. Serialize array of ENUM_SERVICE_STATUS to buffer,
  1412. replacing ptr by offset in buffer
  1413. Arguments:
  1414. pessDependentServices - array of ENUM_SERVICE_STATUS to serialize
  1415. dwNumServices - # of entries in pessDependentServices
  1416. pbBuffer - buffer filled with serialized status as array of SERIALIZED_ENUM_SERVICE_STATUS
  1417. dwBufferSize - maximum size of pbBuffer
  1418. pdwMDRequiredBufferSize - updated with required size if dwBufferSize too small
  1419. Returns:
  1420. ERROR_INSUFFICIENT_BUFFER if dwBufferSize too small
  1421. otherwise COM status
  1422. --*/
  1423. {
  1424. HRESULT hresReturn = S_OK;
  1425. DWORD dwMinSize = 0;
  1426. UINT i;
  1427. if ( !pbBuffer )
  1428. {
  1429. dwBufferSize = 0;
  1430. }
  1431. //
  1432. // size of output buffer is based on size of array of SERIALIZED_ENUM_SERVICE_STATUS
  1433. // plus size of all strings : service name & display name for each entry
  1434. //
  1435. dwMinSize = sizeof(SERIALIZED_ENUM_SERVICE_STATUS) * dwNumServices;
  1436. for ( i = 0 ;
  1437. i < dwNumServices ;
  1438. ++i )
  1439. {
  1440. UINT cServiceName = _tcslen( pessDependentServices[i].lpServiceName ) + 1;
  1441. UINT cDisplayName = _tcslen( pessDependentServices[i].lpDisplayName ) + 1;
  1442. //
  1443. // do not update if output buffer is too small, but keep looping to determine
  1444. // total size
  1445. //
  1446. if ( dwBufferSize >= dwMinSize + (cServiceName + cDisplayName) * sizeof(TCHAR) )
  1447. {
  1448. //
  1449. // copy service status as is
  1450. //
  1451. ((SERIALIZED_ENUM_SERVICE_STATUS*)pbBuffer)[i].ServiceStatus =
  1452. pessDependentServices[i].ServiceStatus;
  1453. //
  1454. // copy string and convert ptr to string to index in output buffer
  1455. //
  1456. memcpy( pbBuffer + dwMinSize, pessDependentServices[i].lpServiceName, cServiceName * sizeof(TCHAR) );
  1457. ((SERIALIZED_ENUM_SERVICE_STATUS*)pbBuffer)[i].iServiceName = dwMinSize ;
  1458. memcpy( pbBuffer + dwMinSize + cServiceName * sizeof(TCHAR), pessDependentServices[i].lpDisplayName, cDisplayName * sizeof(TCHAR) );
  1459. ((SERIALIZED_ENUM_SERVICE_STATUS*)pbBuffer)[i].iDisplayName = dwMinSize + cServiceName * sizeof(TCHAR) ;
  1460. }
  1461. dwMinSize += (cServiceName + cDisplayName) * sizeof(TCHAR) ;
  1462. }
  1463. if ( dwBufferSize < dwMinSize )
  1464. {
  1465. *pdwMDRequiredBufferSize = dwMinSize;
  1466. hresReturn = RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  1467. }
  1468. return hresReturn;
  1469. }
  1470. STDMETHODIMP
  1471. CIisRestart::Status(
  1472. DWORD dwBufferSize,
  1473. unsigned char * pbBuffer,
  1474. DWORD * pdwMDRequiredBufferSize,
  1475. DWORD * pdwNumServices
  1476. )
  1477. /*++
  1478. Status
  1479. Return status of all internet services as array of ENUM_SERVICE_STATUS
  1480. Arguments:
  1481. dwBufferSize - maximum size of pbBuffer
  1482. pbBuffer - buffer filled with serialized status as array of SERIALIZED_ENUM_SERVICE_STATUS
  1483. pdwMDRequiredBufferSize - updated with required size if dwBufferSize too small
  1484. pdwNumServices - updated with number of entries stored in pbBuffer
  1485. Returns:
  1486. ERROR_RESOURCE_DISABLED if access to restart commands disabled
  1487. ERROR_INSUFFICIENT_BUFFER if dwBufferSize too small
  1488. otherwise COM status
  1489. --*/
  1490. {
  1491. SC_HANDLE schSCM = NULL;
  1492. DWORD dwBytesNeeded;
  1493. DWORD dwNumServices = 0;
  1494. HRESULT hresReturn = E_FAIL;
  1495. BYTE abServiceList[2048];
  1496. LPBYTE pbServiceList = NULL;
  1497. LPENUM_SERVICE_STATUS pessDependentServices;
  1498. if ( !IsEnableRemote() )
  1499. {
  1500. hresReturn = RETURNCODETOHRESULT( ERROR_RESOURCE_DISABLED );
  1501. }
  1502. else
  1503. {
  1504. schSCM = OpenSCManager(NULL,
  1505. NULL,
  1506. SC_MANAGER_ALL_ACCESS);
  1507. if ( schSCM == NULL )
  1508. {
  1509. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  1510. }
  1511. else
  1512. {
  1513. hresReturn = EnumStartServices( schSCM,
  1514. _T("IISADMIN"),
  1515. SERVICE_STATE_ALL,
  1516. abServiceList,
  1517. sizeof(abServiceList),
  1518. &pbServiceList,
  1519. pdwNumServices,
  1520. FALSE );
  1521. if ( SUCCEEDED(hresReturn) )
  1522. {
  1523. pessDependentServices = (LPENUM_SERVICE_STATUS)pbServiceList;
  1524. hresReturn = SerializeEnumServiceBuffer( (LPENUM_SERVICE_STATUS)pbServiceList,
  1525. *pdwNumServices,
  1526. pbBuffer,
  1527. dwBufferSize,
  1528. pdwMDRequiredBufferSize );
  1529. if ( pbServiceList != NULL
  1530. && pbServiceList != abServiceList )
  1531. {
  1532. LocalFree( pbServiceList );
  1533. }
  1534. }
  1535. CloseServiceHandle(schSCM);
  1536. }
  1537. }
  1538. return hresReturn;
  1539. }
  1540. HRESULT
  1541. EnumStartServices(
  1542. SC_HANDLE schSCM,
  1543. LPTSTR pszRoot,
  1544. DWORD dwTargetState,
  1545. LPBYTE abServiceList,
  1546. DWORD dwInitializeServiceListSize,
  1547. LPBYTE* ppbServiceList,
  1548. LPDWORD pdwNumServices,
  1549. BOOL fAddIisadmin
  1550. )
  1551. /*++
  1552. EnumStartServices
  1553. Enumerate dependent services to output buffer as array of ENUM_SERVICE_STATUS
  1554. Arguments:
  1555. schSCM - handle to SCM
  1556. pszRoot - service for which to enumerate dependencies
  1557. dwTargetState - dwServiceState for call to EnumDependentServices()
  1558. abServiceList - initial output buffer
  1559. dwInitializeServiceListSize - maximum size of abServiceList
  1560. ppbServiceList - updated with output buffer, may be abServiceList if long enough
  1561. otherwise returned buffer is to be freed using LocalFree()
  1562. pdwNumServices - updated with number of entries stored in pbBuffer
  1563. fAddIisadmin - TRUE to add IISADMIN to list of dependent services
  1564. Returns:
  1565. COM status
  1566. --*/
  1567. {
  1568. HRESULT hresReturn = S_OK;
  1569. SC_HANDLE schIISADMIN = NULL;
  1570. DWORD dwBytesNeeded;
  1571. DWORD dwAddSize = 0;
  1572. DWORD dwOffsetSize = 0;
  1573. *ppbServiceList = NULL;
  1574. schIISADMIN = OpenService(schSCM,
  1575. pszRoot,
  1576. STANDARD_RIGHTS_REQUIRED | SERVICE_ENUMERATE_DEPENDENTS);
  1577. if (schIISADMIN == NULL)
  1578. {
  1579. hresReturn = RETURNCODETOHRESULT(GetLastError());
  1580. }
  1581. else
  1582. {
  1583. if ( fAddIisadmin )
  1584. {
  1585. //
  1586. // if initial size too small for Iisadmin description then fail
  1587. //
  1588. dwOffsetSize = sizeof(ENUM_SERVICE_STATUS );
  1589. dwAddSize = dwOffsetSize;
  1590. if ( dwAddSize > dwInitializeServiceListSize )
  1591. {
  1592. hresReturn = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  1593. goto Cleanup;
  1594. }
  1595. //
  1596. // Use global static name for IISADMIN, no need to copy it to output buffer
  1597. //
  1598. ((LPENUM_SERVICE_STATUS)abServiceList)->lpDisplayName = _T("IISADMIN");
  1599. ((LPENUM_SERVICE_STATUS)abServiceList)->lpServiceName = _T("IISADMIN");
  1600. //
  1601. // don't want to check service status at this point as it may be stuck
  1602. // so assume RUNNING.
  1603. //
  1604. ((LPENUM_SERVICE_STATUS)abServiceList)->ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  1605. }
  1606. if (!EnumDependentServices( schIISADMIN,
  1607. dwTargetState,
  1608. (LPENUM_SERVICE_STATUS)(abServiceList + dwOffsetSize),
  1609. dwInitializeServiceListSize - dwAddSize,
  1610. &dwBytesNeeded,
  1611. pdwNumServices))
  1612. {
  1613. if (GetLastError() == ERROR_MORE_DATA)
  1614. {
  1615. if ( (*ppbServiceList = (LPBYTE)LocalAlloc( LMEM_FIXED,
  1616. dwBytesNeeded + dwAddSize )) == NULL )
  1617. {
  1618. hresReturn = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  1619. }
  1620. else
  1621. {
  1622. memcpy( *ppbServiceList, abServiceList, dwOffsetSize );
  1623. if (!EnumDependentServices( schIISADMIN,
  1624. SERVICE_INACTIVE,
  1625. (LPENUM_SERVICE_STATUS)(*ppbServiceList + dwOffsetSize),
  1626. dwBytesNeeded,
  1627. &dwBytesNeeded,
  1628. pdwNumServices))
  1629. {
  1630. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  1631. LocalFree( *ppbServiceList );
  1632. *ppbServiceList = NULL;
  1633. }
  1634. }
  1635. }
  1636. else
  1637. {
  1638. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  1639. }
  1640. }
  1641. else
  1642. {
  1643. *ppbServiceList = abServiceList;
  1644. }
  1645. }
  1646. Cleanup:
  1647. if ( schIISADMIN )
  1648. {
  1649. CloseServiceHandle( schIISADMIN );
  1650. }
  1651. if ( fAddIisadmin && SUCCEEDED( hresReturn ) )
  1652. {
  1653. ++*pdwNumServices;
  1654. }
  1655. return hresReturn;
  1656. }
  1657. BOOL
  1658. IsEnableRemote(
  1659. )
  1660. /*++
  1661. IsEnableRemote
  1662. Check if restart I/F enabled
  1663. ( based on HKLM\SOFTWARE\Microsoft\INetStp::EnableRestart::REG_DWORD )
  1664. Arguments:
  1665. None
  1666. Returns:
  1667. TRUE if enabled, otherwise FALSE
  1668. --*/
  1669. {
  1670. BOOL fSt = FALSE;
  1671. HKEY hKey;
  1672. DWORD dwValue;
  1673. DWORD dwType;
  1674. DWORD dwSize;
  1675. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1676. TEXT("SOFTWARE\\Microsoft\\INetStp"),
  1677. 0,
  1678. KEY_READ,
  1679. &hKey ) == ERROR_SUCCESS )
  1680. {
  1681. dwSize = sizeof( dwValue );
  1682. if ( RegQueryValueEx( hKey,
  1683. TEXT("EnableRestart"),
  1684. 0,
  1685. &dwType,
  1686. (LPBYTE)&dwValue,
  1687. &dwSize ) == ERROR_SUCCESS )
  1688. {
  1689. fSt = dwValue == 1;
  1690. }
  1691. else
  1692. {
  1693. fSt = TRUE;
  1694. }
  1695. RegCloseKey( hKey );
  1696. }
  1697. return fSt;
  1698. }
  1699. BOOL
  1700. CloseSystemExceptionHandler(
  1701. LPCTSTR pszWindowName
  1702. )
  1703. /*++
  1704. CloseSystemExceptionHandler
  1705. Send a close ( e.g. terminate apps without debugging ) command to the window
  1706. created by NT when a debugger is not configured to automatically start after app exception.
  1707. This window stays on screen until interactive user select either OK or debug app, which is
  1708. a problem for automated restart.
  1709. So we locate this window and send it a command requesting stop w/o debugging.
  1710. We locate the window by enumerating all windows and checking for window name beginning with the name
  1711. of the application that raised an exception, e.g. "inetinfo.exe"
  1712. Arguments:
  1713. pszWindowName - window name where to send terminate command
  1714. Returns:
  1715. TRUE if SUCCESS, otherwise FALSE
  1716. --*/
  1717. {
  1718. BOOL fSt = TRUE;
  1719. HKEY hKey;
  1720. DWORD dwValue;
  1721. DWORD dwType;
  1722. DWORD dwSize;
  1723. TASK_LIST tl;
  1724. TCHAR achBuffer[MAX_PATH];
  1725. GetPidFromTitle( &tl.dwProcessId, (HWND*)&tl.hwnd, pszWindowName );
  1726. if ( tl.dwProcessId )
  1727. {
  1728. #if 0
  1729. //
  1730. // Original idea was to close the exception window, but this fires up the debugger, so I attempted
  1731. // to disable the debugger before closing the window, but this does not work as this setting is
  1732. // apparently not dynamic, i.e. you have to restart NT for this to take effect.
  1733. //
  1734. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1735. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"),
  1736. 0,
  1737. KEY_READ|KEY_WRITE,
  1738. &hKey ) == ERROR_SUCCESS )
  1739. {
  1740. dwSize = sizeof( achBuffer );
  1741. if ( RegQueryValueEx( hKey,
  1742. TEXT("Debugger"),
  1743. 0,
  1744. &dwType,
  1745. (LPBYTE)achBuffer,
  1746. &dwSize ) != ERROR_SUCCESS )
  1747. {
  1748. RegCloseKey( hKey );
  1749. return FALSE;
  1750. }
  1751. if ( RegSetValueEx( hKey,
  1752. TEXT("Debugger"),
  1753. 0,
  1754. REG_SZ,
  1755. (const BYTE*)TEXT(""),
  1756. sizeof(TCHAR) ) != ERROR_SUCCESS )
  1757. {
  1758. }
  1759. RegCloseKey( hKey );
  1760. }
  1761. else
  1762. {
  1763. return FALSE;
  1764. }
  1765. #endif
  1766. #if defined(VERBOSE_DEBUG)
  1767. OutputDebugString(_T("located exception window, try to close it\n"));
  1768. #endif
  1769. //PostMessage( (HWND)tl.hwnd, WM_CLOSE, 0, 0 );
  1770. //
  1771. // WARNING: major hack: turns out that WM_COMMAND 1 is the command to send to
  1772. // the exception handler to ask it to close application w/o debugging
  1773. // This works for NT5, may change in the future...
  1774. //
  1775. PostMessage( (HWND)tl.hwnd, WM_COMMAND, 1, 0 );
  1776. Sleep( 1000 );
  1777. #if 0
  1778. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1779. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"),
  1780. 0,
  1781. KEY_WRITE,
  1782. &hKey ) == ERROR_SUCCESS )
  1783. {
  1784. if ( RegSetValueEx( hKey,
  1785. TEXT("Debugger"),
  1786. 0,
  1787. REG_SZ,
  1788. (const BYTE*)achBuffer,
  1789. dwSize ) == ERROR_SUCCESS )
  1790. {
  1791. fSt = TRUE;
  1792. }
  1793. RegCloseKey( hKey );
  1794. }
  1795. #endif
  1796. }
  1797. else
  1798. {
  1799. fSt = TRUE;
  1800. }
  1801. return fSt;
  1802. }
  1803. HRESULT
  1804. KillTaskByName(
  1805. LPTSTR pname,
  1806. LPSTR pszMandatoryModule
  1807. )
  1808. /*++
  1809. KillTaskByName
  1810. Kill a process by name
  1811. Most of the code was taken from the Platform SDK kill,c sample, and
  1812. utilizes the common.c module included in this project.
  1813. Works only on NT platforms ( NOT Win 9x )
  1814. Arguments:
  1815. pname - name of process to kill ( name of executable w/o extension )
  1816. pszMandatoryModule - module name to look for, e.g. "wam.dll"
  1817. can be NULL for unconditional kill
  1818. Returns:
  1819. COM status
  1820. --*/
  1821. {
  1822. TASK_LIST tlist[MAX_TASKS];
  1823. DWORD i;
  1824. DWORD numTasks;
  1825. TASK_LIST_ENUM te;
  1826. TCHAR tname[PROCESS_SIZE];
  1827. LPTSTR p;
  1828. OSVERSIONINFO verInfo = {0};
  1829. LPGetTaskList GetTaskList;
  1830. LPEnableDebugPriv EnableDebugPriv;
  1831. BOOL fSuccess = TRUE;
  1832. HRESULT hres = S_OK;
  1833. //
  1834. // Determine what system we're on and do the right thing
  1835. //
  1836. verInfo.dwOSVersionInfoSize = sizeof (verInfo);
  1837. GetVersionEx(&verInfo);
  1838. switch (verInfo.dwPlatformId)
  1839. {
  1840. case VER_PLATFORM_WIN32_NT:
  1841. GetTaskList = GetTaskListNT;
  1842. EnableDebugPriv = EnableDebugPrivNT;
  1843. break;
  1844. #if 0
  1845. case VER_PLATFORM_WIN32_WINDOWS:
  1846. GetTaskList = GetTaskList95;
  1847. EnableDebugPriv = EnableDebugPriv95;
  1848. break;
  1849. #endif
  1850. default:
  1851. return RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER);
  1852. }
  1853. //
  1854. // Obtain the ability to manipulate other processes
  1855. //
  1856. EnableDebugPriv();
  1857. //
  1858. // get the task list for the system
  1859. //
  1860. hres = GetTaskList( tlist, MAX_TASKS, pname, &numTasks, TRUE, pszMandatoryModule );
  1861. #if 0
  1862. //
  1863. // enumerate all windows and try to get the window
  1864. // titles for each task
  1865. //
  1866. te.tlist = tlist;
  1867. te.numtasks = numTasks;
  1868. GetWindowTitles( &te );
  1869. for (i=0; i<numTasks; i++)
  1870. {
  1871. tname[0] = 0;
  1872. lstrcpy( tname, tlist[i].ProcessName );
  1873. p = _tcschr( tname, _T('.') );
  1874. if (p)
  1875. {
  1876. p[0] = _T('\0');
  1877. }
  1878. if (MatchPattern( tname, pname ))
  1879. {
  1880. tlist[i].flags = TRUE;
  1881. }
  1882. else if (MatchPattern( tlist[i].ProcessName, pname ))
  1883. {
  1884. tlist[i].flags = TRUE;
  1885. }
  1886. else if (MatchPattern( tlist[i].WindowTitle, pname ))
  1887. {
  1888. tlist[i].flags = TRUE;
  1889. }
  1890. }
  1891. #endif
  1892. #if 0
  1893. for (i=0; i<numTasks; i++)
  1894. {
  1895. if (tlist[i].flags)
  1896. {
  1897. if ( FAILED( hres = KillProcess( &tlist[i], TRUE ) ) )
  1898. {
  1899. break;
  1900. }
  1901. }
  1902. }
  1903. #endif
  1904. return hres;
  1905. }
  1906. VOID
  1907. ReportStatus(
  1908. DWORD dwId,
  1909. DWORD dwStatus
  1910. )
  1911. /*++
  1912. ReportStatus
  1913. Log status event
  1914. Arguments:
  1915. dwId - ID of event to log ( source is "IISCTLS" , SYSTEM log )
  1916. dwStatus - status of operation ( HRESULT )
  1917. Returns:
  1918. Nothing
  1919. --*/
  1920. {
  1921. HANDLE hLog;
  1922. LPTSTR aParams[1];
  1923. if ( (hLog = RegisterEventSource( NULL, _T("IISCTLS") )) != NULL )
  1924. {
  1925. if ( SUCCEEDED( WhoAmI( aParams + 0 ) ) )
  1926. {
  1927. ReportEvent( hLog,
  1928. EVENTLOG_INFORMATION_TYPE,
  1929. 0,
  1930. dwId,
  1931. NULL,
  1932. 1,
  1933. sizeof(DWORD),
  1934. (LPCTSTR*)aParams,
  1935. &dwStatus );
  1936. LocalFree( aParams[0] );
  1937. }
  1938. DeregisterEventSource( hLog );
  1939. }
  1940. }
  1941. HRESULT
  1942. WhoAmI(
  1943. LPTSTR* ppPrincipal
  1944. )
  1945. /*++
  1946. WhoAmI
  1947. Return currently impersonated user
  1948. As this is a COM server running under the identity of the invoker
  1949. this means we access the process token. So we might end up getting
  1950. the wrong user name if the object is invoked in close succession
  1951. ( within the 5s server exit timeout ) by different users.
  1952. Arguments:
  1953. ppPrincipal - update with ptr to string containing user name ( domain\acct )
  1954. must be freed using LocalFree()
  1955. Returns:
  1956. Error status
  1957. --*/
  1958. {
  1959. TCHAR* pPrincipal;
  1960. TCHAR achUserName[512];
  1961. TCHAR achDomain[512];
  1962. DWORD dwLen;
  1963. DWORD dwDomainLen;
  1964. DWORD SIDsize = 256;
  1965. SID_NAME_USE SIDtype = SidTypeUser;
  1966. LPSTR lpszUsr;
  1967. HRESULT hres = E_FAIL;
  1968. #if 0
  1969. //
  1970. // naive attempt to retrieve user name and domain.
  1971. // Unfortunately a LookupAccountName() followed by LookupAccountSid always return
  1972. // the local domain ( typically the local computer name )
  1973. // even if the account is a domain account.
  1974. // So we can't use this...
  1975. //
  1976. PSID pUserSID = (PSID)LocalAlloc( LMEM_FIXED, SIDsize);
  1977. if ( !GetUserName( achUserName, &dwLen ) )
  1978. wcscpy(achUserName, _T("Unknown user"));
  1979. LookupAccountName(NULL, achUserName, pUserSID, &SIDsize,
  1980. achDomain, &dwDomainLen, &SIDtype);
  1981. dwLen = sizeof( achUserName );
  1982. dwDomainLen = sizeof(achDomain);
  1983. LookupAccountSid(NULL, pUserSID, achUserName, &dwLen,
  1984. achDomain, &dwDomainLen, &SIDtype);
  1985. _wcsupr(achDomain);
  1986. wcscat(szMsg,achDomain);
  1987. wcscat(szMsg,_T("\\"));
  1988. wcscat(szMsg,achUserName);
  1989. #else
  1990. #if 0
  1991. //
  1992. // Attempt to retrieve the thread token instead of the process token.
  1993. // doesn't work for COM servers
  1994. //
  1995. IServerSecurity* pSec;
  1996. if ( SUCCEEDED( CoGetCallContext( IID_IServerSecurity,
  1997. (void**)&pSec ) ) )
  1998. {
  1999. DWORD AuthnSvc;
  2000. DWORD AuthzSvc;
  2001. OLECHAR* pServerPrincName;
  2002. DWORD AuthnLevel;
  2003. DWORD ImpLevel;
  2004. void* pPrivs;
  2005. DWORD Capabilities = 0;
  2006. //if ( FAILED(pSec->QueryBlanket( &AuthnSvc, &AuthzSvc, &pServerPrincName, &AuthnLevel, &ImpLevel, &pPrivs, &Capabilities)) )
  2007. if ( FAILED(pSec->ImpersonateClient()) )
  2008. {
  2009. }
  2010. else
  2011. {
  2012. #endif
  2013. //
  2014. // So we have to access the process token and retrieve account & user name
  2015. // by using LookupAccountSid()
  2016. //
  2017. HANDLE hAccTok = NULL;
  2018. if ( OpenProcessToken( GetCurrentProcess(),
  2019. TOKEN_EXECUTE|TOKEN_QUERY,
  2020. &hAccTok ) )
  2021. {
  2022. BYTE abSidAndInfo[512];
  2023. DWORD dwReq;
  2024. //
  2025. // provide a reasonably sized buffer. If this fails we don't
  2026. // retry with a bigger one.
  2027. //
  2028. if ( GetTokenInformation( hAccTok,
  2029. TokenUser,
  2030. (LPVOID)abSidAndInfo,
  2031. sizeof(abSidAndInfo),
  2032. &dwReq) )
  2033. {
  2034. dwLen = sizeof( achUserName ) / sizeof(TCHAR);
  2035. dwDomainLen = sizeof(achDomain) / sizeof(TCHAR);
  2036. //
  2037. // provide a reasonably sized buffer. If this fails we don't
  2038. // retry with a bigger one.
  2039. //
  2040. if ( LookupAccountSid( NULL,
  2041. ((SID_AND_ATTRIBUTES*)abSidAndInfo)->Sid,
  2042. achUserName,
  2043. &dwLen,
  2044. achDomain,
  2045. &dwDomainLen,
  2046. &SIDtype) )
  2047. {
  2048. //
  2049. // We return a LocalAlloc'ed buffer
  2050. //
  2051. dwLen = _tcslen( achUserName );
  2052. dwDomainLen = _tcslen( achDomain );
  2053. if ( pPrincipal = (LPTSTR)LocalAlloc( LMEM_FIXED,
  2054. (dwLen + 1 + dwDomainLen + 1 ) * sizeof(TCHAR) ) )
  2055. {
  2056. memcpy( pPrincipal,
  2057. achDomain,
  2058. sizeof(TCHAR)*dwDomainLen );
  2059. pPrincipal[dwDomainLen] = '\\';
  2060. memcpy( pPrincipal + dwDomainLen + 1,
  2061. achUserName,
  2062. sizeof(TCHAR)*(dwLen+1) );
  2063. *ppPrincipal = pPrincipal;
  2064. hres = S_OK;
  2065. }
  2066. else
  2067. {
  2068. hres = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  2069. }
  2070. }
  2071. else
  2072. {
  2073. hres = RETURNCODETOHRESULT( GetLastError() );
  2074. }
  2075. }
  2076. else
  2077. {
  2078. hres = RETURNCODETOHRESULT( GetLastError() );
  2079. }
  2080. CloseHandle( hAccTok );
  2081. }
  2082. else
  2083. {
  2084. hres = RETURNCODETOHRESULT( GetLastError() );
  2085. }
  2086. #if 0
  2087. }
  2088. pSec->Release();
  2089. }
  2090. else
  2091. {
  2092. OutputDebugString(_T("fail to get call context"));
  2093. }
  2094. #endif
  2095. #endif
  2096. return hres;
  2097. }
  2098. BOOL
  2099. W3SVCandW3SSL(
  2100. DWORD currentIndex,
  2101. ENUM_SERVICE_STATUS* pessRoot,
  2102. DWORD dwNumServices
  2103. )
  2104. {
  2105. /*++
  2106. W3SVCandW3SSL
  2107. Return currently impersonated user
  2108. As this is a COM server running under the identity of the invoker
  2109. this means we access the process token. So we might end up getting
  2110. the wrong user name if the object is invoked in close succession
  2111. ( within the 5s server exit timeout ) by different users.
  2112. Arguments:
  2113. DWORD currentIndex - index of the service we are deciding if we should process.
  2114. ENUM_SERVICE_STATUS* pessRoot - the set of services we are working on.
  2115. DWORD dwNumServices - the number of services in the set.
  2116. Returns:
  2117. TRUE if we found the w3svc and w3ssl on the same line and we are looking at the w3svc
  2118. --*/
  2119. BOOL bResult = FALSE;
  2120. // check if we are looking at the w3svc. If we are find out if the
  2121. // w3ssl is on the same level. Note the w3ssl will always be listed
  2122. // after the w3svc.
  2123. if ( _wcsicmp( pessRoot[currentIndex].lpServiceName, L"w3svc" ) == 0 )
  2124. {
  2125. for ( DWORD i = currentIndex + 1;
  2126. ( i < dwNumServices ) && ( bResult == FALSE );
  2127. i++ )
  2128. {
  2129. if ( _wcsicmp( pessRoot[i].lpServiceName, L"w3ssl" ) == 0 )
  2130. {
  2131. bResult = TRUE;
  2132. }
  2133. }
  2134. }
  2135. return bResult;
  2136. }