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.

2633 lines
78 KiB

  1. /*++
  2. Copyright (c) 1992-2000 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 "userenv.h"
  15. #include <strsafe.h>
  16. // Uncomment the next line to test the Terminate() function when
  17. // a shutdown is in progress.
  18. //#define TEST_TERMINATE_ON_SHUTDOWN
  19. #define LOG_CURRENT_MODULE LOG_MODULE_GENSVC
  20. #define SERVICES_ROOT L"SYSTEM\\CurrentControlSet\\Services\\"
  21. #define DBG_PRINT printf
  22. #define PARAM_NAME__SERVICENAME CLUSREG_NAME_GENSVC_SERVICE_NAME
  23. #define PARAM_NAME__STARTUPPARAMETERS CLUSREG_NAME_GENSVC_STARTUP_PARAMS
  24. #define PARAM_NAME__USENETWORKNAME CLUSREG_NAME_GENSVC_USE_NETWORK_NAME
  25. #define PARAM_MIN__USENETWORKNAME 0
  26. #define PARAM_MAX__USENETWORKNAME 1
  27. #define PARAM_DEFAULT__USENETWORKNAME 0
  28. typedef struct _GENSVC_PARAMS {
  29. PWSTR ServiceName;
  30. PWSTR StartupParameters;
  31. DWORD UseNetworkName;
  32. } GENSVC_PARAMS, *PGENSVC_PARAMS;
  33. typedef struct _GENSVC_RESOURCE {
  34. GENSVC_PARAMS Params;
  35. HRESOURCE hResource;
  36. HANDLE ServiceHandle;
  37. RESOURCE_HANDLE ResourceHandle;
  38. HKEY ResourceKey;
  39. HKEY ParametersKey;
  40. CLUS_WORKER PendingThread;
  41. BOOL Online;
  42. DWORD dwServicePid;
  43. HANDLE hSem;
  44. } GENSVC_RESOURCE, *PGENSVC_RESOURCE;
  45. //
  46. // Global Data
  47. //
  48. // Handle to service controller, set by the first create resource call.
  49. SC_HANDLE g_ScHandle = NULL;
  50. // Log Event Routine
  51. #define g_LogEvent ClusResLogEvent
  52. #define g_SetResourceStatus ClusResSetResourceStatus
  53. // Forward reference to our RESAPI function table.
  54. extern CLRES_FUNCTION_TABLE GenSvcFunctionTable;
  55. //
  56. // Generic Service resource read-write private properties.
  57. //
  58. RESUTIL_PROPERTY_ITEM
  59. GenSvcResourcePrivateProperties[] = {
  60. { PARAM_NAME__SERVICENAME, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(GENSVC_PARAMS,ServiceName) },
  61. { PARAM_NAME__STARTUPPARAMETERS, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, 0, FIELD_OFFSET(GENSVC_PARAMS,StartupParameters) },
  62. { PARAM_NAME__USENETWORKNAME, NULL, CLUSPROP_FORMAT_DWORD, PARAM_DEFAULT__USENETWORKNAME, PARAM_MIN__USENETWORKNAME, PARAM_MAX__USENETWORKNAME, 0, FIELD_OFFSET(GENSVC_PARAMS,UseNetworkName) },
  63. { 0 }
  64. };
  65. //
  66. // Forward routines
  67. //
  68. BOOL
  69. VerifyService(
  70. IN RESID ResourceId,
  71. IN BOOL IsAliveFlag
  72. );
  73. void
  74. wparse_cmdline (
  75. WCHAR *cmdstart,
  76. WCHAR **argv,
  77. WCHAR *args,
  78. int *numargs,
  79. int *numchars
  80. );
  81. DWORD
  82. GenSvcGetPrivateResProperties(
  83. IN const PGENSVC_RESOURCE ResourceEntry,
  84. OUT PVOID OutBuffer,
  85. IN DWORD OutBufferSize,
  86. OUT LPDWORD BytesReturned
  87. );
  88. DWORD
  89. GenSvcValidatePrivateResProperties(
  90. IN const PGENSVC_RESOURCE ResourceEntry,
  91. IN const PVOID InBuffer,
  92. IN DWORD InBufferSize,
  93. OUT PGENSVC_PARAMS Params
  94. );
  95. DWORD
  96. GenSvcSetPrivateResProperties(
  97. IN OUT PGENSVC_RESOURCE ResourceEntry,
  98. IN const PVOID InBuffer,
  99. IN DWORD InBufferSize
  100. );
  101. DWORD
  102. GenSvcCheckInvalidService(
  103. IN PGENSVC_RESOURCE pGenSvcCandidateResourceEntry,
  104. IN LPCWSTR pGenSvcCandidateServiceName,
  105. IN LPCWSTR pCheckedServiceName,
  106. IN SC_HANDLE hSCManager
  107. );
  108. DWORD
  109. GenSvcIsValidService(
  110. IN OUT PGENSVC_RESOURCE ResourceEntry,
  111. IN LPCWSTR ServiceName
  112. );
  113. DWORD
  114. GenSvcOfflineThread(
  115. PCLUS_WORKER pWorker,
  116. IN PGENSVC_RESOURCE ResourceEntry
  117. );
  118. BOOLEAN
  119. GenSvcInit(
  120. VOID
  121. )
  122. {
  123. return(TRUE);
  124. }
  125. BOOLEAN
  126. WINAPI
  127. GenSvcDllEntryPoint(
  128. IN HINSTANCE DllHandle,
  129. IN DWORD Reason,
  130. IN LPVOID Reserved
  131. )
  132. {
  133. switch( Reason ) {
  134. case DLL_PROCESS_ATTACH:
  135. if ( !GenSvcInit() ) {
  136. return(FALSE);
  137. }
  138. break;
  139. case DLL_PROCESS_DETACH:
  140. break;
  141. default:
  142. break;
  143. }
  144. return(TRUE);
  145. } // GenSvc DllEntryPoint
  146. DWORD
  147. GenSvcOnlineThread(
  148. PCLUS_WORKER pWorker,
  149. IN PGENSVC_RESOURCE ResourceEntry
  150. )
  151. /*++
  152. Routine Description:
  153. Brings a disk resource online.
  154. Arguments:
  155. Worker - Supplies the worker structure
  156. Context - A pointer to the DiskInfo block for this resource.
  157. Returns:
  158. ERROR_SUCCESS if successful.
  159. Win32 error code on failure.
  160. --*/
  161. {
  162. SERVICE_STATUS_PROCESS ServiceStatus;
  163. DWORD status = ERROR_SUCCESS;
  164. DWORD numchars;
  165. LPWSTR * serviceArgArray = NULL;
  166. DWORD serviceArgCount;
  167. SC_HANDLE serviceHandle;
  168. RESOURCE_STATUS resourceStatus;
  169. DWORD valueSize;
  170. LPVOID Environment = NULL;
  171. WCHAR * p;
  172. LPWSTR nameOfPropInError;
  173. LPSERVICE_FAILURE_ACTIONS pSvcFailureActions = NULL;
  174. DWORD cbBytesNeeded, i;
  175. LPQUERY_SERVICE_CONFIG lpquerysvcconfig=NULL;
  176. HANDLE processToken = NULL;
  177. DWORD dwRetryCount = 2400; // Try 10 min max.
  178. DWORD dwRetryTick = 250; // msec
  179. ResUtilInitializeResourceStatus( &resourceStatus );
  180. resourceStatus.ResourceState = ClusterResourceFailed;
  181. resourceStatus.CheckPoint = 1;
  182. //set it to NULL, when it is brought online and if the
  183. //service is not running in the system or lsa process
  184. //then store the process id for forceful termination
  185. ResourceEntry->dwServicePid = 0;
  186. //
  187. // Read our parameters.
  188. //
  189. status = ResUtilGetPropertiesToParameterBlock( ResourceEntry->ParametersKey,
  190. GenSvcResourcePrivateProperties,
  191. (LPBYTE) &ResourceEntry->Params,
  192. TRUE, // CheckForRequiredProperties
  193. &nameOfPropInError );
  194. if ( status != ERROR_SUCCESS ) {
  195. (g_LogEvent)(
  196. ResourceEntry->ResourceHandle,
  197. LOG_ERROR,
  198. L"Unable to read the '%1!ls!' property. Error: %2!u!.\n",
  199. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  200. status );
  201. goto error_exit;
  202. }
  203. //
  204. // Parse the startup parameters
  205. //
  206. if ( ResourceEntry->Params.StartupParameters != NULL ) {
  207. //
  208. // Crack the startup parameters into its component arguments because
  209. // the service controller is not good enough to do this for us.
  210. // First, find out how many args we have.
  211. //
  212. wparse_cmdline( ResourceEntry->Params.StartupParameters, NULL, NULL, &serviceArgCount, &numchars );
  213. //
  214. // Allocate space for vector and strings
  215. //
  216. serviceArgArray = LocalAlloc( LMEM_FIXED,
  217. serviceArgCount * sizeof(WCHAR *) +
  218. numchars * sizeof(WCHAR) );
  219. if ( serviceArgArray == NULL ) {
  220. status = ERROR_NOT_ENOUGH_MEMORY;
  221. goto error_exit;
  222. }
  223. wparse_cmdline( ResourceEntry->Params.StartupParameters,
  224. serviceArgArray,
  225. (WCHAR *)(((char *)serviceArgArray) + serviceArgCount * sizeof(WCHAR *)),
  226. &serviceArgCount,
  227. &numchars );
  228. } else {
  229. serviceArgCount = 0;
  230. serviceArgArray = NULL;
  231. }
  232. //
  233. // Now open the requested service
  234. //
  235. ResourceEntry->ServiceHandle = OpenService( g_ScHandle,
  236. ResourceEntry->Params.ServiceName,
  237. SERVICE_ALL_ACCESS );
  238. if ( ResourceEntry->ServiceHandle == NULL ) {
  239. status = GetLastError();
  240. ClusResLogSystemEventByKeyData(ResourceEntry->ResourceKey,
  241. LOG_CRITICAL,
  242. RES_GENSVC_OPEN_FAILED,
  243. sizeof(status),
  244. &status);
  245. (g_LogEvent)(
  246. ResourceEntry->ResourceHandle,
  247. LOG_ERROR,
  248. L"Failed to open service, error = %1!u!.\n",
  249. status );
  250. goto error_exit;
  251. }
  252. valueSize = sizeof(QUERY_SERVICE_CONFIG);
  253. AllocSvcConfig:
  254. // Query the service to make sure it is not disabled
  255. lpquerysvcconfig=(LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, valueSize);
  256. if(lpquerysvcconfig==NULL){
  257. status = GetLastError();
  258. (g_LogEvent)(
  259. ResourceEntry->ResourceHandle,
  260. LOG_ERROR,
  261. L"[Gensvc] Failed to allocate memory for query_service_config, error = %1!u!.\n",
  262. status );
  263. goto error_exit;
  264. }
  265. if (!QueryServiceConfig(ResourceEntry->ServiceHandle,
  266. lpquerysvcconfig,
  267. valueSize,
  268. &cbBytesNeeded))
  269. {
  270. status=GetLastError();
  271. if (status != ERROR_INSUFFICIENT_BUFFER){
  272. (g_LogEvent)(ResourceEntry->ResourceHandle,
  273. LOG_ERROR,
  274. L"svc: Failed to query service configuration, error= %1!u!.\n",
  275. status );
  276. goto error_exit;
  277. }
  278. status=ERROR_SUCCESS;
  279. LocalFree(lpquerysvcconfig);
  280. lpquerysvcconfig=NULL;
  281. valueSize = cbBytesNeeded;
  282. goto AllocSvcConfig;
  283. }
  284. if (lpquerysvcconfig->dwStartType == SERVICE_DISABLED)
  285. {
  286. (g_LogEvent)(
  287. ResourceEntry->ResourceHandle,
  288. LOG_ERROR,
  289. L"svc:The service is DISABLED\n");
  290. status=ERROR_SERVICE_DISABLED;
  291. goto error_exit;
  292. }
  293. //
  294. // Make sure service is set to manual start.
  295. //
  296. ChangeServiceConfig( ResourceEntry->ServiceHandle,
  297. SERVICE_NO_CHANGE,
  298. SERVICE_DEMAND_START, // Manual start
  299. SERVICE_NO_CHANGE,
  300. NULL,
  301. NULL,
  302. NULL,
  303. NULL,
  304. NULL,
  305. NULL,
  306. NULL );
  307. //
  308. // if any of the service actions is set to service restart, set it to none
  309. //
  310. if (!(QueryServiceConfig2(ResourceEntry->ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS,
  311. (LPBYTE)&valueSize, sizeof(DWORD), &cbBytesNeeded)))
  312. {
  313. status = GetLastError();
  314. if (status != ERROR_INSUFFICIENT_BUFFER)
  315. {
  316. (g_LogEvent)(
  317. ResourceEntry->ResourceHandle,
  318. LOG_ERROR,
  319. L"svc: Failed to query service configuration for size, error= %1!u!.\n",
  320. status );
  321. goto error_exit;
  322. }
  323. else
  324. status = ERROR_SUCCESS;
  325. }
  326. pSvcFailureActions = (LPSERVICE_FAILURE_ACTIONS)LocalAlloc(LMEM_FIXED, cbBytesNeeded);
  327. if ( pSvcFailureActions == NULL ) {
  328. status = GetLastError();
  329. (g_LogEvent)(
  330. ResourceEntry->ResourceHandle,
  331. LOG_ERROR,
  332. L"[Gensvc] Failed to allocate memory, error = %1!u!.\n",
  333. status );
  334. goto error_exit;
  335. }
  336. if (!(QueryServiceConfig2(ResourceEntry->ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS,
  337. (LPBYTE)pSvcFailureActions, cbBytesNeeded, &cbBytesNeeded)))
  338. {
  339. status = GetLastError();
  340. (g_LogEvent)(
  341. ResourceEntry->ResourceHandle,
  342. LOG_ERROR,
  343. L"[Gensvc] Failed to query service configuration, error = %1!u!.\n",
  344. status );
  345. goto error_exit;
  346. }
  347. for (i=0; i<pSvcFailureActions->cActions;i++)
  348. {
  349. if (pSvcFailureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
  350. pSvcFailureActions->lpsaActions[i].Type = SC_ACTION_NONE;
  351. }
  352. ChangeServiceConfig2(ResourceEntry->ServiceHandle,
  353. SERVICE_CONFIG_FAILURE_ACTIONS,
  354. pSvcFailureActions);
  355. //
  356. // if the resource has a dependent netname and the service should use that
  357. // as the computer name, then build the env. vars that SCM will use to
  358. // augment the normal environment. The hostname APIs will look for these
  359. // vars and report back the netname instead of the actual hostname.
  360. //
  361. if ( ResourceEntry->Params.UseNetworkName )
  362. {
  363. status = ResUtilSetResourceServiceEnvironment(
  364. ResourceEntry->Params.ServiceName,
  365. ResourceEntry->hResource,
  366. g_LogEvent,
  367. ResourceEntry->ResourceHandle);
  368. if ( status != ERROR_SUCCESS )
  369. {
  370. (g_LogEvent)(ResourceEntry->ResourceHandle,
  371. LOG_ERROR,
  372. L"Failed to set service environment. Error: %1!u!.\n",
  373. status);
  374. goto error_exit;
  375. } // if:
  376. }
  377. //
  378. // start it up...
  379. //
  380. if ( !StartServiceW( ResourceEntry->ServiceHandle,
  381. serviceArgCount,
  382. serviceArgArray ) )
  383. {
  384. status = GetLastError();
  385. if (status != ERROR_SERVICE_ALREADY_RUNNING) {
  386. ClusResLogSystemEventByKeyData(ResourceEntry->ResourceKey,
  387. LOG_CRITICAL,
  388. RES_GENSVC_START_FAILED,
  389. sizeof(status),
  390. &status);
  391. (g_LogEvent)(ResourceEntry->ResourceHandle,
  392. LOG_ERROR,
  393. L"Failed to start service. Error: %1!u!.\n",
  394. status );
  395. goto error_exit;
  396. } else {
  397. status = ERROR_SUCCESS;
  398. }
  399. }
  400. //
  401. // wait for the service to comeonline unless we are asked to terminate
  402. //
  403. while (!ClusWorkerCheckTerminate(pWorker) && dwRetryCount--) {
  404. //
  405. // Tell the Resource Monitor that we are still working.
  406. //
  407. resourceStatus.ResourceState = ClusterResourceOnlinePending;
  408. resourceStatus.CheckPoint++;
  409. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  410. &resourceStatus );
  411. resourceStatus.ResourceState = ClusterResourceFailed;
  412. if ( !QueryServiceStatusEx( ResourceEntry->ServiceHandle,
  413. SC_STATUS_PROCESS_INFO, (LPBYTE)&ServiceStatus,
  414. sizeof(SERVICE_STATUS_PROCESS), &cbBytesNeeded ) )
  415. {
  416. status = GetLastError();
  417. (g_LogEvent)(
  418. ResourceEntry->ResourceHandle,
  419. LOG_ERROR,
  420. L"Query Service Status failed %1!u!.\n",
  421. status );
  422. goto error_exit;
  423. }
  424. if ( ServiceStatus.dwCurrentState != SERVICE_START_PENDING ) {
  425. break;
  426. }
  427. Sleep(dwRetryTick);
  428. }
  429. //
  430. // If we terminated the loop above before setting ServiceStatus,
  431. // then return now.
  432. //
  433. if (ClusWorkerCheckTerminate(pWorker) || (dwRetryCount == (DWORD)-1)) {
  434. (g_LogEvent)(
  435. ResourceEntry->ResourceHandle,
  436. LOG_ERROR,
  437. L"GensvcOnlineThread: Asked to terminate or retry period expired...\n");
  438. // Error code choices are:
  439. // ERROR_PROCESS_ABORTED
  440. // ERROR_SERVICE_MARKED_FOR_DELETE
  441. // ERROR_SERVICE_REQUEST_TIMEOUT
  442. // ERROR_SERVICE_START_HANG
  443. // I vote for ERROR_SERVICE_START_HANG
  444. status = ERROR_SERVICE_START_HANG;
  445. goto error_exit;
  446. }
  447. if ( ServiceStatus.dwCurrentState != SERVICE_RUNNING ) {
  448. if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR ) {
  449. status = ServiceStatus.dwServiceSpecificExitCode;
  450. } else {
  451. status = ServiceStatus.dwWin32ExitCode;
  452. }
  453. ClusResLogSystemEventByKeyData(ResourceEntry->ResourceKey,
  454. LOG_CRITICAL,
  455. RES_GENSVC_FAILED_AFTER_START,
  456. sizeof(status),
  457. &status);
  458. (g_LogEvent)(
  459. ResourceEntry->ResourceHandle,
  460. LOG_ERROR,
  461. L"Service failed during initialization. Error: %1!u!.\n",
  462. status );
  463. goto error_exit;
  464. }
  465. //
  466. // we're online. Let resmon know...
  467. //
  468. resourceStatus.ResourceState = ClusterResourceOnline;
  469. if (!(ServiceStatus.dwServiceFlags & SERVICE_RUNS_IN_SYSTEM_PROCESS)) {
  470. ResourceEntry->dwServicePid = ServiceStatus.dwProcessId;
  471. }
  472. (g_LogEvent)(
  473. ResourceEntry->ResourceHandle,
  474. LOG_INFORMATION,
  475. L"Service is now on line.\n" );
  476. error_exit:
  477. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  478. &resourceStatus );
  479. if ( resourceStatus.ResourceState == ClusterResourceOnline ) {
  480. ResourceEntry->Online = TRUE;
  481. } else {
  482. ResourceEntry->Online = FALSE;
  483. }
  484. //cleanup
  485. if (pSvcFailureActions)
  486. LocalFree(pSvcFailureActions);
  487. if (lpquerysvcconfig)
  488. LocalFree(lpquerysvcconfig);
  489. LocalFree( serviceArgArray );
  490. if (Environment != NULL) {
  491. RtlDestroyEnvironment(Environment);
  492. }
  493. return(status);
  494. } // GenSvcOnlineThread
  495. RESID
  496. WINAPI
  497. GenSvcOpen(
  498. IN LPCWSTR ResourceName,
  499. IN HKEY ResourceKey,
  500. IN RESOURCE_HANDLE ResourceHandle
  501. )
  502. /*++
  503. Routine Description:
  504. Open routine for generic service resource.
  505. This routine gets a handle to the service controller, if we don't already have one,
  506. and then gets a handle to the specified service. The service handle is saved
  507. in the GENSVC_RESOURCE structure.
  508. Arguments:
  509. ResourceName - supplies the resource name
  510. ResourceKey - supplies a handle to the resource's cluster registry key
  511. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  512. is called.
  513. Return Value:
  514. RESID of created resource
  515. Zero on failure
  516. --*/
  517. {
  518. RESID svcResid = 0;
  519. DWORD status;
  520. HKEY parametersKey = NULL;
  521. HKEY resKey = NULL;
  522. PGENSVC_RESOURCE resourceEntry = NULL;
  523. DWORD paramNameSize = 0;
  524. DWORD paramNameMaxSize = 0;
  525. HCLUSTER hCluster;
  526. LPWSTR nameOfPropInError;
  527. LPWSTR lpwTemp=NULL;
  528. DWORD cchTempSize = 0;
  529. //
  530. // Open registry parameters key for this resource.
  531. //
  532. status = ClusterRegOpenKey( ResourceKey,
  533. CLUSREG_KEYNAME_PARAMETERS,
  534. KEY_READ,
  535. &parametersKey );
  536. if ( status != NO_ERROR ) {
  537. (g_LogEvent)(
  538. ResourceHandle,
  539. LOG_ERROR,
  540. L"Unable to open parameters key. Error: %1!u!.\n",
  541. status);
  542. goto error_exit;
  543. }
  544. //
  545. // Get a handle to our resource key so that we can get our name later
  546. // if we need to log an event.
  547. //
  548. status = ClusterRegOpenKey( ResourceKey,
  549. L"",
  550. KEY_READ,
  551. &resKey);
  552. if (status != ERROR_SUCCESS) {
  553. (g_LogEvent)(ResourceHandle,
  554. LOG_ERROR,
  555. L"Unable to open resource key. Error: %1!u!.\n",
  556. status );
  557. goto error_exit;
  558. }
  559. //
  560. // First get a handle to the service controller.
  561. //
  562. if ( g_ScHandle == NULL ) {
  563. g_ScHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
  564. if ( g_ScHandle == NULL ) {
  565. status = GetLastError();
  566. (g_LogEvent)(
  567. ResourceHandle,
  568. LOG_ERROR,
  569. L"Failed to open service control manager, error %1!u!.\n",
  570. status);
  571. goto error_exit;
  572. }
  573. }
  574. resourceEntry = LocalAlloc( LMEM_FIXED, sizeof(GENSVC_RESOURCE) );
  575. if ( resourceEntry == NULL ) {
  576. (g_LogEvent)(
  577. ResourceHandle,
  578. LOG_ERROR,
  579. L"Failed to allocate a service info structure.\n");
  580. status = ERROR_NOT_ENOUGH_MEMORY;
  581. goto error_exit;
  582. }
  583. ZeroMemory( resourceEntry, sizeof(GENSVC_RESOURCE) );
  584. resourceEntry->ResourceHandle = ResourceHandle;
  585. resourceEntry->ResourceKey = resKey;
  586. resourceEntry->ParametersKey = parametersKey;
  587. status = ResUtilGetPropertiesToParameterBlock( resourceEntry->ParametersKey,
  588. GenSvcResourcePrivateProperties,
  589. (LPBYTE) &resourceEntry->Params,
  590. TRUE, // CheckForRequiredProperties
  591. &nameOfPropInError );
  592. if ( status == ERROR_SUCCESS ) {
  593. // Create the Semaphore - this will be executed only if this is not a new
  594. // GenericService Type resource being created for the first time
  595. cchTempSize = (lstrlenW(resourceEntry->Params.ServiceName)+
  596. lstrlenW(L"GenSvc$") + 1);
  597. lpwTemp = (LPWSTR)LocalAlloc(LMEM_FIXED, cchTempSize * sizeof(WCHAR) );
  598. if (lpwTemp==NULL)
  599. {
  600. status=GetLastError();
  601. (g_LogEvent)(
  602. ResourceHandle,
  603. LOG_ERROR,
  604. L"Service '%1!ls!': Not enough memory for storing semaphore name. Error: %2!u!.\n",
  605. resourceEntry->Params.ServiceName,
  606. status );
  607. goto error_exit;
  608. }
  609. StringCchCopy(lpwTemp, cchTempSize, L"GenSvc$");
  610. StringCchCat(lpwTemp, cchTempSize, resourceEntry->Params.ServiceName);
  611. resourceEntry->hSem=CreateSemaphore(NULL,0,1,lpwTemp);
  612. status=GetLastError();
  613. if(resourceEntry->hSem)
  614. {
  615. // Check if there is another resource controlling the same service
  616. if(status==ERROR_ALREADY_EXISTS)
  617. {
  618. status = ERROR_OBJECT_ALREADY_EXISTS;
  619. (g_LogEvent)(
  620. ResourceHandle,
  621. LOG_ERROR,
  622. L"Service '%1!ls!' is controlled by another resource. Error: %2!u!.\n",
  623. resourceEntry->Params.ServiceName,
  624. status );
  625. CloseHandle(resourceEntry->hSem);
  626. resourceEntry->hSem = NULL;
  627. goto error_exit;
  628. }
  629. }
  630. else
  631. {
  632. (g_LogEvent)(
  633. ResourceHandle,
  634. LOG_ERROR,
  635. L"Unable to create semaphore for Service '%1!ls!' . Error: %2!u!.\n",
  636. resourceEntry->Params.ServiceName,
  637. status );
  638. goto error_exit;
  639. }
  640. }
  641. else {
  642. (g_LogEvent)(
  643. ResourceHandle,
  644. LOG_ERROR,
  645. L"Unable to read parameters from registry for Service '%1!ls!' . Error: %2!u!, property in error is '%3!ls!' .\n",
  646. resourceEntry->Params.ServiceName,
  647. status,
  648. nameOfPropInError);
  649. }
  650. status = ERROR_SUCCESS;
  651. hCluster = OpenCluster(NULL);
  652. if (hCluster == NULL) {
  653. status = GetLastError();
  654. (g_LogEvent)(
  655. ResourceHandle,
  656. LOG_ERROR,
  657. L"Failed to open cluster, error %1!u!.\n",
  658. status );
  659. goto error_exit;
  660. }
  661. resourceEntry->hResource = OpenClusterResource(hCluster, ResourceName);
  662. status = GetLastError();
  663. CloseCluster(hCluster);
  664. if ( resourceEntry->hResource == NULL ) {
  665. (g_LogEvent)(
  666. ResourceHandle,
  667. LOG_ERROR,
  668. L"Failed to open resource, error %1!u!.\n", status );
  669. goto error_exit;
  670. }
  671. svcResid = (RESID)resourceEntry;
  672. if (lpwTemp) {
  673. LocalFree(lpwTemp);
  674. }
  675. return(svcResid);
  676. error_exit:
  677. if ( parametersKey != NULL ) {
  678. ClusterRegCloseKey( parametersKey );
  679. }
  680. if ( resKey != NULL) {
  681. ClusterRegCloseKey( resKey );
  682. }
  683. if ( resourceEntry != NULL) {
  684. LocalFree( resourceEntry );
  685. }
  686. if (lpwTemp) {
  687. LocalFree(lpwTemp);
  688. }
  689. SetLastError( status );
  690. return((RESID)NULL);
  691. } // GenSvcOpen
  692. DWORD
  693. WINAPI
  694. GenSvcOnline(
  695. IN RESID ResourceId,
  696. IN OUT PHANDLE EventHandle
  697. )
  698. /*++
  699. Routine Description:
  700. Online routine for Generic Service resource.
  701. Arguments:
  702. ResourceId - Supplies resource id to be brought online
  703. EventHandle - Supplies a pointer to a handle to signal on error.
  704. Return Value:
  705. ERROR_SUCCESS if successful.
  706. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  707. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  708. acquire 'ownership'.
  709. Win32 error code if other failure.
  710. --*/
  711. {
  712. DWORD status;
  713. PGENSVC_RESOURCE resourceEntry;
  714. resourceEntry = (PGENSVC_RESOURCE)ResourceId;
  715. if ( resourceEntry == NULL ) {
  716. DBG_PRINT( "GenSvc: Online request for a nonexistent resource id 0x%p.\n",
  717. ResourceId );
  718. return(ERROR_RESOURCE_NOT_FOUND);
  719. }
  720. ClusWorkerTerminate( &resourceEntry->PendingThread );
  721. status = ClusWorkerCreate( &resourceEntry->PendingThread,
  722. GenSvcOnlineThread,
  723. resourceEntry );
  724. if ( status == ERROR_SUCCESS ) {
  725. status = ERROR_IO_PENDING;
  726. }
  727. return(status);
  728. } // GenSvcOnline
  729. VOID
  730. WINAPI
  731. GenSvcTerminate(
  732. IN RESID ResourceId
  733. )
  734. /*++
  735. Routine Description:
  736. Terminate routine for Generic Application resource.
  737. Arguments:
  738. ResourceId - Supplies resource id to be terminated
  739. Return Value:
  740. None.
  741. --*/
  742. {
  743. SERVICE_STATUS ServiceStatus;
  744. PGENSVC_RESOURCE resourceEntry;
  745. resourceEntry = (PGENSVC_RESOURCE)ResourceId;
  746. if ( resourceEntry == NULL ) {
  747. DBG_PRINT( "GenSvc: Terminate request for a nonexistent resource id 0x%p.\n",
  748. ResourceId );
  749. return;
  750. }
  751. (g_LogEvent)(
  752. resourceEntry->ResourceHandle,
  753. LOG_INFORMATION,
  754. L"Terminate request.\n" );
  755. #ifdef TEST_TERMINATE_ON_SHUTDOWN
  756. {
  757. DWORD dwStatus;
  758. BOOLEAN fWasEnabled;
  759. //
  760. // Test terminate on shutdown code.
  761. //
  762. (g_LogEvent)(
  763. resourceEntry->ResourceHandle,
  764. LOG_ERROR,
  765. L"GenSvcTerminate: TEST_TERMINATE_ON_SHUTDOWN - enabling shutdown privilege.\n"
  766. );
  767. dwStatus = ClRtlEnableThreadPrivilege(
  768. SE_SHUTDOWN_PRIVILEGE,
  769. &fWasEnabled
  770. );
  771. if ( dwStatus != ERROR_SUCCESS ) {
  772. (g_LogEvent)(
  773. resourceEntry->ResourceHandle,
  774. LOG_ERROR,
  775. L"GetSvcTerminate: TEST_TERMINATE_ON_SHUTDOWN - Unable to enable shutdown privilege. Error: %1!u!...\n",
  776. dwStatus
  777. );
  778. } else {
  779. AbortSystemShutdown( NULL );
  780. (g_LogEvent)(
  781. resourceEntry->ResourceHandle,
  782. LOG_ERROR,
  783. L"GenSvcTerminate: TEST_TERMINATE_ON_SHUTDOWN - initiating system shutdown.\n"
  784. );
  785. if ( ! InitiateSystemShutdown(
  786. NULL, // lpMachineName
  787. L"Testing Generic Service cluster resource DLL",
  788. 0, // dwTimeout
  789. TRUE, // bForceAppsClosed
  790. TRUE // bRebootAfterShutdown
  791. ) ) {
  792. dwStatus = GetLastError();
  793. (g_LogEvent)(
  794. resourceEntry->ResourceHandle,
  795. LOG_ERROR,
  796. L"GenSvcTerminate: TEST_TERMINATE_ON_SHUTDOWN - Unable to shutdown the system. Error: %1!u!.\n",
  797. dwStatus
  798. );
  799. } else {
  800. Sleep( 30000 );
  801. }
  802. ClRtlRestoreThreadPrivilege(
  803. SE_SHUTDOWN_PRIVILEGE,
  804. fWasEnabled
  805. );
  806. }
  807. }
  808. #endif
  809. //if there is a pending thread close it
  810. //if the online pending thread is active, the service may be online
  811. //if the offline pending thread is active, the service might be offline
  812. ClusWorkerTerminate( &resourceEntry->PendingThread );
  813. //if the service isnt gone by now, terminate it forcibly
  814. if ( resourceEntry->ServiceHandle != NULL )
  815. {
  816. DWORD dwRetryCount= 100;
  817. BOOL didStop = FALSE;
  818. DWORD dwRetryTick = 300; // 300 msec at a time
  819. DWORD dwStatus;
  820. while (dwRetryCount--)
  821. {
  822. (g_LogEvent)(
  823. resourceEntry->ResourceHandle,
  824. LOG_INFORMATION,
  825. L"GenSvcTerminate : calling SCM (didStop=%1!d!)\n",
  826. didStop
  827. );
  828. dwStatus = (ControlService(
  829. resourceEntry->ServiceHandle,
  830. (didStop
  831. ? SERVICE_CONTROL_INTERROGATE
  832. : SERVICE_CONTROL_STOP),
  833. &ServiceStatus )
  834. ? NO_ERROR
  835. : GetLastError());
  836. if (dwStatus == NO_ERROR)
  837. {
  838. didStop = TRUE;
  839. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED)
  840. {
  841. (g_LogEvent)(
  842. resourceEntry->ResourceHandle,
  843. LOG_INFORMATION,
  844. L"Service stopped.\n" );
  845. //set the status
  846. resourceEntry->Online = FALSE;
  847. resourceEntry->dwServicePid = 0;
  848. break;
  849. }
  850. }
  851. //
  852. // Chittur Subbaraman (chitturs) - 2/21/2000
  853. //
  854. // Since SCM doesn't accept any control requests during
  855. // windows shutdown, don't send any more control
  856. // requests. Just exit from this loop and terminate
  857. // the process brute force.
  858. //
  859. if ( dwStatus == ERROR_SHUTDOWN_IN_PROGRESS )
  860. {
  861. (g_LogEvent)(
  862. resourceEntry->ResourceHandle,
  863. LOG_INFORMATION,
  864. L"System shutdown in progress. Will try to terminate process brute force...\n" );
  865. break;
  866. }
  867. if (dwStatus == ERROR_EXCEPTION_IN_SERVICE ||
  868. dwStatus == ERROR_PROCESS_ABORTED ||
  869. dwStatus == ERROR_SERVICE_NOT_ACTIVE)
  870. {
  871. (g_LogEvent)(
  872. resourceEntry->ResourceHandle,
  873. LOG_INFORMATION,
  874. L"Service died; status = %1!u!.\n",
  875. dwStatus);
  876. //set the status
  877. resourceEntry->Online = FALSE;
  878. resourceEntry->dwServicePid = 0;
  879. break;
  880. }
  881. (g_LogEvent)(
  882. resourceEntry->ResourceHandle,
  883. LOG_INFORMATION,
  884. L"GenSvcTerminate: retrying...\n" );
  885. Sleep(dwRetryTick);
  886. }
  887. //declare this service is offline
  888. //if there is a pid for this, try and terminate that process
  889. //note that terminating a process doesnt terminate all
  890. //the child processes
  891. //also if it is running in a system process, we do nothing
  892. //about it
  893. if (resourceEntry->dwServicePid)
  894. {
  895. DWORD dwResourceState;
  896. (g_LogEvent)(
  897. resourceEntry->ResourceHandle,
  898. LOG_INFORMATION,
  899. L"GenSvcTerminate: Attempting to terminate process with pid=%1!u!...\n",
  900. resourceEntry->dwServicePid );
  901. ResUtilTerminateServiceProcessFromResDll( resourceEntry->dwServicePid,
  902. FALSE, // bOffline
  903. &dwResourceState,
  904. g_LogEvent,
  905. resourceEntry->ResourceHandle );
  906. }
  907. CloseServiceHandle( resourceEntry->ServiceHandle );
  908. resourceEntry->ServiceHandle = NULL;
  909. resourceEntry->dwServicePid = 0;
  910. }
  911. //
  912. // finally, clean up the Environment key for this service if we were
  913. // substituting the netname for the hostname.
  914. //
  915. if ( resourceEntry->Params.UseNetworkName )
  916. {
  917. ResUtilRemoveResourceServiceEnvironment(resourceEntry->Params.ServiceName,
  918. g_LogEvent,
  919. resourceEntry->ResourceHandle);
  920. }
  921. resourceEntry->Online = FALSE;
  922. return;
  923. } // GenSvcTerminate
  924. DWORD
  925. WINAPI
  926. GenSvcOffline(
  927. IN RESID ResourceId
  928. )
  929. /*++
  930. Routine Description:
  931. Offline routine for Generic Service resource.
  932. Arguments:
  933. ResourceId - Supplies the resource to be taken offline
  934. Return Value:
  935. ERROR_SUCCESS - always successful.
  936. --*/
  937. {
  938. PGENSVC_RESOURCE resourceEntry;
  939. DWORD status;
  940. resourceEntry = (PGENSVC_RESOURCE)ResourceId;
  941. if ( resourceEntry == NULL ) {
  942. DBG_PRINT( "GenSvc: Offline request for a nonexistent resource id 0x%p.\n",
  943. ResourceId );
  944. return(ERROR_RESOURCE_NOT_FOUND);
  945. }
  946. ClusWorkerTerminate( &resourceEntry->PendingThread );
  947. status = ClusWorkerCreate( &resourceEntry->PendingThread,
  948. GenSvcOfflineThread,
  949. resourceEntry );
  950. if ( status == ERROR_SUCCESS ) {
  951. status = ERROR_IO_PENDING;
  952. }
  953. return(status);
  954. } // GenSvcOffline
  955. DWORD
  956. GenSvcOfflineThread(
  957. PCLUS_WORKER pWorker,
  958. IN PGENSVC_RESOURCE ResourceEntry
  959. )
  960. /*++
  961. Routine Description:
  962. Brings a generic resource offline
  963. Arguments:
  964. Worker - Supplies the worker structure
  965. Context - A pointer to the DiskInfo block for this resource.
  966. Returns:
  967. ERROR_SUCCESS if successful.
  968. Win32 error code on failure.
  969. --*/
  970. {
  971. RESOURCE_STATUS resourceStatus;
  972. DWORD retryTick = 300; // 300 msec at a time
  973. DWORD status = ERROR_SUCCESS;
  974. BOOL didStop = FALSE;
  975. SERVICE_STATUS ServiceStatus;
  976. DWORD dwRetryCount = 2000; // Try 10 min max.
  977. ResUtilInitializeResourceStatus( &resourceStatus );
  978. resourceStatus.ResourceState = ClusterResourceFailed;
  979. resourceStatus.CheckPoint = 1;
  980. //check if the service has gone offline or was never brought online
  981. if ( ResourceEntry->ServiceHandle == NULL )
  982. {
  983. resourceStatus.ResourceState = ClusterResourceOffline;
  984. goto FnExit;
  985. }
  986. //try to stop the target service. wait for it to be terminated
  987. //as long as we are not asked to terminate
  988. while (!ClusWorkerCheckTerminate(pWorker) && dwRetryCount--) {
  989. //
  990. // Tell the Resource Monitor that we are still working.
  991. //
  992. resourceStatus.ResourceState = ClusterResourceOfflinePending;
  993. resourceStatus.CheckPoint++;
  994. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  995. &resourceStatus );
  996. resourceStatus.ResourceState = ClusterResourceFailed;
  997. //
  998. // Request that the service be stopped, or if we already did that,
  999. // request the current status of the service.
  1000. //
  1001. status = (ControlService(
  1002. ResourceEntry->ServiceHandle,
  1003. (didStop
  1004. ? SERVICE_CONTROL_INTERROGATE
  1005. : SERVICE_CONTROL_STOP),
  1006. &ServiceStatus )
  1007. ? NO_ERROR
  1008. : GetLastError());
  1009. if (status == NO_ERROR) {
  1010. didStop = TRUE;
  1011. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
  1012. (g_LogEvent)(
  1013. ResourceEntry->ResourceHandle,
  1014. LOG_INFORMATION,
  1015. L"Service stopped.\n" );
  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. }
  1029. if (status == ERROR_EXCEPTION_IN_SERVICE ||
  1030. status == ERROR_PROCESS_ABORTED ||
  1031. status == ERROR_SERVICE_NOT_ACTIVE) {
  1032. (g_LogEvent)(
  1033. ResourceEntry->ResourceHandle,
  1034. LOG_INFORMATION,
  1035. L"Service died or not active any more; status = %1!u!.\n",
  1036. status);
  1037. //set the status
  1038. ResourceEntry->Online = FALSE;
  1039. resourceStatus.ResourceState = ClusterResourceOffline;
  1040. CloseServiceHandle( ResourceEntry->ServiceHandle );
  1041. ResourceEntry->ServiceHandle = NULL;
  1042. ResourceEntry->dwServicePid = 0;
  1043. (g_LogEvent)(
  1044. ResourceEntry->ResourceHandle,
  1045. LOG_INFORMATION,
  1046. L"Service is now offline.\n" );
  1047. break;
  1048. }
  1049. //
  1050. // Chittur Subbaraman (chitturs) - 2/21/2000
  1051. //
  1052. // Handle the case in which the SCM refuses to accept control
  1053. // requests since windows is shutting down.
  1054. //
  1055. if ( status == ERROR_SHUTDOWN_IN_PROGRESS )
  1056. {
  1057. DWORD dwResourceState;
  1058. (g_LogEvent)(
  1059. ResourceEntry->ResourceHandle,
  1060. LOG_INFORMATION,
  1061. L"GenSvcOfflineThread: System shutting down. Attempt to terminate service process %1!u!...\n",
  1062. ResourceEntry->dwServicePid );
  1063. status = ResUtilTerminateServiceProcessFromResDll( ResourceEntry->dwServicePid,
  1064. TRUE, // bOffline
  1065. &dwResourceState,
  1066. g_LogEvent,
  1067. ResourceEntry->ResourceHandle );
  1068. if ( status == ERROR_SUCCESS )
  1069. {
  1070. CloseServiceHandle( ResourceEntry->ServiceHandle );
  1071. ResourceEntry->ServiceHandle = NULL;
  1072. ResourceEntry->dwServicePid = 0;
  1073. ResourceEntry->Online = FALSE;
  1074. }
  1075. resourceStatus.ResourceState = dwResourceState;
  1076. break;
  1077. }
  1078. (g_LogEvent)(
  1079. ResourceEntry->ResourceHandle,
  1080. LOG_INFORMATION,
  1081. L"Offline: retrying...\n" );
  1082. Sleep(retryTick);
  1083. }
  1084. //
  1085. // clean up the netname Environment in the registry if necessary
  1086. //
  1087. if ( ResourceEntry->Params.UseNetworkName )
  1088. {
  1089. ResUtilRemoveResourceServiceEnvironment(ResourceEntry->Params.ServiceName,
  1090. g_LogEvent,
  1091. ResourceEntry->ResourceHandle);
  1092. }
  1093. FnExit:
  1094. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  1095. &resourceStatus );
  1096. return(status);
  1097. } // GenSvcOfflineThread
  1098. BOOL
  1099. WINAPI
  1100. GenSvcIsAlive(
  1101. IN RESID ResourceId
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. IsAlive routine for Generic service resource.
  1106. Arguments:
  1107. ResourceId - Supplies the resource id to be polled.
  1108. Return Value:
  1109. TRUE - if service is running
  1110. FALSE - if service is in any other state
  1111. --*/
  1112. {
  1113. return( VerifyService( ResourceId, TRUE ) );
  1114. } // GenSvcIsAlive
  1115. BOOL
  1116. VerifyService(
  1117. IN RESID ResourceId,
  1118. IN BOOL IsAliveFlag
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. Verify that a specified service is running
  1123. Arguments:
  1124. ResourceId - Supplies the resource id
  1125. IsAliveFlag - Says this is an IsAlive call - used only for debug print
  1126. Return Value:
  1127. TRUE - if service is running or starting
  1128. FALSE - service is in any other state
  1129. --*/
  1130. {
  1131. SERVICE_STATUS ServiceStatus;
  1132. PGENSVC_RESOURCE resourceEntry;
  1133. DWORD status = TRUE;
  1134. resourceEntry = (PGENSVC_RESOURCE)ResourceId;
  1135. if ( resourceEntry == NULL ) {
  1136. DBG_PRINT( "GenSvc: IsAlive request for a nonexistent resource id 0x%p.\n",
  1137. ResourceId );
  1138. return(FALSE);
  1139. }
  1140. #ifdef TEST_TERMINATE_ON_SHUTDOWN
  1141. //
  1142. // Test terminate on shutdown.
  1143. //
  1144. if ( IsAliveFlag ) {
  1145. (g_LogEvent)(
  1146. resourceEntry->ResourceHandle,
  1147. LOG_ERROR,
  1148. L"GenSvcIsAlive: TEST_TERMINATE_ON_SHUTDOWN - Artificially failing IsAlive call.\n",
  1149. GetLastError() );
  1150. return FALSE;
  1151. }
  1152. #endif
  1153. if ( !QueryServiceStatus( resourceEntry->ServiceHandle,
  1154. &ServiceStatus ) ) {
  1155. (g_LogEvent)(
  1156. resourceEntry->ResourceHandle,
  1157. LOG_ERROR,
  1158. L"Query Service Status failed %1!u!.\n",
  1159. GetLastError() );
  1160. return(FALSE);
  1161. }
  1162. //
  1163. // Now check the status of the service
  1164. //
  1165. if ( (ServiceStatus.dwCurrentState != SERVICE_RUNNING) &&
  1166. (ServiceStatus.dwCurrentState != SERVICE_START_PENDING) ) {
  1167. status = FALSE;
  1168. }
  1169. if (!status) {
  1170. (g_LogEvent)(
  1171. resourceEntry->ResourceHandle,
  1172. LOG_ERROR,
  1173. L"Failed the IsAlive test. Current State is %1!u!.\n",
  1174. ServiceStatus.dwCurrentState );
  1175. }
  1176. return(status);
  1177. } // Verify Service
  1178. BOOL
  1179. WINAPI
  1180. GenSvcLooksAlive(
  1181. IN RESID ResourceId
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. LooksAlive routine for Generic Service resource.
  1186. Arguments:
  1187. ResourceId - Supplies the resource id to be polled.
  1188. Return Value:
  1189. TRUE - Resource looks like it is alive and well
  1190. FALSE - Resource looks like it is toast.
  1191. --*/
  1192. {
  1193. return( VerifyService( ResourceId, FALSE ) );
  1194. } // GenSvcLooksAlive
  1195. VOID
  1196. WINAPI
  1197. GenSvcClose(
  1198. IN RESID ResourceId
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. Close routine for Generic Applications resource.
  1203. This routine will stop the service, and delete the cluster
  1204. information regarding that service.
  1205. Arguments:
  1206. ResourceId - Supplies resource id to be closed
  1207. Return Value:
  1208. None.
  1209. --*/
  1210. {
  1211. PGENSVC_RESOURCE resourceEntry;
  1212. resourceEntry = (PGENSVC_RESOURCE)ResourceId;
  1213. if ( resourceEntry == NULL ) {
  1214. DBG_PRINT( "GenSvc: Close request for a nonexistent resource id 0x%p\n",
  1215. ResourceId );
  1216. return;
  1217. }
  1218. (g_LogEvent)(
  1219. resourceEntry->ResourceHandle,
  1220. LOG_INFORMATION,
  1221. L"Close request.\n" );
  1222. //
  1223. // Shut it down if it's on line
  1224. //
  1225. GenSvcTerminate( ResourceId );
  1226. ResUtilFreeParameterBlock( (LPBYTE) &(resourceEntry->Params),
  1227. NULL,
  1228. GenSvcResourcePrivateProperties );
  1229. ClusterRegCloseKey( resourceEntry->ParametersKey );
  1230. ClusterRegCloseKey( resourceEntry->ResourceKey );
  1231. CloseClusterResource( resourceEntry->hResource );
  1232. CloseHandle(resourceEntry->hSem);
  1233. LocalFree( resourceEntry );
  1234. } // GenSvcClose
  1235. //
  1236. // Following logic stolen from the CRTs so that our command line parsing
  1237. // works the same as the standard CRT parsing.
  1238. //
  1239. void
  1240. wparse_cmdline (
  1241. WCHAR *cmdstart,
  1242. WCHAR **argv,
  1243. WCHAR *args,
  1244. int *numargs,
  1245. int *numchars
  1246. )
  1247. {
  1248. WCHAR *p;
  1249. WCHAR c;
  1250. int inquote; /* 1 = inside quotes */
  1251. int copychar; /* 1 = copy char to *args */
  1252. unsigned numslash; /* num of backslashes seen */
  1253. *numchars = 0;
  1254. *numargs = 0;
  1255. p = cmdstart;
  1256. inquote = 0;
  1257. /* loop on each argument */
  1258. for(;;) {
  1259. if ( *p ) {
  1260. while (*p == L' ' || *p == L'\t')
  1261. ++p;
  1262. }
  1263. if (*p == L'\0')
  1264. break; /* end of args */
  1265. /* scan an argument */
  1266. if (argv)
  1267. *argv++ = args; /* store ptr to arg */
  1268. ++*numargs;
  1269. /* loop through scanning one argument */
  1270. for (;;) {
  1271. copychar = 1;
  1272. /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
  1273. 2N+1 backslashes + " ==> N backslashes + literal "
  1274. N backslashes ==> N backslashes */
  1275. numslash = 0;
  1276. while (*p == L'\\') {
  1277. /* count number of backslashes for use below */
  1278. ++p;
  1279. ++numslash;
  1280. }
  1281. if (*p == L'\"') {
  1282. /* if 2N backslashes before, start/end quote, otherwise
  1283. copy literally */
  1284. if (numslash % 2 == 0) {
  1285. if (inquote) {
  1286. if (p[1] == L'\"')
  1287. p++; /* Double quote inside quoted string */
  1288. else /* skip first quote char and copy second */
  1289. copychar = 0;
  1290. } else
  1291. copychar = 0; /* don't copy quote */
  1292. inquote = !inquote;
  1293. }
  1294. numslash /= 2; /* divide numslash by two */
  1295. }
  1296. /* copy slashes */
  1297. while (numslash--) {
  1298. if (args)
  1299. *args++ = L'\\';
  1300. ++*numchars;
  1301. }
  1302. /* if at end of arg, break loop */
  1303. if (*p == L'\0' || (!inquote && (*p == L' ' || *p == L'\t')))
  1304. break;
  1305. /* copy character into argument */
  1306. if (copychar) {
  1307. if (args)
  1308. *args++ = *p;
  1309. ++*numchars;
  1310. }
  1311. ++p;
  1312. }
  1313. /* null-terminate the argument */
  1314. if (args)
  1315. *args++ = L'\0'; /* terminate string */
  1316. ++*numchars;
  1317. }
  1318. } // wparse_cmdline
  1319. DWORD
  1320. GenSvcResourceControl(
  1321. IN RESID ResourceId,
  1322. IN DWORD ControlCode,
  1323. IN PVOID InBuffer,
  1324. IN DWORD InBufferSize,
  1325. OUT PVOID OutBuffer,
  1326. IN DWORD OutBufferSize,
  1327. OUT LPDWORD BytesReturned
  1328. )
  1329. /*++
  1330. Routine Description:
  1331. ResourceControl routine for Generic Service resources.
  1332. Perform the control request specified by ControlCode on the specified
  1333. resource.
  1334. Arguments:
  1335. ResourceId - Supplies the resource id for the specific resource.
  1336. ControlCode - Supplies the control code that defines the action
  1337. to be performed.
  1338. InBuffer - Supplies a pointer to a buffer containing input data.
  1339. InBufferSize - Supplies the size, in bytes, of the data pointed
  1340. to by InBuffer.
  1341. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1342. OutBufferSize - Supplies the size, in bytes, of the available space
  1343. pointed to by OutBuffer.
  1344. BytesReturned - Returns the number of bytes of OutBuffer actually
  1345. filled in by the resource. If OutBuffer is too small, BytesReturned
  1346. contains the total number of bytes for the operation to succeed.
  1347. Return Value:
  1348. ERROR_SUCCESS - The function completed successfully.
  1349. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1350. In some cases, this allows the cluster software to perform the work.
  1351. Win32 error code - The function failed.
  1352. --*/
  1353. {
  1354. DWORD status;
  1355. PGENSVC_RESOURCE resourceEntry;
  1356. DWORD required;
  1357. resourceEntry = (PGENSVC_RESOURCE)ResourceId;
  1358. if ( resourceEntry == NULL ) {
  1359. DBG_PRINT( "GenSvc: ResourceControl request for a nonexistent resource id 0x%p\n",
  1360. ResourceId );
  1361. return(FALSE);
  1362. }
  1363. switch ( ControlCode ) {
  1364. case CLUSCTL_RESOURCE_UNKNOWN:
  1365. *BytesReturned = 0;
  1366. status = ERROR_SUCCESS;
  1367. break;
  1368. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
  1369. status = ResUtilGetPropertyFormats( GenSvcResourcePrivateProperties,
  1370. OutBuffer,
  1371. OutBufferSize,
  1372. BytesReturned,
  1373. &required );
  1374. if ( status == ERROR_MORE_DATA ) {
  1375. *BytesReturned = required;
  1376. }
  1377. break;
  1378. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  1379. status = ResUtilEnumProperties( GenSvcResourcePrivateProperties,
  1380. OutBuffer,
  1381. OutBufferSize,
  1382. BytesReturned,
  1383. &required );
  1384. if ( status == ERROR_MORE_DATA ) {
  1385. *BytesReturned = required;
  1386. }
  1387. break;
  1388. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  1389. status = GenSvcGetPrivateResProperties( resourceEntry,
  1390. OutBuffer,
  1391. OutBufferSize,
  1392. BytesReturned );
  1393. break;
  1394. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  1395. status = GenSvcValidatePrivateResProperties( resourceEntry,
  1396. InBuffer,
  1397. InBufferSize,
  1398. NULL );
  1399. break;
  1400. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  1401. status = GenSvcSetPrivateResProperties( resourceEntry,
  1402. InBuffer,
  1403. InBufferSize );
  1404. break;
  1405. default:
  1406. status = ERROR_INVALID_FUNCTION;
  1407. break;
  1408. }
  1409. return(status);
  1410. } // GenSvcResourceControl
  1411. DWORD
  1412. GenSvcResourceTypeControl(
  1413. IN LPCWSTR ResourceTypeName,
  1414. IN DWORD ControlCode,
  1415. IN PVOID InBuffer,
  1416. IN DWORD InBufferSize,
  1417. OUT PVOID OutBuffer,
  1418. IN DWORD OutBufferSize,
  1419. OUT LPDWORD BytesReturned
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. ResourceTypeControl routine for Generic Service resources.
  1424. Perform the control request specified by ControlCode on this resource type.
  1425. Arguments:
  1426. ResourceTypeName - Supplies the resource type name.
  1427. ControlCode - Supplies the control code that defines the action
  1428. to be performed.
  1429. InBuffer - Supplies a pointer to a buffer containing input data.
  1430. InBufferSize - Supplies the size, in bytes, of the data pointed
  1431. to by InBuffer.
  1432. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1433. OutBufferSize - Supplies the size, in bytes, of the available space
  1434. pointed to by OutBuffer.
  1435. BytesReturned - Returns the number of bytes of OutBuffer actually
  1436. filled in by the resource. If OutBuffer is too small, BytesReturned
  1437. contains the total number of bytes for the operation to succeed.
  1438. Return Value:
  1439. ERROR_SUCCESS - The function completed successfully.
  1440. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1441. In some cases, this allows the cluster software to perform the work.
  1442. Win32 error code - The function failed.
  1443. --*/
  1444. {
  1445. DWORD status;
  1446. DWORD required;
  1447. switch ( ControlCode ) {
  1448. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  1449. *BytesReturned = 0;
  1450. status = ERROR_SUCCESS;
  1451. break;
  1452. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
  1453. status = ResUtilGetPropertyFormats( GenSvcResourcePrivateProperties,
  1454. OutBuffer,
  1455. OutBufferSize,
  1456. BytesReturned,
  1457. &required );
  1458. if ( status == ERROR_MORE_DATA ) {
  1459. *BytesReturned = required;
  1460. }
  1461. break;
  1462. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  1463. status = ResUtilEnumProperties( GenSvcResourcePrivateProperties,
  1464. OutBuffer,
  1465. OutBufferSize,
  1466. BytesReturned,
  1467. &required );
  1468. if ( status == ERROR_MORE_DATA ) {
  1469. *BytesReturned = required;
  1470. }
  1471. break;
  1472. default:
  1473. status = ERROR_INVALID_FUNCTION;
  1474. break;
  1475. }
  1476. return(status);
  1477. } // GenSvcResourceTypeControl
  1478. DWORD
  1479. GenSvcGetPrivateResProperties(
  1480. IN const PGENSVC_RESOURCE ResourceEntry,
  1481. OUT PVOID OutBuffer,
  1482. IN DWORD OutBufferSize,
  1483. OUT LPDWORD BytesReturned
  1484. )
  1485. /*++
  1486. Routine Description:
  1487. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
  1488. for resources of type Generic Service.
  1489. Arguments:
  1490. ResourceEntry - Supplies the resource entry on which to operate.
  1491. OutBuffer - Returns the output data.
  1492. OutBufferSize - Supplies the size, in bytes, of the data pointed
  1493. to by OutBuffer.
  1494. BytesReturned - The number of bytes returned in OutBuffer.
  1495. Return Value:
  1496. ERROR_SUCCESS - The function completed successfully.
  1497. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1498. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1499. Win32 error code - The function failed.
  1500. --*/
  1501. {
  1502. DWORD status;
  1503. DWORD required;
  1504. status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  1505. GenSvcResourcePrivateProperties,
  1506. OutBuffer,
  1507. OutBufferSize,
  1508. BytesReturned,
  1509. &required );
  1510. if ( status == ERROR_MORE_DATA ) {
  1511. *BytesReturned = required;
  1512. }
  1513. return(status);
  1514. } // GenSvcGetPrivateResProperties
  1515. DWORD
  1516. GenSvcValidatePrivateResProperties(
  1517. IN const PGENSVC_RESOURCE ResourceEntry,
  1518. IN const PVOID InBuffer,
  1519. IN DWORD InBufferSize,
  1520. OUT PGENSVC_PARAMS Params
  1521. )
  1522. /*++
  1523. Routine Description:
  1524. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  1525. function for resources of type Generic Service.
  1526. Arguments:
  1527. ResourceEntry - Supplies the resource entry on which to operate.
  1528. InBuffer - Supplies a pointer to a buffer containing input data.
  1529. InBufferSize - Supplies the size, in bytes, of the data pointed
  1530. to by InBuffer.
  1531. Params - Supplies the parameter block to fill in.
  1532. Return Value:
  1533. ERROR_SUCCESS - The function completed successfully.
  1534. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1535. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1536. ERROR_DEPENDENCY_NOT_FOUND - Trying to set UseNetworkName when there
  1537. is no dependency on a Network Name resource.
  1538. Win32 error code - The function failed.
  1539. --*/
  1540. {
  1541. DWORD status;
  1542. GENSVC_PARAMS currentProps;
  1543. GENSVC_PARAMS newProps;
  1544. PGENSVC_PARAMS pParams = NULL;
  1545. BOOL hResDependency;
  1546. LPWSTR lpwTemp=NULL;
  1547. DWORD cchTempSize = 0;
  1548. LPWSTR nameOfPropInError;
  1549. WCHAR netnameBuffer[ MAX_PATH + 1 ];
  1550. DWORD netnameBufferSize = sizeof( netnameBuffer ) / sizeof( WCHAR );
  1551. //
  1552. // Check if there is input data.
  1553. //
  1554. if ( (InBuffer == NULL) ||
  1555. (InBufferSize < sizeof(DWORD)) ) {
  1556. return(ERROR_INVALID_DATA);
  1557. }
  1558. //
  1559. // Retrieve the current set of private properties from the
  1560. // cluster database.
  1561. //
  1562. ZeroMemory( &currentProps, sizeof(currentProps) );
  1563. status = ResUtilGetPropertiesToParameterBlock(
  1564. ResourceEntry->ParametersKey,
  1565. GenSvcResourcePrivateProperties,
  1566. (LPBYTE) &currentProps,
  1567. FALSE, /*CheckForRequiredProperties*/
  1568. &nameOfPropInError
  1569. );
  1570. if ( status != ERROR_SUCCESS ) {
  1571. (g_LogEvent)(
  1572. ResourceEntry->ResourceHandle,
  1573. LOG_ERROR,
  1574. L"Unable to read the '%1!ls!' property. Error: %2!u!.\n",
  1575. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  1576. status
  1577. );
  1578. goto FnExit;
  1579. }
  1580. //
  1581. // Duplicate the resource parameter block.
  1582. //
  1583. if ( Params == NULL ) {
  1584. pParams = &newProps;
  1585. } else {
  1586. pParams = Params;
  1587. }
  1588. ZeroMemory( pParams, sizeof(GENSVC_PARAMS) );
  1589. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1590. (LPBYTE) &currentProps,
  1591. GenSvcResourcePrivateProperties
  1592. );
  1593. if ( status != ERROR_SUCCESS ) {
  1594. return(status);
  1595. }
  1596. //
  1597. // Parse and validate the properties.
  1598. //
  1599. status = ResUtilVerifyPropertyTable( GenSvcResourcePrivateProperties,
  1600. NULL,
  1601. TRUE, // Allow unknowns
  1602. InBuffer,
  1603. InBufferSize,
  1604. (LPBYTE) pParams
  1605. );
  1606. if ( status != ERROR_SUCCESS ) {
  1607. goto FnExit;
  1608. }
  1609. //
  1610. // Validate the parameter values.
  1611. //
  1612. status = GenSvcIsValidService( ResourceEntry, pParams->ServiceName );
  1613. if ( status != ERROR_SUCCESS ) {
  1614. goto FnExit;
  1615. }
  1616. //
  1617. // If the resource should use the network name as the computer
  1618. // name, make sure there is a dependency on a Network Name
  1619. // resource.
  1620. //
  1621. if ( pParams->UseNetworkName ) {
  1622. hResDependency = GetClusterResourceNetworkName( ResourceEntry->hResource,
  1623. netnameBuffer,
  1624. &netnameBufferSize
  1625. );
  1626. if ( ! hResDependency ) {
  1627. status = ERROR_DEPENDENCY_NOT_FOUND;
  1628. }
  1629. }
  1630. if ( status != ERROR_SUCCESS ) {
  1631. goto FnExit;
  1632. }
  1633. if ( ResourceEntry->hSem == NULL ) {
  1634. // This is executed only if this is a new resource being created
  1635. cchTempSize = (lstrlenW(pParams->ServiceName) +
  1636. lstrlenW(L"GenSvc$") + 1);
  1637. lpwTemp = (LPWSTR)LocalAlloc(LMEM_FIXED, cchTempSize * sizeof(WCHAR) );
  1638. if ( lpwTemp == NULL ) {
  1639. status = GetLastError();
  1640. (g_LogEvent)(
  1641. ResourceEntry->ResourceHandle,
  1642. LOG_ERROR,
  1643. L"Service '%1!ls!': Not enough memory for storing semaphore name. Error: %2!u!.\n",
  1644. pParams->ServiceName,
  1645. status
  1646. );
  1647. goto FnExit;
  1648. }
  1649. StringCchCopy(lpwTemp, cchTempSize, L"GenSvc$");
  1650. StringCchCat(lpwTemp, cchTempSize, pParams->ServiceName);
  1651. ResourceEntry->hSem = CreateSemaphore( NULL, 0, 1,lpwTemp );
  1652. status=GetLastError();
  1653. if ( ResourceEntry->hSem ) {
  1654. // Check if there is another resource controlling the same service
  1655. if ( status == ERROR_ALREADY_EXISTS ) {
  1656. status = ERROR_OBJECT_ALREADY_EXISTS;
  1657. (g_LogEvent)(
  1658. ResourceEntry->ResourceHandle,
  1659. LOG_ERROR,
  1660. L"Service '%1!ls!' is controlled by another resource. Error: %2!u!.\n",
  1661. pParams->ServiceName,
  1662. status
  1663. );
  1664. CloseHandle( ResourceEntry->hSem );
  1665. ResourceEntry->hSem = NULL;
  1666. goto FnExit;
  1667. }
  1668. } else {
  1669. (g_LogEvent)(
  1670. ResourceEntry->ResourceHandle,
  1671. LOG_ERROR,
  1672. L"SetPrivateProperties: Unable to create Semaphore %1!ls! for Service '%2!ls!' . Error: %3!u!.\n",
  1673. lpwTemp,
  1674. pParams->ServiceName,
  1675. status
  1676. );
  1677. goto FnExit;
  1678. }
  1679. }
  1680. FnExit:
  1681. //
  1682. // Cleanup our parameter block.
  1683. //
  1684. if ( ( (status != ERROR_SUCCESS)
  1685. && (pParams != NULL) )
  1686. || ( pParams == &newProps )
  1687. ) {
  1688. ResUtilFreeParameterBlock( (LPBYTE) pParams,
  1689. (LPBYTE) &currentProps,
  1690. GenSvcResourcePrivateProperties
  1691. );
  1692. }
  1693. ResUtilFreeParameterBlock(
  1694. (LPBYTE) &currentProps,
  1695. NULL,
  1696. GenSvcResourcePrivateProperties
  1697. );
  1698. if ( lpwTemp ) {
  1699. LocalFree( lpwTemp );
  1700. }
  1701. return(status);
  1702. } // GenSvcValidatePrivateResProperties
  1703. DWORD
  1704. GenSvcSetPrivateResProperties(
  1705. IN OUT PGENSVC_RESOURCE ResourceEntry,
  1706. IN const PVOID InBuffer,
  1707. IN DWORD InBufferSize
  1708. )
  1709. /*++
  1710. Routine Description:
  1711. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  1712. for resources of type Generic Service.
  1713. Arguments:
  1714. ResourceEntry - Supplies the resource entry on which to operate.
  1715. InBuffer - Supplies a pointer to a buffer containing input data.
  1716. InBufferSize - Supplies the size, in bytes, of the data pointed
  1717. to by InBuffer.
  1718. Return Value:
  1719. ERROR_SUCCESS - The function completed successfully.
  1720. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1721. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1722. Win32 error code - The function failed.
  1723. --*/
  1724. {
  1725. DWORD status;
  1726. GENSVC_PARAMS params;
  1727. ZeroMemory( &params, sizeof(GENSVC_PARAMS) );
  1728. //
  1729. // Parse and validate the properties.
  1730. //
  1731. status = GenSvcValidatePrivateResProperties( ResourceEntry,
  1732. InBuffer,
  1733. InBufferSize,
  1734. &params );
  1735. if ( status != ERROR_SUCCESS ) {
  1736. return(status);
  1737. }
  1738. //
  1739. // Save the parameter values.
  1740. //
  1741. status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1742. GenSvcResourcePrivateProperties,
  1743. NULL,
  1744. (LPBYTE) &params,
  1745. InBuffer,
  1746. InBufferSize,
  1747. (LPBYTE) &ResourceEntry->Params );
  1748. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1749. (LPBYTE) &ResourceEntry->Params,
  1750. GenSvcResourcePrivateProperties );
  1751. //
  1752. // If the resource is online, return a non-success status.
  1753. //
  1754. if (status == ERROR_SUCCESS) {
  1755. if ( ResourceEntry->Online ) {
  1756. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1757. } else {
  1758. status = ERROR_SUCCESS;
  1759. }
  1760. }
  1761. return status;
  1762. } // GenSvcSetPrivateResProperties
  1763. DWORD
  1764. GenSvcIsValidService(
  1765. IN OUT PGENSVC_RESOURCE ResourceEntry,
  1766. IN LPCWSTR ServiceName
  1767. )
  1768. /*++
  1769. Routine Description:
  1770. Determines if the specified service is a valid service or not.
  1771. Arguments:
  1772. ResourceEntry - Supplies the resource entry on which to operate.
  1773. ServiceName - Service name to verify.
  1774. Return Value:
  1775. ERROR_SUCCESS - Service is valid for a Generic Service resource.
  1776. Any status returned by OpenSCManager(), OpenService(), or
  1777. GenSvcInvalidGenericServiceCheck.
  1778. --*/
  1779. {
  1780. DWORD status;
  1781. HANDLE scManagerHandle;
  1782. HANDLE serviceHandle;
  1783. scManagerHandle = OpenSCManager( NULL, // local machine
  1784. NULL, // ServicesActive database
  1785. SC_MANAGER_ALL_ACCESS ); // all access
  1786. if ( scManagerHandle == NULL ) {
  1787. status = GetLastError();
  1788. (g_LogEvent)(
  1789. ResourceEntry->ResourceHandle,
  1790. LOG_ERROR,
  1791. L"Cannot access service controller for validating service '%1!ws!'. Error: %2!u!....\n",
  1792. ServiceName,
  1793. status
  1794. );
  1795. return(status);
  1796. }
  1797. serviceHandle = OpenService( scManagerHandle,
  1798. ServiceName,
  1799. GENERIC_READ );
  1800. if ( serviceHandle == NULL ) {
  1801. status = GetLastError();
  1802. (g_LogEvent)(
  1803. ResourceEntry->ResourceHandle,
  1804. LOG_ERROR,
  1805. L"Cannot open service '%1!ws!'. Error: %2!u!....\n",
  1806. ServiceName,
  1807. status
  1808. );
  1809. } else {
  1810. status = GenSvcCheckInvalidService( ResourceEntry, ServiceName, TEXT ( "clussvc" ), scManagerHandle );
  1811. if ( status == ERROR_NOT_SUPPORTED )
  1812. {
  1813. (g_LogEvent)(
  1814. ResourceEntry->ResourceHandle,
  1815. LOG_ERROR,
  1816. L"Service %1!ws! is a possible provider of clussvc, so %1!ws! cannot be gensvc resource, status %2!u!\n",
  1817. ServiceName,
  1818. status
  1819. );
  1820. }
  1821. }
  1822. CloseServiceHandle( serviceHandle );
  1823. CloseServiceHandle( scManagerHandle );
  1824. return(status);
  1825. } // GenSvcIsValidService
  1826. DWORD
  1827. GenSvcCheckInvalidService(
  1828. IN PGENSVC_RESOURCE pGenSvcCandidateResourceEntry,
  1829. IN LPCWSTR pGenSvcCandidateServiceName,
  1830. IN LPCWSTR pCheckedServiceName,
  1831. IN SC_HANDLE hSCManager
  1832. )
  1833. /*++
  1834. Routine Description:
  1835. Determines if the specified service is an invalid service for
  1836. use as a generic service. Invalid services include the cluster
  1837. service and any services upon which it depends.
  1838. Arguments:
  1839. pGenSvcCandidateResourceEntry - Supplies the resource entry of the gensvc candidate.
  1840. pGenSvcCandidateServiceName - Gensvc candidate service name.
  1841. pCheckedServiceName - The name of the service whose provider list is checked.
  1842. hSCManager - An open handle to the SC manager.
  1843. Return Value:
  1844. ERROR_SUCCESS - Service is valid for a Generic Service resource.
  1845. ERROR_NOT_SUPPORTED - Service can not be used for a Generic Service resource.
  1846. --*/
  1847. {
  1848. DWORD dwStatus = ERROR_SUCCESS;
  1849. DWORD cbServiceConfig;
  1850. LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
  1851. LPWSTR pCurrentProvider = NULL;
  1852. SC_HANDLE hService = NULL;
  1853. LPENUM_SERVICE_STATUS_PROCESS pEnumInfo = NULL;
  1854. //
  1855. // First check the gensvc candidate against the checked service itself.
  1856. //
  1857. if ( lstrcmpi ( pGenSvcCandidateServiceName, pCheckedServiceName ) == 0 )
  1858. {
  1859. dwStatus = ERROR_NOT_SUPPORTED;
  1860. goto FnExit;
  1861. }
  1862. //
  1863. // Get a handle to the service that is checked.
  1864. //
  1865. hService = OpenService ( hSCManager,
  1866. pCheckedServiceName,
  1867. SERVICE_QUERY_CONFIG );
  1868. if ( hService == NULL )
  1869. {
  1870. dwStatus = GetLastError();
  1871. (g_LogEvent)(
  1872. pGenSvcCandidateResourceEntry->ResourceHandle,
  1873. LOG_ERROR,
  1874. L"Unable to open service %1!ws! for querying config, status %2!u!\n",
  1875. pCheckedServiceName,
  1876. dwStatus
  1877. );
  1878. goto FnExit;
  1879. }
  1880. //
  1881. // Query the configuration info of the service to get the total config info size
  1882. //
  1883. if ( !QueryServiceConfig ( hService,
  1884. NULL,
  1885. 0,
  1886. &cbServiceConfig ) )
  1887. {
  1888. dwStatus = GetLastError();
  1889. if ( dwStatus != ERROR_INSUFFICIENT_BUFFER )
  1890. {
  1891. (g_LogEvent)(
  1892. pGenSvcCandidateResourceEntry->ResourceHandle,
  1893. LOG_ERROR,
  1894. L"Unable to query config info of service %1!ws! for config size, status %2!u!\n",
  1895. pCheckedServiceName,
  1896. dwStatus
  1897. );
  1898. goto FnExit;
  1899. }
  1900. dwStatus = ERROR_SUCCESS;
  1901. }
  1902. pServiceConfig = LocalAlloc ( LMEM_FIXED, cbServiceConfig );
  1903. if ( pServiceConfig == NULL )
  1904. {
  1905. dwStatus = GetLastError();
  1906. (g_LogEvent)(
  1907. pGenSvcCandidateResourceEntry->ResourceHandle,
  1908. LOG_ERROR,
  1909. L"Unable to alloc memory for service %1!ws! config, status %2!u!\n",
  1910. pCheckedServiceName,
  1911. dwStatus
  1912. );
  1913. goto FnExit;
  1914. }
  1915. //
  1916. // Now get the config info
  1917. //
  1918. if ( !QueryServiceConfig ( hService,
  1919. pServiceConfig,
  1920. cbServiceConfig,
  1921. &cbServiceConfig ) )
  1922. {
  1923. dwStatus = GetLastError();
  1924. (g_LogEvent)(
  1925. pGenSvcCandidateResourceEntry->ResourceHandle,
  1926. LOG_ERROR,
  1927. L"Unable to query config info of service %1!ws!, status %2!u!\n",
  1928. pCheckedServiceName,
  1929. dwStatus
  1930. );
  1931. goto FnExit;
  1932. }
  1933. pCurrentProvider = pServiceConfig->lpDependencies;
  1934. //
  1935. // No dependencies, bail.
  1936. //
  1937. if ( pCurrentProvider == NULL )
  1938. {
  1939. dwStatus = ERROR_SUCCESS;
  1940. goto FnExit;
  1941. }
  1942. //
  1943. // Walk the provider list
  1944. //
  1945. while ( *pCurrentProvider != UNICODE_NULL )
  1946. {
  1947. //
  1948. // The service depends on a group. Enumerate the services in the group and check
  1949. // if the gensvc candidate is one of them or one of the providers of the group
  1950. // members.
  1951. //
  1952. if ( pCurrentProvider[0] == SC_GROUP_IDENTIFIER )
  1953. {
  1954. DWORD i, cbStatusBuffer, cServices, dwResumeIndex = 0;
  1955. if ( !EnumServicesStatusEx ( hSCManager,
  1956. SC_ENUM_PROCESS_INFO,
  1957. SERVICE_DRIVER | SERVICE_WIN32,
  1958. SERVICE_STATE_ALL,
  1959. NULL,
  1960. 0,
  1961. &cbStatusBuffer,
  1962. &cServices, // Number of services in the group
  1963. &dwResumeIndex,
  1964. &pCurrentProvider[1] ) ) // group name
  1965. {
  1966. dwStatus = GetLastError ();
  1967. if ( dwStatus != ERROR_MORE_DATA )
  1968. {
  1969. (g_LogEvent)(
  1970. pGenSvcCandidateResourceEntry->ResourceHandle,
  1971. LOG_ERROR,
  1972. L"Unable to enum status of services in group %1!ws! for status size, status %2!u!\n",
  1973. &pCurrentProvider[1],
  1974. dwStatus
  1975. );
  1976. goto FnExit;
  1977. }
  1978. dwStatus = ERROR_SUCCESS;
  1979. dwResumeIndex = 0;
  1980. }
  1981. pEnumInfo = LocalAlloc ( LMEM_FIXED, cbStatusBuffer );
  1982. if ( pEnumInfo == NULL )
  1983. {
  1984. dwStatus = GetLastError ();
  1985. (g_LogEvent)(
  1986. pGenSvcCandidateResourceEntry->ResourceHandle,
  1987. LOG_ERROR,
  1988. L"Unable to alloc memory for status of services in group %1!ws!, status %2!u!\n",
  1989. &pCurrentProvider[1],
  1990. dwStatus
  1991. );
  1992. goto FnExit;
  1993. }
  1994. if ( !EnumServicesStatusEx ( hSCManager,
  1995. SC_ENUM_PROCESS_INFO,
  1996. SERVICE_DRIVER | SERVICE_WIN32,
  1997. SERVICE_STATE_ALL,
  1998. ( LPBYTE ) pEnumInfo,
  1999. cbStatusBuffer,
  2000. &cbStatusBuffer,
  2001. &cServices, // Number of services in the group
  2002. &dwResumeIndex,
  2003. &pCurrentProvider[1] ) ) // group name
  2004. {
  2005. dwStatus = GetLastError ();
  2006. (g_LogEvent)(
  2007. pGenSvcCandidateResourceEntry->ResourceHandle,
  2008. LOG_ERROR,
  2009. L"Unable to enum status of services in group %1!ws!, status %2!u!\n",
  2010. &pCurrentProvider[1],
  2011. dwStatus
  2012. );
  2013. goto FnExit;
  2014. }
  2015. //
  2016. // Walk the list of services in the group and check each one and its providers for
  2017. // a match against the gensvc candidate.
  2018. //
  2019. for ( i=0; i<cServices; i++ )
  2020. {
  2021. dwStatus = GenSvcCheckInvalidService( pGenSvcCandidateResourceEntry,
  2022. pGenSvcCandidateServiceName,
  2023. pEnumInfo[i].lpServiceName,
  2024. hSCManager );
  2025. if ( dwStatus != ERROR_SUCCESS )
  2026. {
  2027. if ( dwStatus == ERROR_NOT_SUPPORTED )
  2028. {
  2029. (g_LogEvent)(
  2030. pGenSvcCandidateResourceEntry->ResourceHandle,
  2031. LOG_ERROR,
  2032. L"Service %1!ws! (group %2!ws!) is a provider of %3!ws!, so %1!ws! cannot be gensvc resource, status %4!u!\n",
  2033. pGenSvcCandidateServiceName,
  2034. &pCurrentProvider[1],
  2035. pCheckedServiceName,
  2036. dwStatus
  2037. );
  2038. }
  2039. goto FnExit;
  2040. }
  2041. }
  2042. LocalFree ( pEnumInfo );
  2043. pEnumInfo = NULL;
  2044. pCurrentProvider += lstrlen ( pCurrentProvider ) + 1;
  2045. continue;
  2046. }
  2047. //
  2048. // Check the provider list of the provider service and see if the candidate service
  2049. // name is present in the list.
  2050. //
  2051. dwStatus = GenSvcCheckInvalidService( pGenSvcCandidateResourceEntry,
  2052. pGenSvcCandidateServiceName,
  2053. pCurrentProvider,
  2054. hSCManager );
  2055. if ( dwStatus != ERROR_SUCCESS )
  2056. {
  2057. if ( dwStatus == ERROR_NOT_SUPPORTED )
  2058. {
  2059. (g_LogEvent)(
  2060. pGenSvcCandidateResourceEntry->ResourceHandle,
  2061. LOG_ERROR,
  2062. L"Service %1!ws! is a provider of %2!ws!, so %1!ws! cannot be gensvc resource, status %3!u!\n",
  2063. pGenSvcCandidateServiceName,
  2064. pCheckedServiceName,
  2065. dwStatus
  2066. );
  2067. }
  2068. goto FnExit;
  2069. }
  2070. pCurrentProvider += lstrlen ( pCurrentProvider ) + 1;
  2071. }// while
  2072. FnExit:
  2073. if ( hService ) CloseServiceHandle ( hService );
  2074. LocalFree ( pServiceConfig );
  2075. LocalFree ( pEnumInfo );
  2076. return ( dwStatus );
  2077. } // GenSvcCheckInvalidService
  2078. //***********************************************************
  2079. //
  2080. // Define Function Table
  2081. //
  2082. //***********************************************************
  2083. CLRES_V1_FUNCTION_TABLE( GenSvcFunctionTable, // Name
  2084. CLRES_VERSION_V1_00, // Version
  2085. GenSvc, // Prefix
  2086. NULL, // Arbitrate
  2087. NULL, // Release
  2088. GenSvcResourceControl,// ResControl
  2089. GenSvcResourceTypeControl ); // ResTypeControl