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.

1264 lines
39 KiB

  1. /*
  2. IisRsta.cxx
  3. Command line utility for access to IIisServiceControl
  4. FILE HISTORY:
  5. Phillich 06-Oct-1998 Created
  6. */
  7. #define INITGUID
  8. #include <windows.h>
  9. #include <winnlsp.h>
  10. #include <tchar.h>
  11. #include <stdio.h>
  12. #include <ole2.h>
  13. #include <locale.h>
  14. #include "iisrsta.h"
  15. #include "iisrstam.h"
  16. // Including so we can use the WIN32_FROM_HRESULT macro that is defined there
  17. #include "iisdef.h"
  18. typedef BOOL (*PFNCHANGESERVICECONFIG2)(SC_HANDLE,DWORD,LPVOID);
  19. #define MAX_STRINGIZED_ULONG_CHAR_COUNT 11 // "4294967295", including the terminating null
  20. //
  21. // Helper functions
  22. //
  23. VOID
  24. DisplayErrorMessage(
  25. DWORD dwErr
  26. )
  27. /*++
  28. DisplayErrorMessage
  29. Display error message associated with error code
  30. Arguments:
  31. dwErr - Win32 error code
  32. Returns:
  33. Nothing
  34. --*/
  35. {
  36. LPTSTR pErr;
  37. if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  38. NULL,
  39. dwErr,
  40. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  41. (LPTSTR)&pErr,
  42. 0,
  43. NULL ) )
  44. {
  45. LPTSTR p;
  46. p = _tcschr( pErr, TEXT('\r') );
  47. if ( p != NULL )
  48. {
  49. *p = TEXT('\0');
  50. }
  51. _fputts( pErr, stdout );
  52. LocalFree( pErr );
  53. }
  54. }
  55. VOID
  56. PrintMessage(
  57. DWORD dwId,
  58. DWORD dwParams,
  59. LPVOID* pParams
  60. )
  61. /*++
  62. PrintMessage
  63. Print message ( from message file ) with optional parameters
  64. Arguments:
  65. dwId - message ID
  66. dwParams - # of params in pParams
  67. pParams - ptr to array of parameters
  68. Returns:
  69. Nothing
  70. --*/
  71. {
  72. LPTSTR pBuf;
  73. if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  74. (LPCVOID)NULL, //GetModuleHandle(NULL),
  75. dwId,
  76. 0,
  77. (LPTSTR)&pBuf,
  78. dwParams,
  79. (va_list *)pParams ) )
  80. {
  81. _fputts( pBuf, stdout );
  82. LocalFree( pBuf );
  83. }
  84. }
  85. VOID
  86. CmdError(
  87. DWORD dwId,
  88. HRESULT hRes
  89. )
  90. /*++
  91. CmdError
  92. Display message followed by error description ( error message + numerical code )
  93. Arguments:
  94. dwId - message ID
  95. hRes - error code
  96. Returns:
  97. Nothing
  98. --*/
  99. {
  100. TCHAR achBuf[128];
  101. PrintMessage( dwId, 0, NULL );
  102. if ( hRes == HRESULT_FROM_WIN32( ERROR_RESOURCE_DISABLED ) )
  103. {
  104. PrintMessage( IRSTASTR_REMOTE_DISABLED, 0, NULL );
  105. }
  106. else if ( hRes == HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) )
  107. {
  108. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  109. }
  110. else if ( hRes == HRESULT_FROM_WIN32( ERROR_SERVICE_NOT_ACTIVE ) )
  111. {
  112. PrintMessage( IRSTASTR_SERVICE_NOT_ACTIVE, 0, NULL );
  113. }
  114. else
  115. {
  116. DisplayErrorMessage( WIN32_FROM_HRESULT( hRes ) );
  117. wsprintf( achBuf, _T(" (%u, %x)\n"), (DWORD)hRes, (DWORD)hRes );
  118. _fputts( achBuf, stdout );
  119. }
  120. }
  121. LPTSTR
  122. GetString(
  123. DWORD dwId
  124. )
  125. /*++
  126. GetString
  127. Retrieve message content
  128. Arguments:
  129. dwId - message ID
  130. Returns:
  131. Ptr to message. Must be freed using LocalFree()
  132. --*/
  133. {
  134. LPTSTR pBuf;
  135. if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_HMODULE,
  136. (LPCVOID)NULL,
  137. dwId,
  138. 0,
  139. (LPTSTR)&pBuf,
  140. 0,
  141. NULL ) )
  142. {
  143. LPTSTR p;
  144. p = _tcschr( pBuf, TEXT('\r') );
  145. if ( p != NULL )
  146. {
  147. *p = TEXT('\0');
  148. }
  149. return pBuf;
  150. }
  151. return NULL;
  152. }
  153. HRESULT
  154. DeserializeEnumServiceBuffer(
  155. LPBYTE pbInBuffer,
  156. DWORD dwNumServices,
  157. LPBYTE pbBuffer,
  158. DWORD dwBufferSize,
  159. LPDWORD pdwMDRequiredBufferSize
  160. )
  161. /*++
  162. DeserializeEnumServiceBuffer
  163. Deserialize array of SERIALIZED_ENUM_SERVICE_STATUS to buffer,
  164. replacing offset in buffer by ptr
  165. Arguments:
  166. pbInBuffer - buffer containing serialized status as array of SERIALIZED_ENUM_SERVICE_STATUS
  167. dwNumServices - # of entries in pbInBuffer
  168. pbBuffer - buffer filled with deserialized status as array of ENUM_SERVICE_STATUS
  169. dwBufferSize - maximum size of pbBuffer
  170. pdwMDRequiredBufferSize - updated with required size if dwBufferSize too small
  171. Returns:
  172. ERROR_INSUFFICIENT_BUFFER if dwBufferSize too small
  173. otherwise COM status
  174. --*/
  175. {
  176. HRESULT hresReturn = S_OK;
  177. DWORD dwMinSize = 0;
  178. UINT i;
  179. SERIALIZED_ENUM_SERVICE_STATUS* pessDependentServices = (SERIALIZED_ENUM_SERVICE_STATUS*)pbInBuffer;
  180. if ( !pbBuffer )
  181. {
  182. dwBufferSize = 0;
  183. }
  184. dwMinSize = sizeof(ENUM_SERVICE_STATUS) * dwNumServices;
  185. for ( i = 0 ;
  186. i < dwNumServices ;
  187. ++i )
  188. {
  189. UINT cServiceName = (UINT) _tcslen( (TCHAR*)(pbInBuffer + pessDependentServices[i].iServiceName) ) + 1;
  190. UINT cDisplayName = (UINT) _tcslen( (TCHAR*)(pbInBuffer + pessDependentServices[i].iDisplayName) ) + 1;
  191. if ( dwBufferSize >= dwMinSize + ( cServiceName + cDisplayName ) * sizeof(TCHAR) )
  192. {
  193. ((LPENUM_SERVICE_STATUS)pbBuffer)[i].ServiceStatus =
  194. pessDependentServices[i].ServiceStatus;
  195. memcpy( pbBuffer + dwMinSize, pbInBuffer + pessDependentServices[i].iServiceName, cServiceName * sizeof(TCHAR) );
  196. ((LPENUM_SERVICE_STATUS)pbBuffer)[i].lpServiceName = (TCHAR*)(pbBuffer + dwMinSize);
  197. memcpy( pbBuffer + dwMinSize + cServiceName * sizeof(TCHAR), pbInBuffer + pessDependentServices[i].iDisplayName, cDisplayName * sizeof(TCHAR) );
  198. ((LPENUM_SERVICE_STATUS)pbBuffer)[i].lpDisplayName = (TCHAR*)(pbBuffer + dwMinSize) + cServiceName;
  199. }
  200. dwMinSize += ( cServiceName + cDisplayName ) * sizeof(TCHAR);
  201. }
  202. if ( dwBufferSize < dwMinSize )
  203. {
  204. *pdwMDRequiredBufferSize = dwMinSize;
  205. hresReturn = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
  206. }
  207. return hresReturn;
  208. }
  209. HRESULT
  210. SetEnableRemote(
  211. DWORD dwValue
  212. )
  213. /*++
  214. SetEnableRemote
  215. set restart I/F enabled flag in registry
  216. ( HKLM\SOFTWARE\Microsoft\INetStp::EnableRestart::REG_DWORD )
  217. Arguments:
  218. dwValue - 0 to disable I/F, !0 to enable
  219. Returns:
  220. status
  221. --*/
  222. {
  223. DWORD dwSt = NO_ERROR;
  224. HKEY hKey;
  225. //
  226. // Check admin privilege by accessing IISADMIN key for write
  227. //
  228. if ( ( dwSt = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  229. TEXT("SYSTEM\\CurrentControlSet\\Services\\IISADMIN"),
  230. 0,
  231. KEY_WRITE,
  232. &hKey ) ) == ERROR_SUCCESS )
  233. {
  234. RegCloseKey( hKey );
  235. //
  236. // Set IISCTL interface access flag in registry
  237. //
  238. if ( ( dwSt = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  239. TEXT("SOFTWARE\\Microsoft\\INetStp"),
  240. 0,
  241. KEY_WRITE,
  242. &hKey ) ) == ERROR_SUCCESS )
  243. {
  244. if ( ( dwSt = RegSetValueEx( hKey,
  245. TEXT("EnableRestart"),
  246. 0,
  247. REG_DWORD,
  248. (const BYTE*)&dwValue,
  249. sizeof(DWORD) ) ) == ERROR_SUCCESS )
  250. {
  251. }
  252. RegCloseKey( hKey );
  253. }
  254. }
  255. return HRESULT_FROM_WIN32( dwSt );
  256. }
  257. BOOL
  258. GetNumeric(
  259. LPSTR pszNumArg,
  260. LPDWORD pdwVal
  261. )
  262. {
  263. // protect against being called wrong.
  264. if ( pszNumArg == NULL ||
  265. pdwVal == NULL )
  266. {
  267. return FALSE;
  268. }
  269. if ( !isdigit( (UCHAR)(*pszNumArg) ) )
  270. {
  271. return FALSE;
  272. }
  273. *pdwVal = atoi( pszNumArg );
  274. return TRUE;
  275. }
  276. BOOL
  277. IsIIS6orGreater(
  278. )
  279. /*++
  280. IsIIS6orGreater
  281. According to Aaron we are guaranteed to have
  282. the appropriate keys in the registry by the
  283. time iisreset /scm is called.
  284. Arguments:
  285. None
  286. Returns:
  287. TRUE = IIS 6 or greater;
  288. FALSE = anything below IIS 6;
  289. --*/
  290. {
  291. // Assume it is not IIS 6.
  292. BOOL IsIIS6 = FALSE;
  293. HKEY hKey;
  294. DWORD dwValue;
  295. DWORD dwType;
  296. DWORD dwSize;
  297. // Check the registry of the major version setup number.
  298. // If it is not there we assume it is not a 6.0 machine,
  299. // since it's better to setup a 6.0 machine in 5.0 state
  300. // instead of a 5.0 machine in 6.0 state.
  301. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  302. TEXT("System\\CurrentControlSet\\Services\\W3SVC\\Parameters"),
  303. 0,
  304. KEY_READ,
  305. &hKey ) == ERROR_SUCCESS )
  306. {
  307. if ( RegQueryValueEx( hKey,
  308. TEXT("MajorVersion"),
  309. 0,
  310. &dwType,
  311. (LPBYTE)&dwValue,
  312. &dwSize ) == ERROR_SUCCESS )
  313. {
  314. if ( dwType == REG_DWORD )
  315. {
  316. if ( dwValue >= 6 )
  317. {
  318. // were are running on a system that does not
  319. // have atleast IIS 6 on it
  320. IsIIS6 = TRUE;
  321. }
  322. }
  323. }
  324. RegCloseKey( hKey );
  325. }
  326. return IsIIS6;
  327. }
  328. HRESULT
  329. SetSCM(
  330. BOOL fEnable
  331. )
  332. /*++
  333. SetSCM
  334. set SCM Recovery configuration for IISADMIN service.
  335. Does nothing on pre Windows 2000 systems.
  336. Arguments:
  337. fEnable - TRUE to enable IISRESET invocation on service failure, FALSE to disable
  338. Returns:
  339. status
  340. --*/
  341. {
  342. PFNCHANGESERVICECONFIG2 pfnChangeServiceConfig2 = NULL;
  343. SERVICE_FAILURE_ACTIONS sfaAction;
  344. SC_ACTION saCmdline[3];
  345. SC_HANDLE schSCM;
  346. SC_HANDLE schSrv;
  347. HRESULT hres = S_OK;
  348. TCHAR achModuleName[MAX_PATH];
  349. TCHAR achFailureCommand[MAX_PATH+32];
  350. HINSTANCE hAdvapi;
  351. hAdvapi = LoadLibrary(_T("ADVAPI32.DLL"));
  352. if ( hAdvapi != NULL )
  353. {
  354. pfnChangeServiceConfig2 = (PFNCHANGESERVICECONFIG2)GetProcAddress( hAdvapi, "ChangeServiceConfig2W" );
  355. }
  356. if ( pfnChangeServiceConfig2 )
  357. {
  358. if ( !GetModuleFileName( NULL,
  359. achModuleName,
  360. sizeof(achModuleName)/sizeof(TCHAR) ) )
  361. {
  362. hres = HRESULT_FROM_WIN32( GetLastError() );
  363. }
  364. if ( SUCCEEDED( hres ) )
  365. {
  366. schSCM = OpenSCManager(NULL,
  367. NULL,
  368. SC_MANAGER_CONNECT);
  369. if ( schSCM == NULL )
  370. {
  371. hres = HRESULT_FROM_WIN32( GetLastError() );
  372. }
  373. else
  374. {
  375. // We need to determine what IIS version we are running on
  376. // in order to know the correct way to setup the server.
  377. BOOL fIIS6orGreater = IsIIS6orGreater();
  378. //
  379. // In IIS 5.1 we want to use the default /restart
  380. // setting of iisreset. In IIS 6 or greater we
  381. // want to use the /start option. A customer
  382. // can configure it to use the /restart option, but
  383. // that is not the default for the scm.
  384. //
  385. if ( fIIS6orGreater )
  386. {
  387. //achModuleName is MAX_PATH size, the rest of the string is less than 32 characters.
  388. wsprintf( achFailureCommand, _T("\"%s\" /start /fail=%%1%%"), achModuleName );
  389. }
  390. else
  391. {
  392. //achModuleName is MAX_PATH size, the rest of the string is less than 32 characters.
  393. wsprintf( achFailureCommand, _T("\"%s\" /fail=%%1%%"), achModuleName );
  394. }
  395. sfaAction.lpCommand = achFailureCommand;
  396. sfaAction.lpRebootMsg = _T("");
  397. sfaAction.dwResetPeriod = 24 * 60 * 60;
  398. if ( fEnable )
  399. {
  400. sfaAction.cActions = 3;
  401. sfaAction.lpsaActions = saCmdline;
  402. saCmdline[0].Type = SC_ACTION_RUN_COMMAND;
  403. saCmdline[0].Delay = 1;
  404. saCmdline[1].Type = SC_ACTION_RUN_COMMAND;
  405. saCmdline[1].Delay = 1;
  406. saCmdline[2].Type = SC_ACTION_RUN_COMMAND;
  407. saCmdline[2].Delay = 1;
  408. }
  409. else
  410. {
  411. sfaAction.cActions = 3;
  412. sfaAction.lpsaActions = saCmdline;
  413. saCmdline[0].Type = SC_ACTION_NONE;
  414. saCmdline[0].Delay = 0;
  415. saCmdline[1].Type = SC_ACTION_NONE;
  416. saCmdline[1].Delay = 0;
  417. saCmdline[2].Type = SC_ACTION_NONE;
  418. saCmdline[2].Delay = 0;
  419. }
  420. schSrv = OpenService( schSCM,
  421. _T("IISADMIN"),
  422. SERVICE_CHANGE_CONFIG);
  423. if ( schSrv )
  424. {
  425. if ( !pfnChangeServiceConfig2( schSrv,
  426. SERVICE_CONFIG_FAILURE_ACTIONS,
  427. &sfaAction ) )
  428. {
  429. hres = HRESULT_FROM_WIN32( GetLastError() );
  430. }
  431. CloseServiceHandle( schSrv );
  432. }
  433. else
  434. {
  435. hres = HRESULT_FROM_WIN32( GetLastError() );
  436. }
  437. //
  438. // Now that we have configured IISAdmin correctly, we also need to
  439. // configure W3SVC.
  440. //
  441. if ( fIIS6orGreater )
  442. {
  443. sfaAction.lpCommand = NULL;
  444. sfaAction.lpRebootMsg = _T("");
  445. sfaAction.dwResetPeriod = 24 * 60 * 60;
  446. if ( fEnable )
  447. {
  448. sfaAction.cActions = 3;
  449. sfaAction.lpsaActions = saCmdline;
  450. saCmdline[0].Type = SC_ACTION_RESTART;
  451. saCmdline[0].Delay = 1;
  452. saCmdline[1].Type = SC_ACTION_RESTART;
  453. saCmdline[1].Delay = 1;
  454. saCmdline[2].Type = SC_ACTION_RESTART;
  455. saCmdline[2].Delay = 1;
  456. }
  457. else
  458. {
  459. sfaAction.cActions = 3;
  460. sfaAction.lpsaActions = saCmdline;
  461. saCmdline[0].Type = SC_ACTION_NONE;
  462. saCmdline[0].Delay = 0;
  463. saCmdline[1].Type = SC_ACTION_NONE;
  464. saCmdline[1].Delay = 0;
  465. saCmdline[2].Type = SC_ACTION_NONE;
  466. saCmdline[2].Delay = 0;
  467. }
  468. schSrv = OpenService( schSCM,
  469. _T("W3SVC"),
  470. SERVICE_CHANGE_CONFIG |
  471. SERVICE_START);
  472. if ( schSrv )
  473. {
  474. if ( !pfnChangeServiceConfig2( schSrv,
  475. SERVICE_CONFIG_FAILURE_ACTIONS,
  476. &sfaAction ) )
  477. {
  478. hres = HRESULT_FROM_WIN32( GetLastError() );
  479. }
  480. CloseServiceHandle( schSrv );
  481. }
  482. else
  483. {
  484. hres = HRESULT_FROM_WIN32( GetLastError() );
  485. }
  486. } // end of setting up restart on w3svc.
  487. CloseServiceHandle( schSCM );
  488. }
  489. }
  490. }
  491. if ( hAdvapi )
  492. {
  493. FreeLibrary( hAdvapi );
  494. }
  495. return hres;
  496. }
  497. enum CMDS { CMD_NONE, CMD_START, CMD_STOP, CMD_REBOOT, CMD_RESTART, CMD_KILL };
  498. // We use lstrcmpiA to compare arguments typed in with our cmd options
  499. // on foreign code pages case insensitivity can be missed, but since we
  500. // are comparing against the english letters, and don't use foreign letters
  501. // I believe this will be ok.
  502. #pragma prefast(push)
  503. #pragma prefast(disable:400, "Don't complain about using lstrcmpiA")
  504. int __cdecl
  505. main(
  506. int argc,
  507. char*argv[]
  508. )
  509. /*++
  510. main
  511. main function
  512. Arguments:
  513. argc
  514. argv
  515. Returns:
  516. 0 if no error, otherwise error code
  517. --*/
  518. {
  519. IIisServiceControl* pIf;
  520. int iA;
  521. int Status = 0;
  522. HRESULT hRes;
  523. CMDS iCmd = CMD_NONE;
  524. DWORD dwStopTimeout = 60 * 1000;
  525. DWORD dwRestartTimeout = 20 * 1000;
  526. DWORD dwStartTimeout = 60 * 1000;
  527. LPBYTE pbBuffer = NULL;
  528. BYTE abBuffer[4096];
  529. LPBYTE pbOutBuffer = NULL;
  530. BYTE abOutBuffer[4096];
  531. DWORD dwRequired;
  532. DWORD dwNumServices;
  533. LPVOID apvParams[8];
  534. UINT i;
  535. BOOL fNoCmd = FALSE;
  536. BOOL fRebootOnError = FALSE;
  537. BOOL fKillOnError = TRUE;
  538. BOOL fForce = TRUE;
  539. BOOL fRebootRestart = FALSE;
  540. BOOL fStatus = FALSE;
  541. COSERVERINFO csiMachineName;
  542. MULTI_QI rgmq;
  543. WCHAR awchComputer[64];
  544. LPSTR pszMachineName = NULL;
  545. BOOL fErrDisplayed = FALSE;
  546. DWORD dwFailCount;
  547. ULONG CodePage = 0;
  548. TCHAR CodePageString[MAX_STRINGIZED_ULONG_CHAR_COUNT + 1];
  549. //
  550. // Make sure international versions display text ok - RonaldM
  551. //
  552. _tsetlocale( LC_ALL, _T(".OCP") );
  553. // in order to get output working when the user code page
  554. // does not match the system code page or the system installed language
  555. // we have added the following lines, thru the second _tsetlocale.
  556. // this was recommended by Rostislav Shabalin. It was also recommended
  557. // to keep the original _tsetlocale because it may be setting configuration
  558. // that will not get changed in the second _tsetlocal call.
  559. // See RAID Windows Bugs #712030 for more info.
  560. CodePage = GetConsoleOutputCP();
  561. CodePageString[0] = _T('.');
  562. _ultot(CodePage, &(CodePageString[1]), 10 );
  563. _tsetlocale( LC_ALL, CodePageString );
  564. // Per issue: 439690 we need to make this call to make sure
  565. // that localized builds work correctly in all cases.
  566. SetThreadUILanguage(0);
  567. _fputts( _T("\n"), stdout );
  568. //
  569. // scan command line
  570. //
  571. for ( iA = 1 ;
  572. iA < argc ;
  573. ++iA )
  574. {
  575. if ( argv[iA][0] == '-' || argv[iA][0] == '/' )
  576. {
  577. if ( !lstrcmpiA( argv[iA]+1, "ENABLE" ) )
  578. {
  579. hRes = SetEnableRemote( 1 );
  580. if ( FAILED( hRes ) )
  581. {
  582. if ( hRes == HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) )
  583. {
  584. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  585. }
  586. else
  587. {
  588. DisplayErrorMessage( WIN32_FROM_HRESULT( hRes ) );
  589. }
  590. Status = WIN32_FROM_HRESULT( hRes );
  591. }
  592. else
  593. {
  594. PrintMessage( IRSTASTR_ENABLED, 0, NULL );
  595. }
  596. fNoCmd = TRUE;
  597. }
  598. else if ( !lstrcmpiA( argv[iA]+1, "DISABLE" ) )
  599. {
  600. hRes = SetEnableRemote( 0 );
  601. if ( FAILED( hRes ) )
  602. {
  603. if ( hRes == HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) )
  604. {
  605. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  606. }
  607. else
  608. {
  609. DisplayErrorMessage( WIN32_FROM_HRESULT( hRes ) );
  610. }
  611. Status = WIN32_FROM_HRESULT( hRes );
  612. }
  613. else
  614. {
  615. PrintMessage( IRSTASTR_DISABLED, 0, NULL );
  616. }
  617. fNoCmd = TRUE;
  618. }
  619. else if ( !_strnicmp( argv[iA]+1, "SCM", sizeof("SCM")-1 ) )
  620. {
  621. if ( FAILED( hRes = SetSCM( TRUE ) ) )
  622. {
  623. DisplayErrorMessage( WIN32_FROM_HRESULT( hRes ) );
  624. Status = WIN32_FROM_HRESULT( hRes );
  625. }
  626. goto Exit;
  627. }
  628. else if ( !_strnicmp( argv[iA]+1, "NOSCM", sizeof("NOSCM")-1 ) )
  629. {
  630. if ( FAILED( hRes = SetSCM( FALSE ) ) )
  631. {
  632. DisplayErrorMessage( WIN32_FROM_HRESULT( hRes ) );
  633. Status = WIN32_FROM_HRESULT( hRes );
  634. }
  635. goto Exit;
  636. }
  637. else if ( !_strnicmp( argv[iA]+1, "STOPTIMEOUT:", sizeof("STOPTIMEOUT:")-1 ) )
  638. {
  639. if ( !GetNumeric( argv[iA]+ 1 + sizeof("STOPTIMEOUT:") - 1, &dwStopTimeout ) )
  640. {
  641. goto invalid_param;
  642. }
  643. dwStopTimeout *= 1000;
  644. }
  645. else if ( !_strnicmp( argv[iA]+1, "TIMEOUT:", sizeof("TIMEOUT:")-1 ) )
  646. {
  647. if ( !GetNumeric( argv[iA]+ 1 + sizeof("TIMEOUT:") - 1, &dwStopTimeout ) )
  648. {
  649. goto invalid_param;
  650. }
  651. dwStopTimeout *= 1000;
  652. dwRestartTimeout = dwStopTimeout;
  653. }
  654. else if ( !_strnicmp( argv[iA]+1, "STARTTIMEOUT:", sizeof("STARTTIMEOUT:")-1 ) )
  655. {
  656. if ( !GetNumeric( argv[iA]+ 1 + sizeof("STARTTIMEOUT:") - 1, &dwStartTimeout ) )
  657. {
  658. goto invalid_param;
  659. }
  660. dwStartTimeout *= 1000;
  661. }
  662. else if ( !_strnicmp( argv[iA]+1, "RESTARTTIMEOUT:", sizeof("RESTARTTIMEOUT:")-1 ) )
  663. {
  664. if ( !GetNumeric( argv[iA]+ 1 + sizeof("RESTARTTIMEOUT:") - 1, &dwRestartTimeout ) )
  665. {
  666. goto invalid_param;
  667. }
  668. dwRestartTimeout *= 1000;
  669. }
  670. else if ( !_strnicmp( argv[iA]+1, "fail=", sizeof("fail=")-1 ) )
  671. {
  672. //
  673. // SCM flag to control restart threshold. We restart only
  674. // 50 times per SCM restart period.
  675. //
  676. // ... The SCM UI already has a way to address this: they add
  677. // a "/fail=N" parameter to the command line
  678. // of the restarter app for each time they fail within the time
  679. // period and leave it up to the restarter app to interpret
  680. // this parameter and throttle restarts approprately.
  681. // So...(here's the change request) we need to capture this
  682. // value, and if "N" is greater than our limit for 1 day of
  683. // restarting (hardcoded to 50), we should just exit the
  684. // command line app with a success code without doing anything,
  685. // i.e. "IISRESET.EXE /fail=50" should restart IIS,
  686. // but "IISRESET.EXE /fail=51" should be a no-op.
  687. // For simplicity, we should hardcode this value of 50 in
  688. // our app-- if a user wants a different value, he can write
  689. // a batch file wrapper to do it! You can see
  690. // the SCM recovery tab for more info.
  691. //
  692. dwFailCount = atoi( argv[iA]+ 1 + sizeof("fail=") - 1 );
  693. if ( dwFailCount > 50 )
  694. {
  695. return 0;
  696. }
  697. }
  698. else if ( !lstrcmpiA( argv[iA]+1, "START" ) )
  699. {
  700. if ( fRebootRestart )
  701. {
  702. }
  703. else if ( iCmd == CMD_STOP )
  704. {
  705. iCmd = CMD_RESTART;
  706. }
  707. else
  708. {
  709. iCmd = CMD_START;
  710. }
  711. }
  712. else if ( !lstrcmpiA( argv[iA]+1, "STOP" ) )
  713. {
  714. if ( fRebootRestart )
  715. {
  716. }
  717. if ( iCmd == CMD_START )
  718. {
  719. iCmd = CMD_RESTART;
  720. }
  721. else
  722. {
  723. iCmd = CMD_STOP;
  724. }
  725. }
  726. else if ( !lstrcmpiA( argv[iA]+1, "REBOOT" ) )
  727. {
  728. iCmd = CMD_REBOOT;
  729. fRebootRestart = TRUE;
  730. }
  731. else if ( !lstrcmpiA( argv[iA]+1, "KILL" ) )
  732. {
  733. iCmd = CMD_KILL;
  734. fRebootRestart = TRUE;
  735. }
  736. else if ( !lstrcmpiA( argv[iA]+1, "RESTART" ) )
  737. {
  738. iCmd = CMD_RESTART;
  739. fRebootRestart = TRUE;
  740. }
  741. else if ( !lstrcmpiA( argv[iA]+1, "STATUS" ) )
  742. {
  743. fStatus = TRUE;
  744. }
  745. else if ( !lstrcmpiA( argv[iA]+1, "REBOOTONERROR" ) )
  746. {
  747. fRebootOnError = TRUE;
  748. fKillOnError = FALSE;
  749. }
  750. else if ( !lstrcmpiA( argv[iA]+1, "NOFORCE" ) )
  751. {
  752. fKillOnError = FALSE;
  753. fForce = FALSE;
  754. }
  755. else if ( !lstrcmpiA( argv[iA]+1, "HELP" ) )
  756. {
  757. PrintMessage( IRSTASTR_USAGE, 0, NULL );
  758. return 0;
  759. }
  760. else
  761. {
  762. invalid_param:
  763. PrintMessage( IRSTASTR_USAGE, 0, NULL );
  764. return ERROR_INVALID_PARAMETER;
  765. }
  766. }
  767. else
  768. {
  769. pszMachineName = argv[iA];
  770. }
  771. }
  772. if ( iCmd == CMD_NONE && !fNoCmd && !fStatus )
  773. {
  774. iCmd = CMD_RESTART;
  775. }
  776. //
  777. //fill the structure for CoCreateInstanceEx
  778. //
  779. ZeroMemory( &csiMachineName, sizeof(csiMachineName) );
  780. if ( pszMachineName )
  781. {
  782. if ( !MultiByteToWideChar( CP_ACP,
  783. MB_PRECOMPOSED,
  784. pszMachineName,
  785. -1, // process whole string including null terminator
  786. awchComputer,
  787. sizeof(awchComputer) / sizeof(WCHAR)) )
  788. {
  789. return GetLastError();
  790. }
  791. csiMachineName.pwszName = awchComputer;
  792. }
  793. else
  794. {
  795. csiMachineName.pwszName = NULL;
  796. }
  797. if ( fNoCmd )
  798. {
  799. iCmd = CMD_NONE;
  800. fStatus = FALSE;
  801. }
  802. if ( iCmd != CMD_NONE || fStatus )
  803. {
  804. BOOL fCoInitialized = true;
  805. //
  806. // call method
  807. //
  808. rgmq.pIID = &IID_IIisServiceControl;
  809. rgmq.pItf = NULL;
  810. rgmq.hr = 0;
  811. if (FAILED(hRes = CoInitializeEx( NULL, COINIT_MULTITHREADED ))) {
  812. fCoInitialized = false;
  813. }
  814. else if ( SUCCEEDED( hRes = CoCreateInstanceEx( CLSID_IisServiceControl,
  815. NULL,
  816. CLSCTX_SERVER,
  817. &csiMachineName,
  818. 1,
  819. &rgmq ) ) &&
  820. SUCCEEDED( hRes = rgmq.hr ) )
  821. {
  822. pIf = (IIisServiceControl*)rgmq.pItf;
  823. switch ( iCmd )
  824. {
  825. case CMD_START:
  826. PrintMessage( IRSTASTR_START_ATTEMPT, 0, NULL );
  827. hRes = pIf->Start( dwStartTimeout );
  828. if ( SUCCEEDED( hRes ) )
  829. {
  830. PrintMessage( IRSTASTR_START_SUCCESS, 0, NULL );
  831. }
  832. else
  833. {
  834. CmdError( IRSTASTR_START_FAILED, hRes );
  835. fErrDisplayed = TRUE;
  836. }
  837. break;
  838. case CMD_STOP:
  839. PrintMessage( IRSTASTR_STOP_ATTEMPT, 0, NULL );
  840. hRes = pIf->Stop( dwStopTimeout, fKillOnError );
  841. if ( SUCCEEDED( hRes ) )
  842. {
  843. PrintMessage( IRSTASTR_STOP_SUCCESS, 0, NULL );
  844. }
  845. else
  846. {
  847. CmdError( IRSTASTR_STOP_FAILED, hRes );
  848. fErrDisplayed = TRUE;
  849. }
  850. break;
  851. case CMD_REBOOT:
  852. PrintMessage( IRSTASTR_REBOOT_ATTEMPT, 0, NULL );
  853. hRes = pIf->Reboot( dwRestartTimeout, fForce );
  854. if ( SUCCEEDED( hRes ) )
  855. {
  856. PrintMessage( IRSTASTR_REBOOT_SUCCESS, 0, NULL );
  857. }
  858. else
  859. {
  860. CmdError( IRSTASTR_REBOOT_FAILED, hRes );
  861. fErrDisplayed = TRUE;
  862. }
  863. break;
  864. case CMD_KILL:
  865. PrintMessage( IRSTASTR_KILL_ON_ERROR, 0, NULL );
  866. hRes = pIf->Kill();
  867. if ( SUCCEEDED( hRes ) )
  868. {
  869. PrintMessage( IRSTASTR_KILL_SUCCESS, 0, NULL );
  870. }
  871. else
  872. {
  873. CmdError( IRSTASTR_KILL_FAILED, hRes );
  874. fErrDisplayed = TRUE;
  875. }
  876. break;
  877. case CMD_RESTART:
  878. PrintMessage( IRSTASTR_STOP_ATTEMPT, 0, NULL );
  879. hRes = pIf->Stop( dwRestartTimeout, fKillOnError );
  880. if ( SUCCEEDED( hRes ) )
  881. {
  882. PrintMessage( IRSTASTR_STOP_SUCCESS, 0, NULL );
  883. PrintMessage( IRSTASTR_START_ATTEMPT, 0, NULL );
  884. hRes = pIf->Start( dwStartTimeout );
  885. if ( SUCCEEDED( hRes ) )
  886. {
  887. PrintMessage( IRSTASTR_RESTART_SUCCESS, 0, NULL );
  888. }
  889. }
  890. if ( FAILED( hRes ) )
  891. {
  892. CmdError( IRSTASTR_RESTART_FAILED, hRes );
  893. fErrDisplayed = TRUE;
  894. }
  895. break;
  896. }
  897. if ( fStatus )
  898. {
  899. pbBuffer = NULL;
  900. fErrDisplayed = FALSE;
  901. if ( FAILED( hRes = pIf->Status( sizeof(abBuffer),
  902. abBuffer,
  903. &dwRequired,
  904. &dwNumServices ) ) )
  905. {
  906. if ( HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) == hRes )
  907. {
  908. if ( (pbBuffer = (LPBYTE)LocalAlloc( LMEM_FIXED, dwRequired )) == NULL )
  909. {
  910. hRes = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  911. }
  912. else
  913. {
  914. hRes = pIf->Status( dwRequired,
  915. pbBuffer,
  916. &dwRequired,
  917. &dwNumServices );
  918. }
  919. }
  920. }
  921. else
  922. {
  923. pbBuffer = abBuffer;
  924. }
  925. if ( SUCCEEDED( hRes ) )
  926. {
  927. pbOutBuffer = NULL;
  928. if ( FAILED( hRes = DeserializeEnumServiceBuffer( pbBuffer,
  929. dwNumServices,
  930. abOutBuffer,
  931. sizeof(abOutBuffer),
  932. &dwRequired ) ) )
  933. {
  934. if ( HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) == hRes )
  935. {
  936. if ( (pbOutBuffer = (LPBYTE)LocalAlloc( LMEM_FIXED, dwRequired )) == NULL )
  937. {
  938. hRes = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  939. }
  940. else
  941. {
  942. hRes = DeserializeEnumServiceBuffer( pbBuffer,
  943. dwNumServices,
  944. pbOutBuffer,
  945. dwRequired,
  946. &dwRequired );
  947. }
  948. }
  949. }
  950. else
  951. {
  952. pbOutBuffer = abOutBuffer;
  953. }
  954. }
  955. if ( SUCCEEDED( hRes ) )
  956. {
  957. for ( i = 0 ; i < dwNumServices ; ++i )
  958. {
  959. apvParams[0] = ((LPENUM_SERVICE_STATUS)pbOutBuffer)[i].lpDisplayName;
  960. apvParams[1] = ((LPENUM_SERVICE_STATUS)pbOutBuffer)[i].lpServiceName;
  961. switch ( ((LPENUM_SERVICE_STATUS)pbOutBuffer)[i].ServiceStatus.dwCurrentState )
  962. {
  963. case SERVICE_STOPPED:
  964. apvParams[2] = GetString(IRSTASTR_SERVICE_STOPPED); break;
  965. case SERVICE_START_PENDING:
  966. apvParams[2] = GetString(IRSTASTR_SERVICE_START_PENDING); break;
  967. case SERVICE_STOP_PENDING:
  968. apvParams[2] = GetString(IRSTASTR_SERVICE_STOP_PENDING); break;
  969. case SERVICE_RUNNING:
  970. apvParams[2] = GetString(IRSTASTR_SERVICE_RUNNING); break;
  971. case SERVICE_CONTINUE_PENDING:
  972. apvParams[2] = GetString(IRSTASTR_SERVICE_CONTINUE_PENDING); break;
  973. case SERVICE_PAUSE_PENDING:
  974. apvParams[2] = GetString(IRSTASTR_SERVICE_PAUSE_PENDING); break;
  975. case SERVICE_PAUSED:
  976. apvParams[2] = GetString(IRSTASTR_SERVICE_PAUSED); break;
  977. default:
  978. apvParams[2] = GetString(IRSTASTR_SERVICE_DEFAULT); break;
  979. }
  980. PrintMessage( IRSTASTR_STATUS_ITEM, 3, apvParams );
  981. }
  982. }
  983. if ( pbBuffer != NULL && pbBuffer != abBuffer )
  984. {
  985. LocalFree( pbBuffer );
  986. }
  987. if ( pbOutBuffer != NULL && pbOutBuffer != abOutBuffer )
  988. {
  989. LocalFree( pbOutBuffer );
  990. }
  991. }
  992. if ( FAILED( hRes ) && fRebootOnError
  993. && ( iCmd == CMD_STOP || iCmd == CMD_RESTART ) )
  994. {
  995. fErrDisplayed = FALSE;
  996. PrintMessage( IRSTASTR_REBOOT_ON_ERROR, 0, NULL );
  997. hRes = pIf->Reboot( 0, fForce );
  998. if ( SUCCEEDED( hRes ) )
  999. {
  1000. PrintMessage( IRSTASTR_REBOOT_SUCCESS, 0, NULL );
  1001. }
  1002. }
  1003. pIf->Release();
  1004. if ( FAILED( hRes ) )
  1005. {
  1006. if ( !fErrDisplayed )
  1007. {
  1008. if ( hRes == HRESULT_FROM_WIN32( ERROR_RESOURCE_DISABLED ) )
  1009. {
  1010. PrintMessage( IRSTASTR_REMOTE_DISABLED, 0, NULL );
  1011. }
  1012. else if ( hRes == HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) )
  1013. {
  1014. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  1015. }
  1016. else
  1017. {
  1018. DisplayErrorMessage( WIN32_FROM_HRESULT( hRes ) );
  1019. }
  1020. }
  1021. Status = WIN32_FROM_HRESULT( hRes );
  1022. }
  1023. }
  1024. else
  1025. {
  1026. if ( hRes == HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) )
  1027. {
  1028. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  1029. }
  1030. else
  1031. {
  1032. DisplayErrorMessage( WIN32_FROM_HRESULT( hRes ) );
  1033. }
  1034. Status = WIN32_FROM_HRESULT( hRes );
  1035. }
  1036. if (fCoInitialized) {
  1037. CoUninitialize();
  1038. }
  1039. }
  1040. Exit:
  1041. return Status;
  1042. }
  1043. #pragma prefast(pop)