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.

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