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.

2093 lines
55 KiB

  1. /*++
  2. Copyright (c) 1992-1999 Microsoft Corporation
  3. Module Name:
  4. gensvc.c
  5. Abstract:
  6. Resource DLL to control and monitor NT services.
  7. Author:
  8. Robs 3/28/96, based on RodGa's generic resource dll
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "clusres.h"
  13. #include "clusrtl.h"
  14. #include "svc.h"
  15. #include "localsvc.h"
  16. #include "wincrypt.h"
  17. #define DBG_PRINT printf
  18. typedef struct _COMMON_RESOURCE {
  19. #ifdef COMMON_PARAMS_DEFINED
  20. COMMON_PARAMS Params;
  21. #endif
  22. HRESOURCE hResource;
  23. HANDLE ServiceHandle;
  24. RESOURCE_HANDLE ResourceHandle;
  25. HKEY ResourceKey;
  26. HKEY ParametersKey;
  27. CLUS_WORKER PendingThread;
  28. BOOL Online;
  29. DWORD dwServicePid;
  30. } COMMON_RESOURCE, * PCOMMON_RESOURCE;
  31. //
  32. // Global Data
  33. //
  34. // Handle to service controller, set by the first create resource call.
  35. static SC_HANDLE g_ScHandle = NULL;
  36. // Log Event Routine
  37. #define g_LogEvent ClusResLogEvent
  38. #define g_SetResourceStatus ClusResSetResourceStatus
  39. #ifdef COMMON_SEMAPHORE
  40. static HANDLE CommonSemaphore;
  41. static PCOMMON_RESOURCE CommonResource;
  42. #endif
  43. #ifndef CRYPTO_VALUE_COUNT
  44. static DWORD CryptoSyncCount = 0;
  45. static LPWSTR CryptoSync[1] = {NULL};
  46. #endif
  47. #ifndef DOMESTIC_CRYPTO_VALUE_COUNT
  48. static DWORD DomesticCryptoSyncCount = 0;
  49. static LPWSTR DomesticCryptoSync[1] = {NULL};
  50. #endif
  51. //
  52. // Forward routines
  53. //
  54. static
  55. DWORD
  56. CommonOnlineThread(
  57. IN PCLUS_WORKER pWorker,
  58. IN PCOMMON_RESOURCE ResourceEntry
  59. );
  60. DWORD
  61. CommonOfflineThread(
  62. PCLUS_WORKER pWorker,
  63. IN PCOMMON_RESOURCE ResourceEntry
  64. );
  65. static
  66. BOOL
  67. CommonVerifyService(
  68. IN RESID ResourceId,
  69. IN BOOL IsAliveFlag
  70. );
  71. static
  72. DWORD
  73. SvcpTerminateServiceProcess(
  74. IN PCOMMON_RESOURCE pResourceEntry,
  75. IN BOOL bOffline,
  76. OUT PDWORD pdwResourceState
  77. );
  78. #ifdef COMMON_ONLINE_THREAD
  79. #define COMMON_ONLINE_THREAD_ROUTINE COMMON_ONLINE_THREAD
  80. #else
  81. #define COMMON_ONLINE_THREAD_ROUTINE CommonOnlineThread
  82. #endif
  83. //
  84. // Local Routines
  85. //
  86. #ifndef COMMON_ONLINE_THREAD
  87. static
  88. DWORD
  89. CommonOnlineThread(
  90. IN PCLUS_WORKER pWorker,
  91. IN PCOMMON_RESOURCE ResourceEntry
  92. )
  93. /*++
  94. Routine Description:
  95. Brings a disk resource online.
  96. Arguments:
  97. Worker - Supplies the worker structure
  98. ResourceEntry - A pointer to the resource entry for this resource.
  99. Returns:
  100. ERROR_SUCCESS if successful.
  101. Win32 error code on failure.
  102. --*/
  103. {
  104. SERVICE_STATUS_PROCESS ServiceStatus;
  105. DWORD status = ERROR_SUCCESS;
  106. RESOURCE_STATUS resourceStatus;
  107. DWORD valueSize;
  108. PVOID pvEnvironment = NULL;
  109. HKEY hkeyServicesKey;
  110. HKEY hkeyServiceName;
  111. DWORD cbBytesNeeded;
  112. DWORD prevCheckPoint = 0;
  113. DWORD idx;
  114. LPSERVICE_FAILURE_ACTIONS pSvcFailureActions = NULL;
  115. LPQUERY_SERVICE_CONFIG lpquerysvcconfig=NULL;
  116. RESOURCE_EXIT_STATE exitState;
  117. ResUtilInitializeResourceStatus( &resourceStatus );
  118. resourceStatus.ResourceState = ClusterResourceFailed;
  119. resourceStatus.CheckPoint = 1;
  120. if ( ResourceEntry != CommonResource ) {
  121. return(ERROR_SUCCESS);
  122. }
  123. //set it to NULL, when it is brought online and if the
  124. //service is not running in the system or lsa process
  125. //then store the process id for forced termination
  126. ResourceEntry->dwServicePid = 0;
  127. #if ENVIRONMENT
  128. //
  129. // Create the new environment with the simulated net name when the
  130. // services queries GetComputerName.
  131. //
  132. pvEnvironment = ResUtilGetEnvironmentWithNetName( ResourceEntry->hResource );
  133. if ( pvEnvironment != NULL ) {
  134. WCHAR * pszEnvString;
  135. //
  136. // Compute the size of the environment. We are looking for
  137. // the double NULL terminator that ends the environment block.
  138. //
  139. pszEnvString = (WCHAR *)pvEnvironment;
  140. while (*pszEnvString) {
  141. while (*pszEnvString++) {
  142. }
  143. }
  144. valueSize = (DWORD)((PUCHAR)pszEnvString - (PUCHAR)pvEnvironment) + sizeof(WCHAR);
  145. }
  146. //
  147. // Set the environment value in the service's registry key.
  148. //
  149. status = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  150. LOCAL_SERVICES,
  151. 0,
  152. KEY_READ,
  153. &hkeyServicesKey );
  154. if ( status != ERROR_SUCCESS ) {
  155. (g_LogEvent)(
  156. ResourceEntry->ResourceHandle,
  157. LOG_ERROR,
  158. L"Failed to open services key, error = %1!u!.\n",
  159. status );
  160. goto error_exit;
  161. }
  162. status = RegOpenKeyExW( hkeyServicesKey,
  163. SERVICE_NAME,
  164. 0,
  165. KEY_READ | KEY_WRITE,
  166. &hkeyServiceName );
  167. RegCloseKey( hkeyServicesKey );
  168. if ( status != ERROR_SUCCESS ) {
  169. (g_LogEvent)(
  170. ResourceEntry->ResourceHandle,
  171. LOG_ERROR,
  172. L"Failed to open service key, error = %1!u!.\n",
  173. status );
  174. goto error_exit;
  175. }
  176. status = RegSetValueExW( hkeyServiceName,
  177. L"Environment",
  178. 0,
  179. REG_MULTI_SZ,
  180. pvEnvironment,
  181. valueSize );
  182. RegCloseKey( hkeyServiceName );
  183. if ( status != ERROR_SUCCESS ) {
  184. (g_LogEvent)(
  185. ResourceEntry->ResourceHandle,
  186. LOG_ERROR,
  187. L"Failed to set service environment value, error = %1!u!.\n",
  188. status );
  189. goto error_exit;
  190. }
  191. #endif //ENVIRONMENT
  192. //
  193. // Now open the requested service
  194. //
  195. ResourceEntry->ServiceHandle = OpenService( g_ScHandle,
  196. SERVICE_NAME,
  197. SERVICE_ALL_ACCESS );
  198. if ( ResourceEntry->ServiceHandle == NULL ) {
  199. status = GetLastError();
  200. ClusResLogSystemEventByKeyData( ResourceEntry->ResourceKey,
  201. LOG_CRITICAL,
  202. RES_GENSVC_OPEN_FAILED,
  203. sizeof(status),
  204. &status );
  205. (g_LogEvent)(
  206. ResourceEntry->ResourceHandle,
  207. LOG_ERROR,
  208. L"Failed to open service, error = %1!u!.\n",
  209. status );
  210. goto error_exit;
  211. }
  212. valueSize = sizeof(QUERY_SERVICE_CONFIG);
  213. AllocSvcConfig:
  214. // Query the service to make sure it is not disabled
  215. lpquerysvcconfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc( LMEM_FIXED, valueSize );
  216. if ( lpquerysvcconfig == NULL ){
  217. status = GetLastError();
  218. (g_LogEvent)(
  219. ResourceEntry->ResourceHandle,
  220. LOG_ERROR,
  221. L"[Svc] Failed to allocate memory for query_service_config, error = %1!u!.\n",
  222. status );
  223. goto error_exit;
  224. }
  225. if ( ! QueryServiceConfig(
  226. ResourceEntry->ServiceHandle,
  227. lpquerysvcconfig,
  228. valueSize,
  229. &cbBytesNeeded ) )
  230. {
  231. status=GetLastError();
  232. if (status != ERROR_INSUFFICIENT_BUFFER){
  233. (g_LogEvent)(
  234. ResourceEntry->ResourceHandle,
  235. LOG_ERROR,
  236. L"svc: Failed to query service configuration, error= %1!u!.\n",
  237. status );
  238. goto error_exit;
  239. }
  240. status=ERROR_SUCCESS;
  241. LocalFree( lpquerysvcconfig );
  242. lpquerysvcconfig=NULL;
  243. valueSize = cbBytesNeeded;
  244. goto AllocSvcConfig;
  245. }
  246. if ( lpquerysvcconfig->dwStartType == SERVICE_DISABLED )
  247. {
  248. (g_LogEvent)(
  249. ResourceEntry->ResourceHandle,
  250. LOG_ERROR,
  251. L"svc:The service is DISABLED\n");
  252. status=ERROR_SERVICE_DISABLED;
  253. goto error_exit;
  254. }
  255. //
  256. // Make sure service is set to manual start.
  257. //
  258. ChangeServiceConfig( ResourceEntry->ServiceHandle,
  259. SERVICE_NO_CHANGE,
  260. SERVICE_DEMAND_START, // Manual start
  261. SERVICE_NO_CHANGE,
  262. NULL,
  263. NULL,
  264. NULL,
  265. NULL,
  266. NULL,
  267. NULL,
  268. NULL );
  269. // Use valuesize as the dummy buffer since the queryserviceconfig2
  270. // api is not that friendly.
  271. // If any of the service action is set to service restart, set it to
  272. // none
  273. if ( ! (QueryServiceConfig2(
  274. ResourceEntry->ServiceHandle,
  275. SERVICE_CONFIG_FAILURE_ACTIONS,
  276. (LPBYTE)&valueSize,
  277. sizeof(DWORD),
  278. &cbBytesNeeded )) )
  279. {
  280. status = GetLastError();
  281. if ( status != ERROR_INSUFFICIENT_BUFFER )
  282. {
  283. (g_LogEvent)(
  284. ResourceEntry->ResourceHandle,
  285. LOG_ERROR,
  286. L"svc: Failed to query service configuration for size, error= %1!u!.\n",
  287. status );
  288. goto error_exit;
  289. }
  290. else
  291. status = ERROR_SUCCESS;
  292. }
  293. pSvcFailureActions = (LPSERVICE_FAILURE_ACTIONS)LocalAlloc( LMEM_FIXED, cbBytesNeeded );
  294. if ( pSvcFailureActions == NULL ) {
  295. status = GetLastError();
  296. (g_LogEvent)(
  297. ResourceEntry->ResourceHandle,
  298. LOG_ERROR,
  299. L"Failed to allocate memory of size %1!u!, error = %2!u!.\n",
  300. cbBytesNeeded,
  301. status );
  302. goto error_exit;
  303. }
  304. if ( ! (QueryServiceConfig2(
  305. ResourceEntry->ServiceHandle,
  306. SERVICE_CONFIG_FAILURE_ACTIONS,
  307. (LPBYTE)pSvcFailureActions,
  308. cbBytesNeeded,
  309. &cbBytesNeeded )) )
  310. {
  311. status = GetLastError();
  312. (g_LogEvent)(
  313. ResourceEntry->ResourceHandle,
  314. LOG_ERROR,
  315. L"svc:Failed to query service configuration, error = %1!u!.\n",
  316. status );
  317. goto error_exit;
  318. }
  319. for ( idx=0; idx < pSvcFailureActions->cActions; idx++ )
  320. {
  321. if ( pSvcFailureActions->lpsaActions[idx].Type == SC_ACTION_RESTART ) {
  322. pSvcFailureActions->lpsaActions[idx].Type = SC_ACTION_NONE;
  323. }
  324. }
  325. ChangeServiceConfig2(
  326. ResourceEntry->ServiceHandle,
  327. SERVICE_CONFIG_FAILURE_ACTIONS,
  328. pSvcFailureActions );
  329. #ifdef COMMON_ONLINE_THREAD_CALLBACK
  330. //
  331. // Allow the resource DLL to perform some operations before the service
  332. // is started, such as setting registry keys, etc.
  333. //
  334. status = CommonOnlineThreadCallback( ResourceEntry );
  335. if ( status != ERROR_SUCCESS ) {
  336. goto error_exit;
  337. }
  338. #endif // COMMON_ONLINE_THREAD_CALLBACK
  339. if ( ! StartServiceW(
  340. ResourceEntry->ServiceHandle,
  341. 0,
  342. NULL ) ) {
  343. status = GetLastError();
  344. if (status != ERROR_SERVICE_ALREADY_RUNNING) {
  345. ClusResLogSystemEventByKeyData( ResourceEntry->ResourceKey,
  346. LOG_CRITICAL,
  347. RES_GENSVC_START_FAILED,
  348. sizeof(status),
  349. &status );
  350. (g_LogEvent)(ResourceEntry->ResourceHandle,
  351. LOG_ERROR,
  352. L"Failed to start %1!ws! service. Error: %2!u!.\n",
  353. SERVICE_NAME,
  354. status );
  355. goto error_exit;
  356. } else {
  357. status = ERROR_SUCCESS;
  358. }
  359. }
  360. resourceStatus.ResourceState = ClusterResourceOnlinePending;
  361. while ( ! ClusWorkerCheckTerminate( &ResourceEntry->PendingThread ) ) {
  362. if ( ! QueryServiceStatusEx(
  363. ResourceEntry->ServiceHandle,
  364. SC_STATUS_PROCESS_INFO,
  365. (LPBYTE)&ServiceStatus,
  366. sizeof(SERVICE_STATUS_PROCESS),
  367. &cbBytesNeeded ) ) {
  368. status = GetLastError();
  369. (g_LogEvent)(
  370. ResourceEntry->ResourceHandle,
  371. LOG_ERROR,
  372. L"Query Service Status failed %1!u!.\n",
  373. status );
  374. resourceStatus.ResourceState = ClusterResourceFailed;
  375. goto error_exit;
  376. }
  377. if ( ServiceStatus.dwCurrentState != SERVICE_START_PENDING ) {
  378. break;
  379. }
  380. if ( prevCheckPoint != ServiceStatus.dwCheckPoint ) {
  381. prevCheckPoint = ServiceStatus.dwCheckPoint;
  382. ++resourceStatus.CheckPoint;
  383. }
  384. exitState = (g_SetResourceStatus)(
  385. ResourceEntry->ResourceHandle,
  386. &resourceStatus );
  387. if ( exitState == ResourceExitStateTerminate ) {
  388. break;
  389. }
  390. Sleep( 500 ); // Sleep for 1/2 second
  391. }
  392. //
  393. // Assume that we failed.
  394. //
  395. resourceStatus.ResourceState = ClusterResourceFailed;
  396. //
  397. // If we exited the loop before setting ServiceStatus, then return now.
  398. //
  399. if ( ClusWorkerCheckTerminate( &ResourceEntry->PendingThread ) ) {
  400. goto error_exit;
  401. }
  402. if ( ServiceStatus.dwCurrentState != SERVICE_RUNNING ) {
  403. if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR ) {
  404. status = ServiceStatus.dwServiceSpecificExitCode;
  405. } else {
  406. status = ServiceStatus.dwWin32ExitCode;
  407. }
  408. ClusResLogSystemEventByKeyData(ResourceEntry->ResourceKey,
  409. LOG_CRITICAL,
  410. RES_GENSVC_FAILED_AFTER_START,
  411. sizeof(status),
  412. &status);
  413. (g_LogEvent)(
  414. ResourceEntry->ResourceHandle,
  415. LOG_ERROR,
  416. L"Service failed during initialization. Error: %1!u!.\n",
  417. status );
  418. goto error_exit;
  419. }
  420. resourceStatus.ResourceState = ClusterResourceOnline;
  421. if ( ! (ServiceStatus.dwServiceFlags & SERVICE_RUNS_IN_SYSTEM_PROCESS) ) {
  422. ResourceEntry->dwServicePid = ServiceStatus.dwProcessId;
  423. }
  424. (g_LogEvent)(
  425. ResourceEntry->ResourceHandle,
  426. LOG_INFORMATION,
  427. L"Service is now on line.\n" );
  428. error_exit:
  429. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  430. &resourceStatus );
  431. if ( resourceStatus.ResourceState == ClusterResourceOnline ) {
  432. ResourceEntry->Online = TRUE;
  433. } else {
  434. ResourceEntry->Online = FALSE;
  435. }
  436. if(lpquerysvcconfig)
  437. LocalFree(lpquerysvcconfig);
  438. if (pSvcFailureActions)
  439. LocalFree(pSvcFailureActions);
  440. #if ENVIRONMENT
  441. if ( pvEnvironment != NULL ) {
  442. RtlDestroyEnvironment( pvEnvironment );
  443. }
  444. #endif
  445. return(status);
  446. } // CommonOnlineThread
  447. #endif
  448. static
  449. RESID
  450. WINAPI
  451. CommonOpen(
  452. IN LPCWSTR ResourceName,
  453. IN HKEY ResourceKey,
  454. IN RESOURCE_HANDLE ResourceHandle
  455. )
  456. /*++
  457. Routine Description:
  458. Open routine for generic service resource.
  459. This routine gets a handle to the service controller, if we don't already have one,
  460. and then gets a handle to the specified service. The service handle is saved
  461. in the COMMON structure.
  462. Arguments:
  463. ResourceName - supplies the resource name
  464. ResourceKey - supplies a handle to the resource's cluster registry key
  465. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  466. is called.
  467. Return Value:
  468. RESID of created resource
  469. Zero on failure
  470. --*/
  471. {
  472. RESID svcResid = 0;
  473. DWORD status;
  474. HKEY parametersKey = NULL;
  475. HKEY resKey = NULL;
  476. PCOMMON_RESOURCE resourceEntry = NULL;
  477. DWORD paramNameSize = 0;
  478. DWORD paramNameMaxSize = 0;
  479. HCLUSTER hCluster;
  480. DWORD returnSize;
  481. DWORD idx;
  482. //
  483. // Open registry parameters key for this resource.
  484. //
  485. status = ClusterRegOpenKey( ResourceKey,
  486. L"Parameters",
  487. KEY_READ,
  488. &parametersKey );
  489. if ( status != NO_ERROR ) {
  490. (g_LogEvent)(
  491. ResourceHandle,
  492. LOG_ERROR,
  493. L"Unable to open parameters key. Error: %1!u!.\n",
  494. status);
  495. goto error_exit;
  496. }
  497. //
  498. // Get a handle to our resource key so that we can get our name later
  499. // if we need to log an event.
  500. //
  501. status = ClusterRegOpenKey( ResourceKey,
  502. L"",
  503. KEY_READ,
  504. &resKey );
  505. if ( status != ERROR_SUCCESS ) {
  506. (g_LogEvent)(ResourceHandle,
  507. LOG_ERROR,
  508. L"Unable to open resource key. Error: %1!u!.\n",
  509. status );
  510. goto error_exit;
  511. }
  512. //
  513. // First get a handle to the service controller.
  514. //
  515. if ( g_ScHandle == NULL ) {
  516. g_ScHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
  517. if ( g_ScHandle == NULL ) {
  518. status = GetLastError();
  519. (g_LogEvent)(
  520. ResourceHandle,
  521. LOG_ERROR,
  522. L"Failed to open service control manager, error = %1!u!.\n",
  523. status);
  524. goto error_exit;
  525. }
  526. }
  527. resourceEntry = LocalAlloc( LMEM_FIXED, sizeof(COMMON_RESOURCE) );
  528. if ( resourceEntry == NULL ) {
  529. (g_LogEvent)(
  530. ResourceHandle,
  531. LOG_ERROR,
  532. L"Failed to allocate a service info structure.\n");
  533. status = ERROR_NOT_ENOUGH_MEMORY;
  534. goto error_exit;
  535. }
  536. ZeroMemory( resourceEntry, sizeof(COMMON_RESOURCE) );
  537. resourceEntry->ResourceHandle = ResourceHandle;
  538. resourceEntry->ResourceKey = resKey;
  539. resourceEntry->ParametersKey = parametersKey;
  540. hCluster = OpenCluster(NULL);
  541. if ( hCluster == NULL ) {
  542. status = GetLastError();
  543. (g_LogEvent)(
  544. ResourceHandle,
  545. LOG_ERROR,
  546. L"Failed to open cluster, error %1!u!.\n",
  547. status );
  548. goto error_exit;
  549. }
  550. resourceEntry->hResource = OpenClusterResource( hCluster, ResourceName );
  551. status = GetLastError();
  552. CloseCluster( hCluster );
  553. if ( resourceEntry->hResource == NULL ) {
  554. (g_LogEvent)(
  555. ResourceHandle,
  556. LOG_ERROR,
  557. L"Failed to open resource, error %1!u!.\n",
  558. status );
  559. goto error_exit;
  560. }
  561. //
  562. // Set any registry checkpoints that we need.
  563. //
  564. if ( RegSyncCount != 0 ) {
  565. returnSize = 0;
  566. //
  567. // Set registry sync keys if we need them.
  568. //
  569. for ( idx = 0; idx < RegSyncCount; idx++ ) {
  570. status = ClusterResourceControl( resourceEntry->hResource,
  571. NULL,
  572. CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT,
  573. RegSync[idx],
  574. (lstrlenW( RegSync[idx] ) + 1) * sizeof(WCHAR),
  575. NULL,
  576. 0,
  577. &returnSize );
  578. if ( status != ERROR_SUCCESS ){
  579. if ( status == ERROR_ALREADY_EXISTS ){
  580. status = ERROR_SUCCESS;
  581. }
  582. else{
  583. (g_LogEvent)(
  584. resourceEntry->ResourceHandle,
  585. LOG_ERROR,
  586. L"Failed to set registry checkpoint, status %1!u!.\n",
  587. status );
  588. goto error_exit;
  589. }
  590. }
  591. }
  592. }
  593. //
  594. // Set any crypto checkpoints that we need.
  595. //
  596. if ( CryptoSyncCount != 0 ) {
  597. returnSize = 0;
  598. //
  599. // Set registry sync keys if we need them.
  600. //
  601. for ( idx = 0; idx < CryptoSyncCount; idx++ ) {
  602. status = ClusterResourceControl( resourceEntry->hResource,
  603. NULL,
  604. CLUSCTL_RESOURCE_ADD_CRYPTO_CHECKPOINT,
  605. CryptoSync[idx],
  606. (lstrlenW( CryptoSync[idx] ) + 1) * sizeof(WCHAR),
  607. NULL,
  608. 0,
  609. &returnSize );
  610. if ( status != ERROR_SUCCESS ){
  611. if (status == ERROR_ALREADY_EXISTS){
  612. status = ERROR_SUCCESS;
  613. }
  614. else{
  615. (g_LogEvent)(
  616. resourceEntry->ResourceHandle,
  617. LOG_ERROR,
  618. L"Failed to set crypto checkpoint, status %1!u!.\n",
  619. status );
  620. goto error_exit;
  621. }
  622. }
  623. }
  624. }
  625. //
  626. // Set any domestic crypto checkpoints that we need.
  627. //
  628. if ( DomesticCryptoSyncCount != 0 ) {
  629. HCRYPTPROV hProv = 0;
  630. //
  631. // check if domestic crypto is available
  632. //
  633. if (CryptAcquireContextA( &hProv,
  634. NULL,
  635. MS_ENHANCED_PROV_A,
  636. PROV_RSA_FULL,
  637. CRYPT_VERIFYCONTEXT)) {
  638. CryptReleaseContext( hProv, 0 );
  639. returnSize = 0;
  640. //
  641. // Set registry sync keys if we need them.
  642. //
  643. for ( idx = 0; idx < DomesticCryptoSyncCount; idx++ ) {
  644. status = ClusterResourceControl( resourceEntry->hResource,
  645. NULL,
  646. CLUSCTL_RESOURCE_ADD_CRYPTO_CHECKPOINT,
  647. DomesticCryptoSync[idx],
  648. (lstrlenW( DomesticCryptoSync[idx] ) + 1) * sizeof(WCHAR),
  649. NULL,
  650. 0,
  651. &returnSize );
  652. if ( status != ERROR_SUCCESS ){
  653. if (status == ERROR_ALREADY_EXISTS){
  654. status = ERROR_SUCCESS;
  655. }
  656. else{
  657. (g_LogEvent)(
  658. resourceEntry->ResourceHandle,
  659. LOG_ERROR,
  660. L"Failed to set domestic crypto checkpoint, status %1!u!.\n",
  661. status );
  662. goto error_exit;
  663. }
  664. }
  665. }
  666. }
  667. }
  668. #ifdef COMMON_PARAMS_DEFINED
  669. //
  670. // Get any parameters... so we can handle the GET_DEPENDENCIES request.
  671. //
  672. CommonReadParameters( resourceEntry );
  673. // ignore status return
  674. #endif // COMMON_PARAMS_DEFINED
  675. #ifdef COMMON_SEMAPHORE
  676. //
  677. // Check if more than one resource of this type.
  678. //
  679. if ( WaitForSingleObject( CommonSemaphore, 0 ) == WAIT_TIMEOUT ) {
  680. //
  681. // A version of this service is already running
  682. //
  683. (g_LogEvent)(
  684. ResourceHandle,
  685. LOG_ERROR,
  686. L"Service is already running.\n");
  687. status = ERROR_SERVICE_ALREADY_RUNNING;
  688. goto error_exit;
  689. }
  690. if ( CommonResource ) {
  691. (g_LogEvent)(
  692. ResourceHandle,
  693. LOG_ERROR,
  694. L"Service resource info non-null!\n");
  695. status = ERROR_DUPLICATE_SERVICE_NAME;
  696. goto error_exit;
  697. }
  698. CommonResource = resourceEntry;
  699. #endif // COMMON_SEMAPHORE
  700. svcResid = (RESID)resourceEntry;
  701. return(svcResid);
  702. error_exit:
  703. LocalFree( resourceEntry );
  704. if ( parametersKey != NULL ) {
  705. ClusterRegCloseKey( parametersKey );
  706. }
  707. if ( resKey != NULL) {
  708. ClusterRegCloseKey( resKey );
  709. }
  710. SetLastError( status );
  711. return((RESID)NULL);
  712. } // CommonOpen
  713. static
  714. DWORD
  715. WINAPI
  716. CommonOnline(
  717. IN RESID ResourceId,
  718. IN OUT PHANDLE EventHandle
  719. )
  720. /*++
  721. Routine Description:
  722. Online routine for Common Service resource.
  723. Arguments:
  724. ResourceId - Supplies resource id to be brought online
  725. EventHandle - Supplies a pointer to a handle to signal on error.
  726. Return Value:
  727. ERROR_SUCCESS if successful.
  728. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  729. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  730. acquire 'ownership'.
  731. Win32 error code if other failure.
  732. --*/
  733. {
  734. DWORD status;
  735. PCOMMON_RESOURCE resourceEntry;
  736. resourceEntry = (PCOMMON_RESOURCE)ResourceId;
  737. if ( resourceEntry != CommonResource ) {
  738. DBG_PRINT( "Common: Online request for wrong resource, 0x%p.\n",
  739. ResourceId );
  740. }
  741. if ( resourceEntry == NULL ) {
  742. DBG_PRINT( "Common: Online request for a nonexistent resource id 0x%p.\n",
  743. ResourceId );
  744. return(ERROR_RESOURCE_NOT_FOUND);
  745. }
  746. ClusWorkerTerminate( &resourceEntry->PendingThread );
  747. status = ClusWorkerCreate( &resourceEntry->PendingThread,
  748. COMMON_ONLINE_THREAD_ROUTINE,
  749. resourceEntry );
  750. if ( status == ERROR_SUCCESS ) {
  751. status = ERROR_IO_PENDING;
  752. }
  753. return(status);
  754. } // CommonOnline
  755. static
  756. VOID
  757. WINAPI
  758. CommonTerminate(
  759. IN RESID ResourceId
  760. )
  761. /*++
  762. Routine Description:
  763. Terminate routine for Common Service resource.
  764. Arguments:
  765. ResourceId - Supplies resource id to be terminated
  766. Return Value:
  767. None.
  768. --*/
  769. {
  770. SERVICE_STATUS ServiceStatus;
  771. PCOMMON_RESOURCE resourceEntry;
  772. resourceEntry = (PCOMMON_RESOURCE)ResourceId;
  773. if ( resourceEntry != CommonResource ) {
  774. DBG_PRINT( "Common: Offline request for wrong resource, 0x%p.\n",
  775. ResourceId );
  776. return;
  777. }
  778. if ( resourceEntry == NULL ) {
  779. DBG_PRINT( "Common: Offline request for a nonexistent resource id 0x%p.\n",
  780. ResourceId );
  781. return;
  782. }
  783. (g_LogEvent)(
  784. resourceEntry->ResourceHandle,
  785. LOG_INFORMATION,
  786. L"Offline request.\n" );
  787. ClusWorkerTerminate( &resourceEntry->PendingThread );
  788. if ( resourceEntry->ServiceHandle != NULL ) {
  789. DWORD retryTime = 30*1000; // wait 30 secs for shutdown
  790. DWORD retryTick = 300; // 300 msec at a time
  791. DWORD status;
  792. BOOL didStop = FALSE;
  793. for (;;) {
  794. status = (ControlService(
  795. resourceEntry->ServiceHandle,
  796. (didStop
  797. ? SERVICE_CONTROL_INTERROGATE
  798. : SERVICE_CONTROL_STOP),
  799. &ServiceStatus )
  800. ? NO_ERROR
  801. : GetLastError());
  802. if (status == NO_ERROR) {
  803. didStop = TRUE;
  804. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
  805. (g_LogEvent)(
  806. resourceEntry->ResourceHandle,
  807. LOG_INFORMATION,
  808. L"Service stopped.\n" );
  809. //set the status
  810. resourceEntry->Online = FALSE;
  811. resourceEntry->dwServicePid = 0;
  812. break;
  813. }
  814. }
  815. //
  816. // Chittur Subbaraman (chitturs) - 2/21/2000
  817. //
  818. // Since SCM doesn't accept any control requests during
  819. // windows shutdown, don't send any more control
  820. // requests. Just exit from this loop and terminate
  821. // the process brute force.
  822. //
  823. if (status == ERROR_SHUTDOWN_IN_PROGRESS)
  824. {
  825. (g_LogEvent)(
  826. resourceEntry->ResourceHandle,
  827. LOG_INFORMATION,
  828. L"System shutdown in progress. Will try to terminate the process...\n");
  829. break;
  830. }
  831. if (status == ERROR_EXCEPTION_IN_SERVICE ||
  832. status == ERROR_PROCESS_ABORTED ||
  833. status == ERROR_SERVICE_NOT_ACTIVE) {
  834. (g_LogEvent)(
  835. resourceEntry->ResourceHandle,
  836. LOG_INFORMATION,
  837. L"Service died; status = %1!u!.\n",
  838. status);
  839. //set the status
  840. resourceEntry->Online = FALSE;
  841. resourceEntry->dwServicePid = 0;
  842. break;
  843. }
  844. if ((retryTime -= retryTick) <= 0) {
  845. (g_LogEvent)(
  846. resourceEntry->ResourceHandle,
  847. LOG_ERROR,
  848. L"Service did not stop; giving up.\n" );
  849. break;
  850. }
  851. (g_LogEvent)(
  852. resourceEntry->ResourceHandle,
  853. LOG_INFORMATION,
  854. L"Offline: retrying...\n" );
  855. Sleep(retryTick);
  856. }
  857. //if there is a pid for this, try and terminate that process
  858. //note that terminating a process doesnt terminate all
  859. //the child processes
  860. if (resourceEntry->dwServicePid)
  861. {
  862. (g_LogEvent)(
  863. resourceEntry->ResourceHandle,
  864. LOG_INFORMATION,
  865. L"SvcTerminate: terminating processid =%1!u!\n",
  866. resourceEntry->dwServicePid);
  867. SvcpTerminateServiceProcess( resourceEntry,
  868. FALSE,
  869. NULL );
  870. }
  871. CloseServiceHandle( resourceEntry->ServiceHandle );
  872. resourceEntry->ServiceHandle = NULL;
  873. resourceEntry->dwServicePid = 0;
  874. }
  875. resourceEntry->Online = FALSE;
  876. } // CommonTerminate
  877. static
  878. DWORD
  879. WINAPI
  880. CommonOffline(
  881. IN RESID ResourceId
  882. )
  883. /*++
  884. Routine Description:
  885. Offline routine for Common Service resource.
  886. Arguments:
  887. ResourceId - Supplies the resource to be taken offline
  888. Return Value:
  889. ERROR_SUCCESS - always successful.
  890. --*/
  891. {
  892. PCOMMON_RESOURCE resourceEntry;
  893. DWORD status;
  894. resourceEntry = (PCOMMON_RESOURCE)ResourceId;
  895. if ( resourceEntry == NULL ) {
  896. DBG_PRINT( "Common: Offline request for a nonexistent resource id 0x%p.\n",
  897. ResourceId );
  898. return(ERROR_RESOURCE_NOT_FOUND);
  899. }
  900. if ( resourceEntry != CommonResource ) {
  901. DBG_PRINT( "Common: Offline request for wrong resource, 0x%p.\n",
  902. ResourceId );
  903. return(ERROR_INVALID_PARAMETER);
  904. }
  905. (g_LogEvent)(
  906. resourceEntry->ResourceHandle,
  907. LOG_INFORMATION,
  908. L"Offline request.\n" );
  909. ClusWorkerTerminate( &resourceEntry->PendingThread );
  910. status = ClusWorkerCreate( &resourceEntry->PendingThread,
  911. CommonOfflineThread,
  912. resourceEntry );
  913. if ( status == ERROR_SUCCESS ) {
  914. status = ERROR_IO_PENDING;
  915. }
  916. return(status);
  917. }
  918. static
  919. DWORD
  920. CommonOfflineThread(
  921. PCLUS_WORKER pWorker,
  922. IN PCOMMON_RESOURCE ResourceEntry
  923. )
  924. /*++
  925. Routine Description:
  926. Offline routine for Common Service resource.
  927. Arguments:
  928. ResourceId - Supplies the resource to be taken offline
  929. Return Value:
  930. ERROR_SUCCESS - always successful.
  931. --*/
  932. {
  933. RESOURCE_STATUS resourceStatus;
  934. DWORD retryTick = 300; // 300 msec at a time
  935. DWORD status = ERROR_SUCCESS;
  936. BOOL didStop = FALSE;
  937. SERVICE_STATUS ServiceStatus;
  938. ResUtilInitializeResourceStatus( &resourceStatus );
  939. resourceStatus.ResourceState = ClusterResourceFailed;
  940. //resourceStatus.WaitHint = 0;
  941. resourceStatus.CheckPoint = 1;
  942. //check if the service has gone offline or was never brought online
  943. if ( ResourceEntry->ServiceHandle == NULL )
  944. {
  945. resourceStatus.ResourceState = ClusterResourceOffline;
  946. goto FnExit;
  947. }
  948. //try to stop the cluster service, wait for it to be terminated
  949. //as long as we are not asked to terminate
  950. while (!ClusWorkerCheckTerminate(pWorker)) {
  951. status = (ControlService(
  952. ResourceEntry->ServiceHandle,
  953. (didStop
  954. ? SERVICE_CONTROL_INTERROGATE
  955. : SERVICE_CONTROL_STOP),
  956. &ServiceStatus )
  957. ? NO_ERROR
  958. : GetLastError());
  959. if (status == NO_ERROR) {
  960. didStop = TRUE;
  961. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
  962. (g_LogEvent)(
  963. ResourceEntry->ResourceHandle,
  964. LOG_INFORMATION,
  965. L"Service stopped.\n" );
  966. //set the status
  967. ResourceEntry->Online = FALSE;
  968. resourceStatus.ResourceState = ClusterResourceOffline;
  969. CloseServiceHandle( ResourceEntry->ServiceHandle );
  970. ResourceEntry->ServiceHandle = NULL;
  971. ResourceEntry->dwServicePid = 0;
  972. (g_LogEvent)(
  973. ResourceEntry->ResourceHandle,
  974. LOG_INFORMATION,
  975. L"Service is now offline.\n" );
  976. break;
  977. }
  978. }
  979. //
  980. // Chittur Subbaraman (chitturs) - 2/21/2000
  981. //
  982. // Since SCM doesn't accept any control requests during
  983. // windows shutdown, don't send any more control
  984. // requests. Just exit from this loop and terminate
  985. // the process brute force.
  986. //
  987. if (status == ERROR_SHUTDOWN_IN_PROGRESS)
  988. {
  989. DWORD dwResourceState;
  990. (g_LogEvent)(
  991. ResourceEntry->ResourceHandle,
  992. LOG_INFORMATION,
  993. L"OfflineThread: System shutting down. Attempt to terminate service process %1!u!...\n",
  994. ResourceEntry->dwServicePid );
  995. status = SvcpTerminateServiceProcess( ResourceEntry,
  996. TRUE,
  997. &dwResourceState );
  998. if ( status == ERROR_SUCCESS )
  999. {
  1000. CloseServiceHandle( ResourceEntry->ServiceHandle );
  1001. ResourceEntry->ServiceHandle = NULL;
  1002. ResourceEntry->dwServicePid = 0;
  1003. ResourceEntry->Online = FALSE;
  1004. }
  1005. resourceStatus.ResourceState = dwResourceState;
  1006. break;
  1007. }
  1008. if (status == ERROR_EXCEPTION_IN_SERVICE ||
  1009. status == ERROR_PROCESS_ABORTED ||
  1010. status == ERROR_SERVICE_NOT_ACTIVE) {
  1011. (g_LogEvent)(
  1012. ResourceEntry->ResourceHandle,
  1013. LOG_INFORMATION,
  1014. L"Service died or not active any more; status = %1!u!.\n",
  1015. status);
  1016. //set the status
  1017. ResourceEntry->Online = FALSE;
  1018. resourceStatus.ResourceState = ClusterResourceOffline;
  1019. CloseServiceHandle( ResourceEntry->ServiceHandle );
  1020. ResourceEntry->ServiceHandle = NULL;
  1021. ResourceEntry->dwServicePid = 0;
  1022. (g_LogEvent)(
  1023. ResourceEntry->ResourceHandle,
  1024. LOG_INFORMATION,
  1025. L"Service is now offline.\n" );
  1026. break;
  1027. }
  1028. (g_LogEvent)(
  1029. ResourceEntry->ResourceHandle,
  1030. LOG_INFORMATION,
  1031. L"Offline: retrying...\n" );
  1032. Sleep(retryTick);
  1033. }
  1034. FnExit:
  1035. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  1036. &resourceStatus );
  1037. return(status);
  1038. }
  1039. // CommonOfflineThread
  1040. static
  1041. BOOL
  1042. WINAPI
  1043. CommonIsAlive(
  1044. IN RESID ResourceId
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. IsAlive routine for Common service resource.
  1049. Arguments:
  1050. ResourceId - Supplies the resource id to be polled.
  1051. Return Value:
  1052. TRUE - if service is running
  1053. FALSE - if service is in any other state
  1054. --*/
  1055. {
  1056. return( CommonVerifyService( ResourceId, TRUE ) );
  1057. } // CommonIsAlive
  1058. static
  1059. BOOL
  1060. CommonVerifyService(
  1061. IN RESID ResourceId,
  1062. IN BOOL IsAliveFlag)
  1063. /*++
  1064. Routine Description:
  1065. Verify that a specified service is running
  1066. Arguments:
  1067. ResourceId - Supplies the resource id
  1068. IsAliveFlag - Says this is an IsAlive call - used only for debug print
  1069. Return Value:
  1070. TRUE - if service is running or starting
  1071. FALSE - service is in any other state
  1072. --*/
  1073. {
  1074. SERVICE_STATUS ServiceStatus;
  1075. PCOMMON_RESOURCE resourceEntry;
  1076. DWORD status = TRUE;
  1077. resourceEntry = (PCOMMON_RESOURCE)ResourceId;
  1078. if ( resourceEntry != CommonResource ) {
  1079. DBG_PRINT( "Common: IsAlive request for wrong resource 0x%p.\n",
  1080. ResourceId );
  1081. return(FALSE);
  1082. }
  1083. if ( resourceEntry == NULL ) {
  1084. DBG_PRINT( "Common: IsAlive request for a nonexistent resource id 0x%p.\n",
  1085. ResourceId );
  1086. return(FALSE);
  1087. }
  1088. if ( !QueryServiceStatus( resourceEntry->ServiceHandle,
  1089. &ServiceStatus ) ) {
  1090. (g_LogEvent)(
  1091. resourceEntry->ResourceHandle,
  1092. LOG_ERROR,
  1093. L"Query Service Status failed %1!u!.\n",
  1094. GetLastError() );
  1095. return(FALSE);
  1096. }
  1097. //
  1098. // Now check the status of the service
  1099. //
  1100. if ((ServiceStatus.dwCurrentState != SERVICE_RUNNING)&&(ServiceStatus.dwCurrentState != SERVICE_START_PENDING)){
  1101. status = FALSE;
  1102. }
  1103. if (!status) {
  1104. (g_LogEvent)(
  1105. resourceEntry->ResourceHandle,
  1106. LOG_ERROR,
  1107. L"Failed the IsAlive test. Current State is %1!u!.\n",
  1108. ServiceStatus.dwCurrentState );
  1109. }
  1110. return(status);
  1111. } // Verify Service
  1112. static
  1113. BOOL
  1114. WINAPI
  1115. CommonLooksAlive(
  1116. IN RESID ResourceId
  1117. )
  1118. /*++
  1119. Routine Description:
  1120. LooksAlive routine for Common Service resource.
  1121. Arguments:
  1122. ResourceId - Supplies the resource id to be polled.
  1123. Return Value:
  1124. TRUE - Resource looks like it is alive and well
  1125. FALSE - Resource looks like it is toast.
  1126. --*/
  1127. {
  1128. return( CommonVerifyService( ResourceId, FALSE ) );
  1129. } // CommonLooksAlive
  1130. static
  1131. VOID
  1132. WINAPI
  1133. CommonClose(
  1134. IN RESID ResourceId
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. Close routine for Common Services resource.
  1139. This routine will stop the service, and delete the cluster
  1140. information regarding that service.
  1141. Arguments:
  1142. ResourceId - Supplies resource id to be closed
  1143. Return Value:
  1144. None.
  1145. --*/
  1146. {
  1147. PCOMMON_RESOURCE resourceEntry;
  1148. DWORD errorCode;
  1149. resourceEntry = (PCOMMON_RESOURCE)ResourceId;
  1150. if ( resourceEntry == NULL ) {
  1151. DBG_PRINT( "Common: Close request for a nonexistent resource id 0x%p\n",
  1152. ResourceId );
  1153. return;
  1154. }
  1155. (g_LogEvent)(
  1156. resourceEntry->ResourceHandle,
  1157. LOG_INFORMATION,
  1158. L"Close request.\n" );
  1159. //
  1160. // Shut it down if it's on line
  1161. //
  1162. CommonTerminate( ResourceId );
  1163. ClusterRegCloseKey( resourceEntry->ParametersKey );
  1164. ClusterRegCloseKey( resourceEntry->ResourceKey );
  1165. CloseClusterResource( resourceEntry->hResource );
  1166. #ifdef COMMON_SEMAPHORE
  1167. if ( resourceEntry == CommonResource ) {
  1168. (g_LogEvent)(
  1169. resourceEntry->ResourceHandle,
  1170. LOG_INFORMATION,
  1171. L"Setting Semaphore %1!ws!.\n",
  1172. COMMON_SEMAPHORE );
  1173. CommonResource = NULL;
  1174. ReleaseSemaphore( CommonSemaphore, 1 , NULL );
  1175. }
  1176. #endif
  1177. LocalFree( resourceEntry );
  1178. } // CommonClose
  1179. static
  1180. DWORD
  1181. SvcpTerminateServiceProcess(
  1182. IN PCOMMON_RESOURCE pResourceEntry,
  1183. IN BOOL bOffline,
  1184. OUT PDWORD pdwResourceState
  1185. )
  1186. /*++
  1187. Routine Description:
  1188. Attempts to terminate a service process.
  1189. Arguments:
  1190. pResourceEntry - Gensvc resource structure.
  1191. bOffline - Called from the offline thread or not.
  1192. pdwResourceState - State of the gensvc resource.
  1193. Return Value:
  1194. ERROR_SUCCESS - The termination was successful.
  1195. Win32 error - Otherwise.
  1196. --*/
  1197. {
  1198. HANDLE hSvcProcess = NULL;
  1199. DWORD dwStatus = ERROR_SUCCESS;
  1200. BOOLEAN bWasEnabled;
  1201. DWORD dwResourceState = ClusterResourceFailed;
  1202. //
  1203. // Chittur Subbaraman (chitturs) - 2/23/2000
  1204. //
  1205. (g_LogEvent)(
  1206. pResourceEntry->ResourceHandle,
  1207. LOG_INFORMATION,
  1208. L"SvcpTerminateServiceProcess: Process with id=%1!u! might be terminated...\n",
  1209. pResourceEntry->dwServicePid );
  1210. //
  1211. // Adjust the privilege to allow debug. This is to allow
  1212. // termination of a service process which runs in a local
  1213. // system account from a different service process which runs in a
  1214. // domain user account.
  1215. //
  1216. dwStatus = ClRtlEnableThreadPrivilege( SE_DEBUG_PRIVILEGE,
  1217. &bWasEnabled );
  1218. if ( dwStatus != ERROR_SUCCESS )
  1219. {
  1220. (g_LogEvent)(
  1221. pResourceEntry->ResourceHandle,
  1222. LOG_ERROR,
  1223. L"SvcpTerminateServiceProcess: Unable to set debug privilege for process with id=%1!u!, status=%2!u!...\n",
  1224. pResourceEntry->dwServicePid,
  1225. dwStatus );
  1226. goto FnExit;
  1227. }
  1228. hSvcProcess = OpenProcess( PROCESS_TERMINATE,
  1229. FALSE,
  1230. pResourceEntry->dwServicePid );
  1231. if ( !hSvcProcess )
  1232. {
  1233. //
  1234. // Did this happen because the process terminated
  1235. // too quickly after we sent out one control request ?
  1236. //
  1237. dwStatus = GetLastError();
  1238. (g_LogEvent)(
  1239. pResourceEntry->ResourceHandle,
  1240. LOG_INFORMATION,
  1241. L"SvcpTerminateServiceProcess: Unable to open pid=%1!u! for termination, status=%2!u!...\n",
  1242. pResourceEntry->dwServicePid,
  1243. dwStatus );
  1244. goto FnRestoreAndExit;
  1245. }
  1246. if ( !bOffline )
  1247. {
  1248. (g_LogEvent)(
  1249. pResourceEntry->ResourceHandle,
  1250. LOG_INFORMATION,
  1251. L"SvcpTerminateServiceProcess: Pid=%1!u! will be terminated brute force...\n",
  1252. pResourceEntry->dwServicePid );
  1253. goto skip_waiting;
  1254. }
  1255. if ( WaitForSingleObject( hSvcProcess, 3000 )
  1256. == WAIT_OBJECT_0 )
  1257. {
  1258. (g_LogEvent)(
  1259. pResourceEntry->ResourceHandle,
  1260. LOG_INFORMATION,
  1261. L"SvcpTerminateServiceProcess: Process with id=%1!u! shutdown gracefully...\n",
  1262. pResourceEntry->dwServicePid );
  1263. dwResourceState = ClusterResourceOffline;
  1264. dwStatus = ERROR_SUCCESS;
  1265. goto FnRestoreAndExit;
  1266. }
  1267. skip_waiting:
  1268. if ( !TerminateProcess( hSvcProcess, 0 ) )
  1269. {
  1270. dwStatus = GetLastError();
  1271. (g_LogEvent)(
  1272. pResourceEntry->ResourceHandle,
  1273. LOG_ERROR,
  1274. L"SvcpTerminateServiceProcess: Unable to terminate process with id=%1!u!, status=%2!u!...\n",
  1275. pResourceEntry->dwServicePid,
  1276. dwStatus );
  1277. goto FnRestoreAndExit;
  1278. }
  1279. dwResourceState = ClusterResourceOffline;
  1280. FnRestoreAndExit:
  1281. ClRtlRestoreThreadPrivilege( SE_DEBUG_PRIVILEGE,
  1282. bWasEnabled );
  1283. FnExit:
  1284. if ( hSvcProcess )
  1285. {
  1286. CloseHandle( hSvcProcess );
  1287. }
  1288. if ( ARGUMENT_PRESENT( pdwResourceState ) )
  1289. {
  1290. *pdwResourceState = dwResourceState;
  1291. }
  1292. (g_LogEvent)(
  1293. pResourceEntry->ResourceHandle,
  1294. LOG_INFORMATION,
  1295. L"SvcpTerminateServiceProcess: Process id=%1!u!, status=%2!u!, state=%3!u!...\n",
  1296. pResourceEntry->dwServicePid,
  1297. dwStatus,
  1298. dwResourceState );
  1299. return( dwStatus );
  1300. } // SvcpTerminateServiceProcess
  1301. #ifdef COMMON_CONTROL
  1302. static
  1303. DWORD
  1304. CommonGetRequiredDependencies(
  1305. OUT PVOID OutBuffer,
  1306. IN DWORD OutBufferSize,
  1307. OUT LPDWORD BytesReturned
  1308. )
  1309. /*++
  1310. Routine Description:
  1311. Processes the CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES control function
  1312. for common service resources.
  1313. Arguments:
  1314. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1315. OutBufferSize - Supplies the size, in bytes, of the available space
  1316. pointed to by OutBuffer.
  1317. BytesReturned - Returns the number of bytes of OutBuffer actually
  1318. filled in by the resource. If OutBuffer is too small, BytesReturned
  1319. contains the total number of bytes for the operation to succeed.
  1320. Return Value:
  1321. ERROR_SUCCESS - The function completed successfully.
  1322. ERROR_MORE_DATA - The output buffer is too small to return the data.
  1323. BytesReturned contains the required size.
  1324. Win32 error code - The function failed.
  1325. --*/
  1326. {
  1327. PCOMMON_DEPEND_SETUP pdepsetup = CommonDependSetup;
  1328. PCOMMON_DEPEND_DATA pdepdata = (PCOMMON_DEPEND_DATA)OutBuffer;
  1329. CLUSPROP_BUFFER_HELPER value;
  1330. DWORD status;
  1331. *BytesReturned = sizeof(COMMON_DEPEND_DATA);
  1332. if ( OutBufferSize < sizeof(COMMON_DEPEND_DATA) ) {
  1333. if ( OutBuffer == NULL ) {
  1334. status = ERROR_SUCCESS;
  1335. } else {
  1336. status = ERROR_MORE_DATA;
  1337. }
  1338. } else {
  1339. ZeroMemory( OutBuffer, sizeof(COMMON_DEPEND_DATA) );
  1340. while ( pdepsetup->Syntax.dw != 0 ) {
  1341. value.pb = (PUCHAR)OutBuffer + pdepsetup->Offset;
  1342. value.pValue->Syntax.dw = pdepsetup->Syntax.dw;
  1343. value.pValue->cbLength = pdepsetup->Length;
  1344. switch ( pdepsetup->Syntax.wFormat ) {
  1345. case CLUSPROP_FORMAT_DWORD:
  1346. value.pDwordValue->dw = (DWORD)((DWORD_PTR)pdepsetup->Value);
  1347. break;
  1348. case CLUSPROP_FORMAT_ULARGE_INTEGER:
  1349. value.pULargeIntegerValue->li.LowPart =
  1350. (DWORD)((DWORD_PTR)pdepsetup->Value);
  1351. break;
  1352. case CLUSPROP_FORMAT_SZ:
  1353. case CLUSPROP_FORMAT_EXPAND_SZ:
  1354. case CLUSPROP_FORMAT_MULTI_SZ:
  1355. case CLUSPROP_FORMAT_BINARY:
  1356. memcpy( value.pBinaryValue->rgb, pdepsetup->Value, pdepsetup->Length );
  1357. break;
  1358. default:
  1359. break;
  1360. }
  1361. pdepsetup++;
  1362. }
  1363. pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
  1364. status = ERROR_SUCCESS;
  1365. }
  1366. return(status);
  1367. } // CommonGetRequiredDependencies
  1368. static
  1369. DWORD
  1370. CommonGetRegistryCheckpoints(
  1371. OUT PVOID OutBuffer,
  1372. IN DWORD OutBufferSize,
  1373. OUT LPDWORD BytesReturned
  1374. )
  1375. /*++
  1376. Routine Description:
  1377. Processes the CLUSCTL_RESOURCE_GET_REGISTRY_CHECKPOINTS control function
  1378. for common service resources.
  1379. Arguments:
  1380. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1381. OutBufferSize - Supplies the size, in bytes, of the available space
  1382. pointed to by OutBuffer.
  1383. BytesReturned - Returns the number of bytes of OutBuffer actually
  1384. filled in by the resource. If OutBuffer is too small, BytesReturned
  1385. contains the total number of bytes for the operation to succeed.
  1386. Return Value:
  1387. ERROR_SUCCESS - The function completed successfully.
  1388. ERROR_MORE_DATA - The output buffer is too small to return the data.
  1389. BytesReturned contains the required size.
  1390. Win32 error code - The function failed.
  1391. --*/
  1392. {
  1393. DWORD status;
  1394. DWORD i;
  1395. DWORD totalBufferLength = 0;
  1396. LPWSTR psz = OutBuffer;
  1397. // Build a Multi-sz string.
  1398. //
  1399. // Calculate total buffer length needed.
  1400. //
  1401. for ( i = 0; i < RegSyncCount; i++ ) {
  1402. totalBufferLength += (lstrlenW( RegSync[i] ) + 1) * sizeof(WCHAR);
  1403. }
  1404. if ( !totalBufferLength ) {
  1405. *BytesReturned = 0;
  1406. return(ERROR_SUCCESS);
  1407. }
  1408. totalBufferLength += sizeof(UNICODE_NULL);
  1409. *BytesReturned = totalBufferLength;
  1410. if ( OutBufferSize < totalBufferLength ) {
  1411. if ( OutBuffer == NULL ) {
  1412. status = ERROR_SUCCESS;
  1413. } else {
  1414. status = ERROR_MORE_DATA;
  1415. }
  1416. } else {
  1417. //ZeroMemory( OutBuffer, totalBufferLength );
  1418. for ( i = 0; i < RegSyncCount; i++ ) {
  1419. lstrcpyW( psz, RegSync[i] );
  1420. psz += lstrlenW( RegSync[i] ) + 1;
  1421. }
  1422. *psz = L'\0';
  1423. status = ERROR_SUCCESS;
  1424. }
  1425. return(status);
  1426. } // CommonGetRegistryCheckpoints
  1427. static
  1428. DWORD
  1429. CommonGetCryptoCheckpoints(
  1430. OUT PVOID OutBuffer,
  1431. IN DWORD OutBufferSize,
  1432. OUT LPDWORD BytesReturned
  1433. )
  1434. /*++
  1435. Routine Description:
  1436. Processes the CLUSCTL_RESOURCE_GET_CRYPTO_CHECKPOINTS control function
  1437. for common service resources.
  1438. Arguments:
  1439. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1440. OutBufferSize - Supplies the size, in bytes, of the available space
  1441. pointed to by OutBuffer.
  1442. BytesReturned - Returns the number of bytes of OutBuffer actually
  1443. filled in by the resource. If OutBuffer is too small, BytesReturned
  1444. contains the total number of bytes for the operation to succeed.
  1445. Return Value:
  1446. ERROR_SUCCESS - The function completed successfully.
  1447. ERROR_MORE_DATA - The output buffer is too small to return the data.
  1448. BytesReturned contains the required size.
  1449. Win32 error code - The function failed.
  1450. --*/
  1451. {
  1452. DWORD status;
  1453. DWORD i;
  1454. DWORD totalBufferLength = 0;
  1455. LPWSTR psz = OutBuffer;
  1456. // Build a Multi-sz string.
  1457. //
  1458. // Calculate total buffer length needed.
  1459. //
  1460. for ( i = 0; i < CryptoSyncCount; i++ ) {
  1461. totalBufferLength += (lstrlenW( CryptoSync[i] ) + 1) * sizeof(WCHAR);
  1462. }
  1463. if ( !totalBufferLength ) {
  1464. *BytesReturned = 0;
  1465. return(ERROR_SUCCESS);
  1466. }
  1467. totalBufferLength += sizeof(UNICODE_NULL);
  1468. *BytesReturned = totalBufferLength;
  1469. if ( OutBufferSize < totalBufferLength ) {
  1470. if ( OutBuffer == NULL ) {
  1471. status = ERROR_SUCCESS;
  1472. } else {
  1473. status = ERROR_MORE_DATA;
  1474. }
  1475. } else {
  1476. //ZeroMemory( OutBuffer, totalBufferLength );
  1477. for ( i = 0; i < CryptoSyncCount; i++ ) {
  1478. lstrcpyW( psz, CryptoSync[i] );
  1479. psz += lstrlenW( CryptoSync[i] ) + 1;
  1480. }
  1481. *psz = L'\0';
  1482. status = ERROR_SUCCESS;
  1483. }
  1484. return(status);
  1485. } // CommonGetCryptoCheckpoints
  1486. static
  1487. DWORD
  1488. WINAPI
  1489. CommonResourceControl(
  1490. IN RESID ResourceId,
  1491. IN DWORD ControlCode,
  1492. IN PVOID InBuffer,
  1493. IN DWORD InBufferSize,
  1494. OUT PVOID OutBuffer,
  1495. IN DWORD OutBufferSize,
  1496. OUT LPDWORD BytesReturned
  1497. )
  1498. /*++
  1499. Routine Description:
  1500. ResourceControl routine for Common Virtual Root resources.
  1501. Perform the control request specified by ControlCode on the specified
  1502. resource.
  1503. Arguments:
  1504. ResourceId - Supplies the resource id for the specific resource.
  1505. ControlCode - Supplies the control code that defines the action
  1506. to be performed.
  1507. InBuffer - Supplies a pointer to a buffer containing input data.
  1508. InBufferSize - Supplies the size, in bytes, of the data pointed
  1509. to by InBuffer.
  1510. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1511. OutBufferSize - Supplies the size, in bytes, of the available space
  1512. pointed to by OutBuffer.
  1513. BytesReturned - Returns the number of bytes of OutBuffer actually
  1514. filled in by the resource. If OutBuffer is too small, BytesReturned
  1515. contains the total number of bytes for the operation to succeed.
  1516. Return Value:
  1517. ERROR_SUCCESS - The function completed successfully.
  1518. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1519. In some cases, this allows the cluster software to perform the work.
  1520. Win32 error code - The function failed.
  1521. --*/
  1522. {
  1523. DWORD status;
  1524. PCOMMON_RESOURCE resourceEntry = NULL;
  1525. switch ( ControlCode ) {
  1526. case CLUSCTL_RESOURCE_UNKNOWN:
  1527. *BytesReturned = 0;
  1528. status = ERROR_SUCCESS;
  1529. break;
  1530. case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
  1531. status = CommonGetRequiredDependencies( OutBuffer,
  1532. OutBufferSize,
  1533. BytesReturned
  1534. );
  1535. break;
  1536. case CLUSCTL_RESOURCE_GET_REGISTRY_CHECKPOINTS:
  1537. status = CommonGetRegistryCheckpoints( OutBuffer,
  1538. OutBufferSize,
  1539. BytesReturned
  1540. );
  1541. break;
  1542. case CLUSCTL_RESOURCE_GET_CRYPTO_CHECKPOINTS:
  1543. status = CommonGetCryptoCheckpoints( OutBuffer,
  1544. OutBufferSize,
  1545. BytesReturned
  1546. );
  1547. break;
  1548. default:
  1549. status = ERROR_INVALID_FUNCTION;
  1550. break;
  1551. }
  1552. return(status);
  1553. } // CommonResourceControl
  1554. static
  1555. DWORD
  1556. WINAPI
  1557. CommonResourceTypeControl(
  1558. IN LPCWSTR ResourceTypeName,
  1559. IN DWORD ControlCode,
  1560. IN PVOID InBuffer,
  1561. IN DWORD InBufferSize,
  1562. OUT PVOID OutBuffer,
  1563. IN DWORD OutBufferSize,
  1564. OUT LPDWORD BytesReturned
  1565. )
  1566. /*++
  1567. Routine Description:
  1568. ResourceTypeControl routine for Common Virtual Root resources.
  1569. Perform the control request specified by ControlCode.
  1570. Arguments:
  1571. ResourceTypeName - Supplies the name of the resource type.
  1572. ControlCode - Supplies the control code that defines the action
  1573. to be performed.
  1574. InBuffer - Supplies a pointer to a buffer containing input data.
  1575. InBufferSize - Supplies the size, in bytes, of the data pointed
  1576. to by InBuffer.
  1577. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1578. OutBufferSize - Supplies the size, in bytes, of the available space
  1579. pointed to by OutBuffer.
  1580. BytesReturned - Returns the number of bytes of OutBuffer actually
  1581. filled in by the resource. If OutBuffer is too small, BytesReturned
  1582. contains the total number of bytes for the operation to succeed.
  1583. Return Value:
  1584. ERROR_SUCCESS - The function completed successfully.
  1585. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1586. In some cases, this allows the cluster software to perform the work.
  1587. Win32 error code - The function failed.
  1588. --*/
  1589. {
  1590. DWORD status;
  1591. switch ( ControlCode ) {
  1592. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  1593. *BytesReturned = 0;
  1594. status = ERROR_SUCCESS;
  1595. break;
  1596. case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
  1597. status = CommonGetRequiredDependencies( OutBuffer,
  1598. OutBufferSize,
  1599. BytesReturned
  1600. );
  1601. break;
  1602. case CLUSCTL_RESOURCE_TYPE_GET_REGISTRY_CHECKPOINTS:
  1603. status = CommonGetRegistryCheckpoints( OutBuffer,
  1604. OutBufferSize,
  1605. BytesReturned
  1606. );
  1607. break;
  1608. case CLUSCTL_RESOURCE_TYPE_GET_CRYPTO_CHECKPOINTS:
  1609. status = CommonGetCryptoCheckpoints( OutBuffer,
  1610. OutBufferSize,
  1611. BytesReturned
  1612. );
  1613. break;
  1614. default:
  1615. status = ERROR_INVALID_FUNCTION;
  1616. break;
  1617. }
  1618. return(status);
  1619. } // CommonResourceTypeControl
  1620. #endif // COMMON_CONTROL