Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1299 lines
34 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. services.c
  5. Abstract:
  6. Routines to manage nt service configurations for promotion and demotion
  7. Author:
  8. Colin Brace ColinBr March 29, 1999.
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include <setpch.h>
  14. #include <dssetp.h>
  15. #include <malloc.h> // alloca
  16. #include <lmcons.h> // net api definitions
  17. #include <lmsvc.h> // service names
  18. #include <ismapi.h> //defines ISM_SERVICE_CONTROL_REMOVE_STOP
  19. #include "services.h"
  20. //
  21. // These last 3 magic values supplied by Shirish Koti (koti) to setup up
  22. // ras services for macintosh on a domain controller
  23. //
  24. #define DSROLEP_MSV10_PATH L"SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0"
  25. #define DSROLEP_RASSFM_NAME L"Auth2"
  26. #define DSROLEP_RASSFM_VALUE L"RASSFM"
  27. //
  28. // Global Data for this module
  29. //
  30. //
  31. // Table based data for the intrinsic nt services
  32. //
  33. typedef struct _DSROLEP_SERVICE_ITEM
  34. {
  35. LPWSTR ServiceName; // name of the service to configure
  36. ULONG ConfigureOn; // the dsrole flag to enable the service
  37. ULONG ConfigureOff; // the dsrole flag to disable the service
  38. ULONG RevertSettings; // the dsrole flags to use to revert settings
  39. LPWSTR Dependencies[3]; // the dependencies the service has when enabled
  40. } DSROLEP_SERVICE_ITEM;
  41. //
  42. // These are services that run on machines that are part of a domain
  43. //
  44. DSROLEP_SERVICE_ITEM DsRoleDomainServices[] =
  45. {
  46. {
  47. SERVICE_W32TIME,
  48. DSROLEP_SERVICE_AUTOSTART,
  49. DSROLEP_SERVICE_DEMANDSTART,
  50. DSROLEP_SERVICES_INVALID,
  51. NULL, NULL, NULL
  52. },
  53. {
  54. SERVICE_NETLOGON,
  55. DSROLEP_SERVICE_AUTOSTART,
  56. DSROLEP_SERVICE_DEMANDSTART,
  57. 0,
  58. NULL, NULL, NULL
  59. }
  60. };
  61. ULONG DsRoleDomainServicesCount = sizeof(DsRoleDomainServices) / sizeof(DsRoleDomainServices[0]);
  62. //
  63. // These are servers that run on machines that are domain controllers
  64. //
  65. DSROLEP_SERVICE_ITEM DsRoleDomainControllerServices[] =
  66. {
  67. {
  68. SERVICE_RPCLOCATOR,
  69. DSROLEP_SERVICE_AUTOSTART,
  70. DSROLEP_SERVICE_DEMANDSTART,
  71. DSROLEP_SERVICES_INVALID,
  72. NULL, NULL, NULL
  73. },
  74. {
  75. SERVICE_ISMSERV,
  76. DSROLEP_SERVICE_AUTOSTART,
  77. DSROLEP_SERVICE_DISABLED | DSROLEP_SERVICE_STOP_ISM,
  78. DSROLEP_SERVICES_INVALID,
  79. NULL, NULL, NULL
  80. },
  81. {
  82. SERVICE_KDC,
  83. DSROLEP_SERVICE_AUTOSTART,
  84. DSROLEP_SERVICE_DISABLED,
  85. DSROLEP_SERVICES_INVALID,
  86. NULL, NULL, NULL
  87. },
  88. {
  89. SERVICE_TRKSVR,
  90. DSROLEP_SERVICE_AUTOSTART,
  91. DSROLEP_SERVICE_DEMANDSTART,
  92. DSROLEP_SERVICES_INVALID,
  93. NULL, NULL, NULL
  94. },
  95. {
  96. SERVICE_NETLOGON,
  97. DSROLEP_SERVICE_AUTOSTART | DSROLEP_SERVICE_DEP_ADD,
  98. DSROLEP_SERVICE_AUTOSTART | DSROLEP_SERVICE_DEP_REMOVE,
  99. DSROLEP_SERVICES_INVALID,
  100. SERVICE_SERVER, NULL, NULL
  101. }
  102. };
  103. ULONG DsRoleDomainControllerServicesCount = sizeof(DsRoleDomainControllerServices) / sizeof(DsRoleDomainControllerServices[0]);
  104. //
  105. // Local forwards
  106. //
  107. DWORD
  108. DsRolepSetRegStringValue(
  109. IN LPWSTR Path,
  110. IN LPWSTR ValueName,
  111. IN LPWSTR Value
  112. );
  113. DWORD
  114. DsRolepConfigureGenericServices(
  115. IN DSROLEP_SERVICE_ITEM *ServiceArray,
  116. IN ULONG ServiceCount,
  117. IN ULONG Flags
  118. );
  119. DWORD
  120. DsRolepMakeAdjustedDependencyList(
  121. IN HANDLE hSvc,
  122. IN DWORD ServiceOptions,
  123. IN LPWSTR Dependency,
  124. OUT LPWSTR *DependenyList
  125. );
  126. DWORD
  127. DsRolepGetServiceConfig(
  128. IN SC_HANDLE hScMgr,
  129. IN LPWSTR ServiceName,
  130. IN SC_HANDLE ServiceHandle,
  131. IN LPQUERY_SERVICE_CONFIG *ServiceConfig
  132. );
  133. //
  134. // Small helper functions
  135. //
  136. DWORD DsRolepFlagsToServiceFlags(
  137. IN DWORD f
  138. )
  139. {
  140. if ( FLAG_ON( f, DSROLEP_SERVICE_BOOTSTART ) ) return SERVICE_BOOT_START;
  141. if ( FLAG_ON( f, DSROLEP_SERVICE_SYSTEM_START ) ) return SERVICE_SYSTEM_START;
  142. if ( FLAG_ON( f, DSROLEP_SERVICE_AUTOSTART ) ) return SERVICE_AUTO_START;
  143. if ( FLAG_ON( f, DSROLEP_SERVICE_DEMANDSTART ) ) return SERVICE_DEMAND_START;
  144. if ( FLAG_ON( f, DSROLEP_SERVICE_DISABLED ) ) return SERVICE_DISABLED;
  145. // No flag, no change
  146. return SERVICE_NO_CHANGE;
  147. }
  148. DWORD DsRolepServiceFlagsToDsRolepFlags(
  149. IN DWORD f
  150. )
  151. {
  152. if ( f == SERVICE_BOOT_START ) return DSROLEP_SERVICE_BOOTSTART;
  153. if ( f == SERVICE_SYSTEM_START ) return DSROLEP_SERVICE_SYSTEM_START;
  154. if ( f == SERVICE_AUTO_START ) return DSROLEP_SERVICE_AUTOSTART;
  155. if ( f == SERVICE_DEMAND_START ) return DSROLEP_SERVICE_DEMANDSTART;
  156. if ( f == SERVICE_DISABLED ) return DSROLEP_SERVICE_DISABLED;
  157. if ( f == SERVICE_NO_CHANGE ) return 0;
  158. ASSERT( FALSE && !"Unknown service start type" );
  159. // This is safe
  160. return DSROLEP_SERVICE_DEMANDSTART;
  161. }
  162. //
  163. // Exported (from this file) functions
  164. //
  165. DWORD
  166. DsRolepConfigureDomainControllerServices(
  167. IN DWORD Flags
  168. )
  169. /*++
  170. Routine Description
  171. Parameters
  172. Return Values
  173. ERROR_SUCCESS if no errors; a system service error otherwise.
  174. --*/
  175. {
  176. DWORD WinError = ERROR_SUCCESS;
  177. //
  178. // Configure the registry for RASSFM service
  179. //
  180. if ( FLAG_ON( Flags, DSROLEP_SERVICES_ON ) ) {
  181. WinError = DsRolepSetRegStringValue(DSROLEP_MSV10_PATH,
  182. DSROLEP_RASSFM_NAME,
  183. DSROLEP_RASSFM_VALUE);
  184. //
  185. // This is not fatal -- log message
  186. //
  187. WinError = ERROR_SUCCESS;
  188. }
  189. //
  190. // Configure the intrinsic nt services
  191. //
  192. WinError = DsRolepConfigureGenericServices( DsRoleDomainControllerServices,
  193. DsRoleDomainControllerServicesCount,
  194. Flags );
  195. //
  196. // No need to undo RASSFM change
  197. //
  198. return WinError;
  199. }
  200. DWORD
  201. DsRolepConfigureDomainServices(
  202. DWORD Flags
  203. )
  204. /*++
  205. Routine Description
  206. Parameters
  207. Return Values
  208. ERROR_SUCCESS if no errors; a system service error otherwise.
  209. --*/
  210. {
  211. DWORD WinError = ERROR_SUCCESS;
  212. //
  213. // Configure the intrinsic nt services
  214. //
  215. WinError = DsRolepConfigureGenericServices( DsRoleDomainServices,
  216. DsRoleDomainServicesCount,
  217. Flags );
  218. return WinError;
  219. }
  220. DWORD
  221. DsRolepStartNetlogon(
  222. VOID
  223. )
  224. {
  225. DWORD WinError = ERROR_SUCCESS;
  226. WinError = DsRolepConfigureService( SERVICE_NETLOGON,
  227. DSROLEP_SERVICE_START,
  228. NULL,
  229. NULL );
  230. return WinError;
  231. }
  232. DWORD
  233. DsRolepStopNetlogon(
  234. OUT BOOLEAN *WasRunning
  235. )
  236. {
  237. DWORD WinError = ERROR_SUCCESS;
  238. ULONG PreviousSettings = 0;
  239. WinError = DsRolepConfigureService( SERVICE_NETLOGON,
  240. DSROLEP_SERVICE_STOP,
  241. NULL,
  242. &PreviousSettings );
  243. if ( (ERROR_SUCCESS == WinError)
  244. && WasRunning ) {
  245. *WasRunning = (BOOLEAN) FLAG_ON( PreviousSettings, DSROLEP_SERVICE_START );
  246. }
  247. return WinError;
  248. }
  249. //
  250. // Local functions
  251. //
  252. DWORD
  253. DsRolepSetRegStringValue(LPWSTR Path,
  254. LPWSTR ValueName,
  255. LPWSTR Value)
  256. /*++
  257. Routine Description
  258. This routine sets Value as a REG_SZ value on the value ValueName
  259. on the key Path
  260. Parameters
  261. Path, a registry path relative to HKLM
  262. ValueName, a null-terminated string
  263. Value, a null terminated string
  264. Return Values
  265. ERROR_SUCCESS if no errors; a system service error otherwise.
  266. --*/
  267. {
  268. DWORD WinErroror = ERROR_INVALID_PARAMETER, WinErroror2;
  269. HKEY hKey;
  270. ASSERT(Path);
  271. ASSERT(ValueName);
  272. ASSERT(Value);
  273. if (Path && ValueName && Value) {
  274. WinErroror = RegCreateKey(HKEY_LOCAL_MACHINE,
  275. Path,
  276. &hKey);
  277. if (ERROR_SUCCESS == WinErroror) {
  278. WinErroror = RegSetValueEx(hKey,
  279. ValueName,
  280. 0, // reserved
  281. REG_SZ,
  282. (VOID*)Value,
  283. (wcslen(Value)+1)*sizeof(WCHAR));
  284. WinErroror2 = RegCloseKey(hKey);
  285. ASSERT(ERROR_SUCCESS == WinErroror2);
  286. }
  287. }
  288. DsRolepLogPrint(( DEB_TRACE,
  289. "DsRolepSetRegStringValue on %ws\\%ws to %ws returned %lu\n",
  290. Path,
  291. ValueName,
  292. Value,
  293. WinErroror ));
  294. return WinErroror;
  295. }
  296. DWORD
  297. DsRolepConfigureGenericServices(
  298. IN DSROLEP_SERVICE_ITEM *ServiceArray,
  299. IN ULONG ServiceCount,
  300. IN ULONG Flags
  301. )
  302. /*++
  303. Routine Description:
  304. Arguments:
  305. Returns:
  306. --*/
  307. {
  308. DWORD WinError = ERROR_SUCCESS;
  309. ULONG ServicesInstalled;
  310. //
  311. // Configure each service
  312. //
  313. for ( ServicesInstalled = 0;
  314. ServicesInstalled < ServiceCount && (WinError == ERROR_SUCCESS);
  315. ServicesInstalled++ ) {
  316. ULONG *RevertSettings = &ServiceArray[ServicesInstalled].RevertSettings;
  317. ULONG Operation = 0;
  318. //
  319. // Check for cancel before contining if we are not reverting
  320. //
  321. if ( !FLAG_ON( Flags, DSROLEP_SERVICES_REVERT ) ) {
  322. DSROLEP_CHECK_FOR_CANCEL( WinError );
  323. if ( ERROR_SUCCESS != WinError ) {
  324. break;
  325. }
  326. }
  327. //
  328. // Determine the operation flag
  329. //
  330. if ( FLAG_ON( Flags, DSROLEP_SERVICES_ON ) ) {
  331. Operation |= ServiceArray[ServicesInstalled].ConfigureOn;
  332. *RevertSettings = 0;
  333. } else if ( FLAG_ON( Flags, DSROLEP_SERVICES_OFF ) ) {
  334. Operation |= ServiceArray[ServicesInstalled].ConfigureOff;
  335. *RevertSettings = 0;
  336. } else if ( FLAG_ON( Flags, DSROLEP_SERVICES_REVERT ) ) {
  337. Operation |= ServiceArray[ServicesInstalled].RevertSettings;
  338. //
  339. // N.B. We don't want to set the revert settings when we are
  340. // reverting!
  341. //
  342. RevertSettings = NULL;
  343. }
  344. if ( FLAG_ON( Flags, DSROLEP_SERVICES_START ) ) {
  345. Operation |= DSROLEP_SERVICE_START;
  346. } else if ( FLAG_ON( Flags, DSROLEP_SERVICES_STOP ) ) {
  347. Operation |= DSROLEP_SERVICE_STOP;
  348. }
  349. //
  350. // Currently we don't handle more than one dependency
  351. //
  352. ASSERT( NULL == ServiceArray[ ServicesInstalled ].Dependencies[1] );
  353. // We should do something
  354. ASSERT( 0 != Operation );
  355. //
  356. // Configure the service
  357. //
  358. WinError = DsRolepConfigureService( ServiceArray[ ServicesInstalled ].ServiceName,
  359. Operation,
  360. ServiceArray[ ServicesInstalled ].Dependencies[0],
  361. RevertSettings
  362. );
  363. }
  364. //
  365. // If there is an error, undo the work already done
  366. //
  367. if ( ERROR_SUCCESS != WinError
  368. && !FLAG_ON( Flags, DSROLEP_SERVICES_REVERT ) ) {
  369. DWORD WinError2;
  370. ULONG i;
  371. for ( i = 0; i < ServicesInstalled; i++ ) {
  372. //
  373. // Configure the service
  374. //
  375. WinError2 = DsRolepConfigureService( ServiceArray[ i ].ServiceName,
  376. ServiceArray[ServicesInstalled].RevertSettings,
  377. ServiceArray[ i ].Dependencies[0],
  378. NULL // we don't need to know revert settings
  379. );
  380. //
  381. // This should succeed, though since this is the undo path it is
  382. // not critical
  383. //
  384. ASSERT( ERROR_SUCCESS == WinError2 );
  385. }
  386. }
  387. return WinError;
  388. }
  389. DWORD
  390. DsRolepConfigureService(
  391. IN LPWSTR ServiceName,
  392. IN ULONG ServiceOptions,
  393. IN LPWSTR Dependency OPTIONAL,
  394. OUT ULONG *RevertServiceOptions OPTIONAL
  395. )
  396. /*++
  397. Routine Description:
  398. Starts, stops, or modifies the configuration of a service.
  399. Arguments:
  400. ServiceName - Service to configure
  401. ServiceOptions - Stop, start, dependency add/remove, or configure
  402. Dependency - a null terminated string identify a dependency
  403. ServiceWasRunning - Optional. When stopping a service, the previous service state
  404. is returned here
  405. Returns:
  406. ERROR_SUCCESS - Success
  407. ERROR_INVALID_PARAMETER - A bad service option was given
  408. --*/
  409. {
  410. DWORD WinError = ERROR_SUCCESS;
  411. SC_HANDLE hScMgr = NULL, hSvc = NULL;
  412. ULONG OpenMode = 0;
  413. LPENUM_SERVICE_STATUS DependentServices = NULL;
  414. ULONG DependSvcSize = 0, DependSvcCount = 0, i;
  415. LPWSTR NewDependencyList = NULL;
  416. DWORD NewStartType = SERVICE_NO_CHANGE;
  417. ULONG UpdateMsgId = DSROLEEVT_CONFIGURE_SERVICE;
  418. //
  419. // If the service doesn't stop within two minutes minute, continue on
  420. //
  421. ULONG AccumulatedSleepTime;
  422. ULONG MaxSleepTime = 120000;
  423. BOOLEAN ConfigChangeRequired = FALSE;
  424. BOOLEAN RunChangeRequired = FALSE;
  425. DWORD PreviousStartType = SERVICE_NO_CHANGE;
  426. BOOLEAN fServiceWasRunning = FALSE;
  427. //
  428. // Parameter checks
  429. //
  430. ASSERT( ! (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_ADD )
  431. && (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_REMOVE ))) );
  432. ASSERT( ! (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_AUTOSTART )
  433. && (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DISABLED ))) );
  434. ASSERT( ! (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_START )
  435. && (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP ))) );
  436. //
  437. // Do some logic to determine the open mode of the service
  438. //
  439. NewStartType = DsRolepFlagsToServiceFlags( ServiceOptions );
  440. if ( (SERVICE_NO_CHANGE != NewStartType) ||
  441. FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_ADD ) ||
  442. FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_REMOVE ))
  443. {
  444. ConfigChangeRequired = TRUE;
  445. }
  446. if( ConfigChangeRequired ) {
  447. OpenMode |= SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG;
  448. }
  449. if( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP ) ) {
  450. OpenMode |= SERVICE_STOP | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_QUERY_STATUS;
  451. UpdateMsgId = DSROLEEVT_STOP_SERVICE;
  452. RunChangeRequired = TRUE;
  453. }
  454. if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP_ISM ) ) {
  455. OpenMode |= SERVICE_USER_DEFINED_CONTROL;
  456. }
  457. if( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_START ) ) {
  458. OpenMode |= SERVICE_START | SERVICE_QUERY_STATUS;
  459. UpdateMsgId = DSROLEEVT_START_SERVICE;
  460. RunChangeRequired = TRUE;
  461. }
  462. //
  463. // Open the service control manager
  464. //
  465. hScMgr = OpenSCManager( NULL,
  466. SERVICES_ACTIVE_DATABASE,
  467. GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE );
  468. if ( hScMgr == NULL ) {
  469. WinError = GetLastError();
  470. DsRolepLogOnFailure( WinError,
  471. DsRolepLogPrint(( DEB_TRACE,
  472. "Can't contact the service controller manager (%lu)\n",
  473. WinError )) );
  474. goto Cleanup;
  475. }
  476. //
  477. // Open the service
  478. //
  479. hSvc = OpenService( hScMgr,
  480. ServiceName,
  481. OpenMode );
  482. if ( hSvc == NULL ) {
  483. WinError = GetLastError();
  484. DsRolepLogOnFailure( WinError,
  485. DsRolepLogPrint(( DEB_TRACE,
  486. "OpenService on %ws failed with %lu\n",
  487. ServiceName,
  488. WinError )) );
  489. goto Cleanup;
  490. }
  491. DSROLEP_CURRENT_OP1( UpdateMsgId, ServiceName );
  492. //
  493. // Determine if the service is running if we are going to be stopping or
  494. // starting it
  495. //
  496. if( RunChangeRequired ) {
  497. SERVICE_STATUS SvcStatus;
  498. if( QueryServiceStatus( hSvc,&SvcStatus ) == FALSE ) {
  499. WinError = GetLastError();
  500. goto Cleanup;
  501. }
  502. if ( SvcStatus.dwCurrentState == SERVICE_RUNNING ) {
  503. fServiceWasRunning = TRUE;
  504. }
  505. }
  506. //
  507. // Determine the current start type if we are going to be changing it
  508. //
  509. if ( ConfigChangeRequired ) {
  510. LPQUERY_SERVICE_CONFIG ServiceConfig = NULL;
  511. DWORD Size = 0;
  512. BOOL fSuccess;
  513. QueryServiceConfig( hSvc,
  514. ServiceConfig,
  515. Size,
  516. &Size );
  517. ASSERT( GetLastError() == ERROR_INSUFFICIENT_BUFFER );
  518. ServiceConfig = (LPQUERY_SERVICE_CONFIG) alloca( Size );
  519. fSuccess = QueryServiceConfig( hSvc,
  520. ServiceConfig,
  521. Size,
  522. &Size );
  523. if ( !fSuccess ) {
  524. WinError = GetLastError();
  525. goto Cleanup;
  526. }
  527. PreviousStartType = ServiceConfig->dwStartType;
  528. }
  529. //
  530. // Do the config change
  531. //
  532. if ( ConfigChangeRequired ) {
  533. //
  534. // Make a new dependency list
  535. //
  536. if ( Dependency ) {
  537. WinError = DsRolepMakeAdjustedDependencyList( hSvc,
  538. ServiceOptions,
  539. Dependency,
  540. &NewDependencyList );
  541. if ( ERROR_SUCCESS != WinError ) {
  542. goto Cleanup;
  543. }
  544. }
  545. //
  546. // Change the service with new parameters
  547. //
  548. if ( ChangeServiceConfig( hSvc,
  549. SERVICE_NO_CHANGE,
  550. NewStartType,
  551. SERVICE_NO_CHANGE,
  552. NULL,
  553. NULL,
  554. 0,
  555. NewDependencyList,
  556. NULL, NULL, NULL ) == FALSE ) {
  557. WinError = GetLastError();
  558. DsRolepLogOnFailure( WinError,
  559. DsRolepLogPrint(( DEB_TRACE,
  560. "ChangeServiceConfig on %ws failed with %lu\n",
  561. ServiceName,
  562. WinError )) );
  563. goto Cleanup;
  564. }
  565. }
  566. // Stop the service.
  567. if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP ) || FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP_ISM ) ) {
  568. SERVICE_STATUS SvcStatus;
  569. WinError = ERROR_SUCCESS;
  570. //
  571. // Enumerate all of the dependent services first
  572. //
  573. if(EnumDependentServices( hSvc,
  574. SERVICE_ACTIVE,
  575. NULL,
  576. 0,
  577. &DependSvcSize,
  578. &DependSvcCount ) == FALSE ) {
  579. WinError = GetLastError();
  580. }
  581. if ( WinError == ERROR_MORE_DATA ) {
  582. DependentServices = RtlAllocateHeap( RtlProcessHeap(), 0, DependSvcSize );
  583. if ( DependentServices == NULL) {
  584. WinError = ERROR_OUTOFMEMORY;
  585. } else {
  586. if( EnumDependentServices( hSvc,
  587. SERVICE_ACTIVE,
  588. DependentServices,
  589. DependSvcSize,
  590. &DependSvcSize,
  591. &DependSvcCount ) == FALSE ) {
  592. WinError = GetLastError();
  593. } else {
  594. for ( i = 0; i < DependSvcCount; i++) {
  595. DsRoleDebugOut(( DEB_TRACE,
  596. "Service %ws depends on %ws\n",
  597. DependentServices[i].lpServiceName,
  598. ServiceName ));
  599. WinError = DsRolepConfigureService(
  600. DependentServices[i].lpServiceName,
  601. DSROLEP_SERVICE_STOP,
  602. NULL,
  603. NULL );
  604. if ( WinError != ERROR_SUCCESS ) {
  605. break;
  606. }
  607. }
  608. }
  609. RtlFreeHeap( RtlProcessHeap(), 0, DependentServices );
  610. }
  611. }
  612. if ( WinError == ERROR_SUCCESS ) {
  613. if ( (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP_ISM )?
  614. ControlService( hSvc,
  615. ISM_SERVICE_CONTROL_REMOVE_STOP,
  616. &SvcStatus ):
  617. ControlService( hSvc,
  618. SERVICE_CONTROL_STOP,
  619. &SvcStatus )) == FALSE ) {
  620. WinError = GetLastError();
  621. //
  622. // It's not an error if the service wasn't running
  623. //
  624. if ( WinError == ERROR_SERVICE_NOT_ACTIVE ) {
  625. WinError = ERROR_SUCCESS;
  626. }
  627. } else {
  628. WinError = ERROR_SUCCESS;
  629. //
  630. // Wait for the service to stop
  631. //
  632. AccumulatedSleepTime = 0;
  633. while ( TRUE ) {
  634. if( QueryServiceStatus( hSvc,&SvcStatus ) == FALSE ) {
  635. WinError = GetLastError();
  636. }
  637. if ( WinError != ERROR_SUCCESS ||
  638. SvcStatus.dwCurrentState == SERVICE_STOPPED) {
  639. break;
  640. }
  641. if ( AccumulatedSleepTime < MaxSleepTime ) {
  642. if ( 0 == SvcStatus.dwWaitHint ) {
  643. //if we are told not to wait we will
  644. //wait for 5 seconds anyway.
  645. //bug # 221482
  646. Sleep ( 5000 );
  647. AccumulatedSleepTime += 5000;
  648. } else {
  649. Sleep( SvcStatus.dwWaitHint );
  650. AccumulatedSleepTime += SvcStatus.dwWaitHint;
  651. }
  652. } else {
  653. //
  654. // Give up and return an error
  655. //
  656. WinError = WAIT_TIMEOUT;
  657. break;
  658. }
  659. }
  660. }
  661. DsRoleDebugOut(( DEB_TRACE, "StopService on %ws returned %lu\n",
  662. ServiceName, WinError ));
  663. }
  664. DsRolepLogOnFailure( WinError,
  665. DsRolepLogPrint(( DEB_TRACE,
  666. "StopService on %ws failed with %lu\n",
  667. ServiceName,
  668. WinError )) );
  669. if ( ERROR_SUCCESS != WinError ) {
  670. goto Cleanup;
  671. }
  672. }
  673. if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_START ) ) {
  674. //
  675. // See about changing its state
  676. //
  677. if ( StartService( hSvc, 0, NULL ) == FALSE ) {
  678. WinError = GetLastError();
  679. } else {
  680. WinError = ERROR_SUCCESS;
  681. }
  682. DsRoleDebugOut(( DEB_TRACE, "StartService on %ws returned %lu\n",
  683. ServiceName, WinError ));
  684. DsRolepLogOnFailure( WinError,
  685. DsRolepLogPrint(( DEB_TRACE,
  686. "StartService on %ws failed with %lu\n",
  687. ServiceName,
  688. WinError )) );
  689. if ( ERROR_SUCCESS != WinError ) {
  690. goto Cleanup;
  691. }
  692. }
  693. //
  694. // Success! By the time we are here, we have completed the task asked
  695. // of us, so set the Revert parameter
  696. //
  697. ASSERT( ERROR_SUCCESS == WinError );
  698. if ( RevertServiceOptions ) {
  699. *RevertServiceOptions = 0;
  700. if( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP )
  701. && fServiceWasRunning ) {
  702. *RevertServiceOptions |= DSROLEP_SERVICE_START;
  703. }
  704. if( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_START )
  705. && !fServiceWasRunning ) {
  706. *RevertServiceOptions |= DSROLEP_SERVICE_STOP;
  707. }
  708. if ( PreviousStartType != SERVICE_NO_CHANGE ) {
  709. *RevertServiceOptions |= DsRolepServiceFlagsToDsRolepFlags( PreviousStartType );
  710. }
  711. if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_ADD ) ) {
  712. *RevertServiceOptions |= DSROLEP_SERVICE_DEP_REMOVE;
  713. }
  714. if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_REMOVE ) ) {
  715. *RevertServiceOptions |= DSROLEP_SERVICE_DEP_ADD;
  716. }
  717. }
  718. Cleanup:
  719. if ( hSvc ) {
  720. CloseServiceHandle( hSvc );
  721. }
  722. if ( hScMgr ) {
  723. CloseServiceHandle( hScMgr );
  724. }
  725. if ( NewDependencyList ) {
  726. RtlFreeHeap(RtlProcessHeap(), 0, NewDependencyList);
  727. }
  728. DsRolepLogPrint(( DEB_TRACE,
  729. "Configuring service %ws to %lu returned %lu\n",
  730. ServiceName,
  731. ServiceOptions,
  732. WinError ));
  733. DSROLEP_FAIL1( WinError, DSROLERES_SERVICE_CONFIGURE, ServiceName );
  734. return( WinError );
  735. }
  736. DWORD
  737. DsRolepMakeAdjustedDependencyList(
  738. IN HANDLE hSvc,
  739. IN DWORD ServiceOptions,
  740. IN LPWSTR Dependency,
  741. OUT LPWSTR *NewDependencyList
  742. )
  743. /*++
  744. Routine Description
  745. This function adds or removes Dependency from the service referred to
  746. by hSvc.
  747. Parameters
  748. hSvc, a handle to an open service
  749. ServiceOptions, either DSROLEP_SERVICE_DEP_REMOVE or DSROLEP_SERVICE_DEP_ADD
  750. Dependency, null terminated string
  751. NewDependencyList, a block list of strings to freed by the caller
  752. Return Values
  753. ERROR_SUCCESS if no errors; a system service error otherwise.
  754. --*/
  755. {
  756. DWORD WinError = STATUS_SUCCESS;
  757. BOOLEAN fDone = FALSE;
  758. WCHAR *CurrentDependency;
  759. ULONG CurrentDependencyLength;
  760. ULONG DependencySize;
  761. ULONG DependencyListSize;
  762. ULONG NewDependencyListSize;
  763. LPWSTR TempDependencyList = NULL;
  764. WCHAR *CurrNewList;
  765. LPQUERY_SERVICE_CONFIG ServiceConfigInfo=NULL;
  766. //
  767. // Query for the existing dependencies
  768. //
  769. WinError = DsRolepGetServiceConfig(NULL,
  770. NULL,
  771. hSvc,
  772. &ServiceConfigInfo);
  773. if (ERROR_SUCCESS != WinError) {
  774. goto Cleanup;
  775. }
  776. if (FLAG_ON(ServiceOptions, DSROLEP_SERVICE_DEP_ADD)) {
  777. // Get the size of the dependency
  778. DependencySize = (wcslen(Dependency) + 1)*sizeof(WCHAR); // for NULL
  779. // Get the size of the dependency list
  780. DependencyListSize = 0;
  781. CurrentDependency = ServiceConfigInfo->lpDependencies;
  782. while (CurrentDependency && *CurrentDependency != L'\0') {
  783. // Get the current list size
  784. if (!_wcsicmp(CurrentDependency, Dependency)) {
  785. //
  786. // Dependency is already here
  787. //
  788. break;
  789. fDone = TRUE;
  790. }
  791. CurrentDependencyLength = wcslen(CurrentDependency) + 1; // for NULL
  792. DependencyListSize += CurrentDependencyLength * sizeof(WCHAR);
  793. CurrentDependency += CurrentDependencyLength;
  794. }
  795. if ( fDone ) {
  796. WinError = ERROR_SUCCESS;
  797. goto Cleanup;
  798. }
  799. // Calculate the size of the new dependency list
  800. NewDependencyListSize = DependencyListSize +
  801. DependencySize +
  802. sizeof(WCHAR); // the whole string of strings
  803. // NULL terminated
  804. //
  805. // Now allocate a space to hold the new dependency array
  806. //
  807. TempDependencyList = RtlAllocateHeap(RtlProcessHeap(),
  808. 0,
  809. NewDependencyListSize);
  810. if (!TempDependencyList) {
  811. WinError = ERROR_NOT_ENOUGH_MEMORY;
  812. goto Cleanup;
  813. }
  814. RtlZeroMemory(TempDependencyList, NewDependencyListSize);
  815. RtlCopyMemory(TempDependencyList,
  816. ServiceConfigInfo->lpDependencies,
  817. DependencyListSize);
  818. RtlCopyMemory(&TempDependencyList[DependencyListSize/sizeof(WCHAR)],
  819. Dependency,
  820. DependencySize);
  821. } else if (FLAG_ON(ServiceOptions, DSROLEP_SERVICE_DEP_REMOVE)) {
  822. // Get the size of the dependency
  823. DependencySize = (wcslen(Dependency) + 1)*sizeof(WCHAR); // for NULL
  824. // Get the size of the dependency list
  825. DependencyListSize = 0;
  826. CurrentDependency = ServiceConfigInfo->lpDependencies;
  827. while (CurrentDependency && *CurrentDependency != L'\0') {
  828. CurrentDependencyLength = wcslen(CurrentDependency) + 1; // for NULL
  829. DependencyListSize += CurrentDependencyLength * sizeof(WCHAR);
  830. CurrentDependency += CurrentDependencyLength;
  831. }
  832. // Calculate the size of the new dependency list
  833. NewDependencyListSize = DependencyListSize -
  834. DependencySize +
  835. sizeof(WCHAR); // the whole string of strings
  836. // NULL terminated
  837. //
  838. // Now allocate a space to hold the new dependency array
  839. // This is overkill, but not much.
  840. //
  841. TempDependencyList = RtlAllocateHeap(RtlProcessHeap(),
  842. 0,
  843. NewDependencyListSize);
  844. if (!TempDependencyList) {
  845. WinError = ERROR_NOT_ENOUGH_MEMORY;
  846. goto Cleanup;
  847. }
  848. RtlZeroMemory(TempDependencyList, NewDependencyListSize);
  849. CurrentDependency = ServiceConfigInfo->lpDependencies;
  850. CurrNewList = TempDependencyList;
  851. while (CurrentDependency && *CurrentDependency != L'\0') {
  852. CurrentDependencyLength = wcslen(CurrentDependency) + 1; // for NULL
  853. // Get the current list size
  854. if (!_wcsicmp(CurrentDependency, Dependency)) {
  855. //
  856. // This is the one - don't copy it
  857. //
  858. } else {
  859. wcscpy(CurrNewList, CurrentDependency);
  860. CurrNewList += CurrentDependencyLength;
  861. }
  862. CurrentDependency += CurrentDependencyLength;
  863. }
  864. }
  865. Cleanup:
  866. if (WinError != ERROR_SUCCESS && TempDependencyList) {
  867. RtlFreeHeap(RtlProcessHeap(), 0, TempDependencyList);
  868. *NewDependencyList = NULL;
  869. } else {
  870. *NewDependencyList = TempDependencyList;
  871. }
  872. if (ServiceConfigInfo) {
  873. RtlFreeHeap(RtlProcessHeap(), 0, ServiceConfigInfo);
  874. }
  875. return( WinError );
  876. }
  877. DWORD
  878. DsRolepGetServiceConfig(
  879. IN SC_HANDLE hScMgr,
  880. IN LPWSTR ServiceName,
  881. IN SC_HANDLE ServiceHandle,
  882. IN LPQUERY_SERVICE_CONFIG *ServiceConfig
  883. )
  884. /*++
  885. Routine Description:
  886. Parameters:
  887. Return Values:
  888. ERROR_SUCCESS
  889. ERROR_NOT_ENOUGH_MEMORY
  890. --*/
  891. {
  892. DWORD Win32Error;
  893. SC_HANDLE hService;
  894. ULONG SizeNeeded;
  895. #if DBG
  896. if (!ServiceHandle) {
  897. ASSERT(ServiceName);
  898. ASSERT(hScMgr);
  899. }
  900. #endif
  901. if (!ServiceHandle) {
  902. hService = OpenService( hScMgr,
  903. ServiceName,
  904. SERVICE_QUERY_CONFIG );
  905. } else {
  906. hService = ServiceHandle;
  907. }
  908. if (hService) {
  909. SizeNeeded = 0;
  910. Win32Error = ERROR_SUCCESS;
  911. if (!QueryServiceConfig(hService,
  912. NULL,
  913. 0,
  914. &SizeNeeded)) {
  915. Win32Error = GetLastError();
  916. }
  917. ASSERT(Win32Error == ERROR_INSUFFICIENT_BUFFER);
  918. ASSERT( SizeNeeded > 0 );
  919. *ServiceConfig = RtlAllocateHeap(RtlProcessHeap(),
  920. 0,
  921. SizeNeeded);
  922. if (*ServiceConfig) {
  923. Win32Error = ERROR_SUCCESS;
  924. if (!QueryServiceConfig(hService,
  925. *ServiceConfig,
  926. SizeNeeded,
  927. &SizeNeeded)) {
  928. Win32Error = GetLastError();
  929. }
  930. } else {
  931. Win32Error = ERROR_NOT_ENOUGH_MEMORY;
  932. }
  933. if (!ServiceHandle) {
  934. CloseServiceHandle(hService);
  935. }
  936. } else {
  937. Win32Error = GetLastError();
  938. }
  939. DsRolepLogOnFailure( Win32Error,
  940. DsRolepLogPrint(( DEB_TRACE,
  941. "DsRolepGetServiceConfig on %ws failed with %lu\n",
  942. ServiceName,
  943. Win32Error )) );
  944. return Win32Error;
  945. }