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.

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