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.

1667 lines
45 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. svcctrl.cxx
  5. Abstract:
  6. This is the main routine for the NT LAN Manager Service Controller.
  7. To use this as a template for another service, simply replace the string
  8. "svcctl" with the name of the new interface.
  9. Author:
  10. Dan Lafferty (danl) 20-Mar-1991
  11. Environment:
  12. User Mode - Win32
  13. Revision History:
  14. 04-Aug-1999 jschwart
  15. Added code to watch the list of network providers and write the list
  16. of providers enabled in this HW profile to the registry for mpr.dll
  17. 22-Oct-1998 jschwart
  18. Added an unhandled exception filter and converted SCM to use
  19. the NT thread pool APIs
  20. 22-Jun-1998 jschwart
  21. Added SetErrorMode call to prevent services from halting the process
  22. with a hard error popup
  23. 10-Mar-1998 jschwart
  24. Added RegisterScmCallback call to provide SCM support for passing
  25. PnP messages to services
  26. 12-Dec-1997 WesW
  27. Added support for safe boot
  28. 11-Jun-1996 AnirudhS
  29. Don't popup messages during setup. The most common cause of popups
  30. during upgrade is that a service runs in a domain account, and hence
  31. has a dependency on netlogon, which is disabled during upgrade.
  32. 26-Jun-1995 AnirudhS
  33. Added callouts to service object class code (ScNotifyServiceObject).
  34. 20-Oct-1993 Danl
  35. Added Globals for ScConnectedToSecProc and ScGlobalNetLogonName.
  36. 28-Oct-1992 Danl
  37. Removed ParseArgs and the NT event. Added Windows event for
  38. synchronizing service controller with the OpenSCManager client side.
  39. OpenScManager will now wait until the service controller event is
  40. set.
  41. 20-Mar-1991 danl
  42. created
  43. --*/
  44. //
  45. // INCLUDES
  46. //
  47. #include "precomp.hxx"
  48. #include <stdio.h> // printf
  49. #include <winuserp.h> // RegisterServicesProcess
  50. #include <lmcons.h> // needed by lmalert.h
  51. #include <lmalert.h> // NetAlertRaiseEx definitions
  52. #include <alertmsg.h> // ALERT_SC_IsLastKnownGood
  53. #ifdef _CAIRO_
  54. #include <wtypes.h> // HRESULT
  55. #include <scmso.h> // ScmCallSvcObject
  56. #endif
  57. #include <tstr.h> // Unicode string macros
  58. #include <ntrpcp.h> // Rpcp... function prototypes
  59. #include <sclib.h> // SC_INTERNAL_START_EVENT
  60. #include <svcslib.h> // CWorkItemContext
  61. #include "scsec.h" // Security object functions
  62. #include "scconfig.h" // ScInitSecurityProcess
  63. #include "depend.h" // ScAutoStartServices
  64. #include "bootcfg.h" // ScCheckLastKnownGood()
  65. #include "account.h" // ScInitServiceAccount
  66. #include "info.h" // ScGetBootAndSystemDriverState
  67. #include "control.h" // ScShutdownAllServices
  68. #include "lockapi.h" // ScLockDatabase
  69. #include "scbsm.h" // ScInitBSM
  70. #include "valid.h" // MAX_SERVICE_NAME_LENGTH
  71. #include <svcsp.h> // SVCS_RPC_PIPE, SVCS_LRPC_PROTOCOl, SVCS_LRPC_PORT
  72. #include <winsvcp.h> // SC_AUTOSTART_EVENT_NAME
  73. #include <sddl.h> // ConvertSidToStringSid
  74. #include "resource.h"
  75. extern "C" {
  76. #include <cfgmgr32.h>
  77. #include "cfgmgrp.h"
  78. }
  79. #include <scesrv.h>
  80. #include <crypstub.h> // StartCryptServiceStubs, StopCryptServiceStubs
  81. #include <trkstub.h> // StartTrkWksServiceStubs, StopTrkWksServiceStubs
  82. //
  83. // Macros:
  84. //
  85. // IsServer -- We're running on an NT server or DC
  86. // IsTerminalServer -- We're running Hydra
  87. //
  88. // Note that IsServer is not guaranteed to be accurate during GUI-mode setup since
  89. // the product type may be changing during an upgrade.
  90. //
  91. #define IsServer() (USER_SHARED_DATA->NtProductType != NtProductWinNt)
  92. #define IsTerminalServer() (BOOLEAN)(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer))
  93. #define LENGTH(array) (sizeof(array)/sizeof((array)[0]))
  94. //
  95. // The following turns on code that captures time info & displays it.
  96. // To be used for performance analysis.
  97. //
  98. //#define TIMING_TEST 1
  99. //
  100. // Defines
  101. //
  102. #define SVCCTRL_SHUTDOWN_LEVEL 480
  103. #define SCREG_BASE_PRIORITY 9
  104. #define SERVICES_EXPANDPATH L"%SystemRoot%\\system32\\services.exe"
  105. #define SECURITY_EXPANDPATH L"%SystemRoot%\\system32\\lsass.exe"
  106. extern "C" typedef
  107. NET_API_STATUS (NET_API_FUNCTION * PF_NetAlertRaiseEx) (
  108. IN LPCWSTR AlertEventName,
  109. IN LPVOID VariableInfo,
  110. IN DWORD VariableInfoSize,
  111. IN LPCWSTR ServiceName
  112. );
  113. //===========================
  114. // Globals
  115. //===========================
  116. DWORD ScShutdownInProgress = FALSE;
  117. //
  118. // For determining if the service controller is still in its
  119. // initialization code.
  120. //
  121. BOOL ScStillInitializing = TRUE;
  122. //
  123. // For the service controller to put up a popup to notify the first
  124. // logged on user if any boot, system, or auto start services failed
  125. // to start.
  126. //
  127. BOOL ScPopupStartFail = FALSE;
  128. //
  129. // Flag indicating whether or not NetLogon has been created, and we
  130. // have successfully connected to the Security Process .
  131. // If it hasn't then we need to look for it when it is created so that
  132. // we can synchronize with lsass appropriately.
  133. //
  134. BOOL ScConnectedToSecProc = FALSE;
  135. //
  136. // Linked list of names of boot or system start drivers which failed
  137. // to load. This list is logged to the eventlog.
  138. //
  139. LPFAILED_DRIVER ScFailedDrivers = NULL;
  140. DWORD ScTotalSizeFailedDrivers = 0;
  141. //
  142. // ScGlobalThisExePath gets initialized to the full path of where this
  143. // executable image is to be. This is later used to create an image
  144. // record for services that run in the context of this process.
  145. //
  146. LPWSTR ScGlobalThisExePath = NULL;
  147. //
  148. // ScGlobalSecurityExePath gets initialized to the full path of the
  149. // security process's executable image. This is later used to
  150. // determine if we need to initialize the security proc when starting
  151. // services (i.e., initialize if we start the first SecProc service)
  152. //
  153. LPWSTR ScGlobalSecurityExePath = NULL;
  154. //
  155. // ScGlobalProductType contains the product type for this machine.
  156. // Possiblilties are NtProductWinNt, NtProductLanManNt, NtProductServer.
  157. //
  158. NT_PRODUCT_TYPE ScGlobalProductType;
  159. //
  160. // Global variables used for safeboot support. g_szSafebootKey contains
  161. // the name of the safeboot key (minus the service name, which is filled
  162. // in by ScStartService for each service in start.cxx). g_dwSafebootLen
  163. // holds the length of the safeboot key name, minus the service name
  164. //
  165. WCHAR g_szSafebootKey[SAFEBOOT_KEY_LENGTH + MAX_SERVICE_NAME_LENGTH + 50 + 1] = SAFEBOOT_KEY;
  166. DWORD g_dwSafebootLen;
  167. DWORD g_SafeBootEnabled;
  168. //
  169. // Key handle for MPR provider change notification. Do this in
  170. // the SCM so we can avoid loading 3 DLLs (needed for calling the
  171. // client side of the PNP HW profile APIs) into every process that
  172. // uses mpr.dll.
  173. //
  174. HKEY g_hProviderKey;
  175. //
  176. // Handle to this process' token or to LocalSystem.
  177. //
  178. HANDLE g_hProcessToken;
  179. //=================================
  180. // prototypes
  181. //=================================
  182. BOOL
  183. ScGetStartEvent(
  184. LPHANDLE pScStartEvent
  185. );
  186. VOID
  187. ScPopupThread(
  188. DWORD StartFailFlag
  189. );
  190. VOID
  191. ScDestroyFailedDriverList(
  192. VOID
  193. );
  194. DWORD
  195. ScMakeFailedDriversOneString(
  196. LPWSTR *DriverList
  197. );
  198. LONG
  199. WINAPI
  200. ScUnhandledExceptionFilter(
  201. struct _EXCEPTION_POINTERS *ExceptionInfo
  202. );
  203. NTSTATUS
  204. SvcStartRPCProxys(
  205. VOID
  206. );
  207. NTSTATUS
  208. SvcStopRPCProxys(
  209. VOID
  210. );
  211. NTSTATUS
  212. ScCreateRpcEndpointSD(
  213. PSECURITY_DESCRIPTOR *ppSD
  214. );
  215. VOID
  216. SvcctrlMain (
  217. int argc,
  218. PCHAR argv[]
  219. )
  220. /*++
  221. Routine Description:
  222. This is the main routine for the Service Controller. It sets up
  223. the RPC interface.
  224. Arguments:
  225. Return Value:
  226. Note:
  227. --*/
  228. {
  229. RPC_STATUS status;
  230. NTSTATUS ntStatus;
  231. DWORD dwStatus;
  232. HANDLE ScStartEvent;
  233. HANDLE ThreadHandle;
  234. DWORD ThreadId;
  235. SC_RPC_LOCK Lock=NULL;
  236. KPRIORITY NewBasePriority = SCREG_BASE_PRIORITY;
  237. HANDLE AutoStartHandle = NULL;
  238. HKEY hKeySafeBoot;
  239. HANDLE hProviderEvent = NULL;
  240. TOKEN_PRIVILEGES TokenPrivs;
  241. //
  242. // Save bitwise flags to indicate the amount of initialization
  243. // work done so that if we hit an error along the way, the
  244. // appropriate amount of shutdown can occur.
  245. //
  246. DWORD ScInitState = 0;
  247. SetUnhandledExceptionFilter(&ScUnhandledExceptionFilter);
  248. //
  249. // Prevent critical errors from raising hard error popups and
  250. // halting services.exe. The flag below will have the system
  251. // send the errors to the process instead.
  252. //
  253. SetErrorMode(SEM_FAILCRITICALERRORS);
  254. RtlSetProcessIsCritical(TRUE, NULL, TRUE);
  255. #ifdef TIMING_TEST
  256. DWORD TickCount1;
  257. DWORD TickCount2;
  258. DWORD TickCount3;
  259. TickCount1 = GetTickCount();
  260. #endif // TIMING_TEST
  261. //
  262. // Turn off privileges that we don't need. Leave the handle to the token
  263. // open since it is now needed during Service startup processing. Make
  264. // sure all accesses needed by the rest of the SCM are specified here.
  265. //
  266. ntStatus = NtOpenProcessToken(NtCurrentProcess(),
  267. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE,
  268. &g_hProcessToken);
  269. if (!NT_SUCCESS(ntStatus))
  270. {
  271. goto CleanExit;
  272. }
  273. TokenPrivs.PrivilegeCount = 1;
  274. TokenPrivs.Privileges[0].Luid = RtlConvertLongToLuid(SE_CREATE_TOKEN_PRIVILEGE);
  275. TokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
  276. ntStatus = NtAdjustPrivilegesToken(g_hProcessToken,
  277. FALSE,
  278. &TokenPrivs,
  279. sizeof(TokenPrivs),
  280. NULL,
  281. NULL);
  282. if (!NT_SUCCESS(ntStatus))
  283. {
  284. goto CleanExit;
  285. }
  286. //
  287. // Create event that Service Controller will set when done starting all
  288. // Auto-Start services (including async devices). If this call fails,
  289. // it typically means somebody tried to start up a second instance of
  290. // services.exe (which is running in the user's context, not LocalSystem).
  291. //
  292. AutoStartHandle = CreateEvent(
  293. NULL, // Event Attributes
  294. TRUE, // ManualReset
  295. FALSE, // Initial State (not-signaled)
  296. SC_AUTOSTART_EVENT_NAME); // Name
  297. if (AutoStartHandle == NULL)
  298. {
  299. SC_LOG2(ERROR,
  300. "SvcctrlMain: CreateEvent( \"%ws\" ) failed %ld\n",
  301. SC_AUTOSTART_EVENT_NAME,
  302. GetLastError());
  303. goto CleanExit;
  304. }
  305. //
  306. // Create a string containing the pathname for this executable image
  307. // and one containing the pathname for the security proc image
  308. //
  309. {
  310. DWORD NumChars = 0;
  311. DWORD CharsReturned = 0;
  312. WCHAR Temp[1];
  313. //
  314. // Create the string for this Exe
  315. //
  316. NumChars = ExpandEnvironmentStringsW(SERVICES_EXPANDPATH,Temp,1);
  317. if (NumChars > 1) {
  318. ScGlobalThisExePath = (LPWSTR)LocalAlloc(
  319. LPTR,
  320. NumChars * sizeof(WCHAR));
  321. if (ScGlobalThisExePath == NULL) {
  322. SC_LOG0(ERROR,"Couldn't allocate for ThisExePath\n");
  323. goto CleanExit;
  324. }
  325. CharsReturned = ExpandEnvironmentStringsW(
  326. SERVICES_EXPANDPATH,
  327. ScGlobalThisExePath,
  328. NumChars);
  329. if (CharsReturned > NumChars) {
  330. SC_LOG0(ERROR,"Couldn't expand ThisExePath\n");
  331. goto CleanExit;
  332. }
  333. }
  334. //
  335. // Create the string for the security image
  336. //
  337. NumChars = ExpandEnvironmentStringsW(SECURITY_EXPANDPATH, Temp, 1);
  338. if (NumChars > 1) {
  339. ScGlobalSecurityExePath = (LPWSTR)LocalAlloc(LPTR,
  340. NumChars * sizeof(WCHAR));
  341. if (ScGlobalSecurityExePath == NULL) {
  342. SC_LOG0(ERROR,"Couldn't allocate for SecurityExePath\n");
  343. goto CleanExit;
  344. }
  345. CharsReturned = ExpandEnvironmentStringsW(
  346. SECURITY_EXPANDPATH,
  347. ScGlobalSecurityExePath,
  348. NumChars);
  349. if (CharsReturned > NumChars) {
  350. SC_LOG0(ERROR,"Couldn't expand SecurityExePath\n");
  351. goto CleanExit;
  352. }
  353. }
  354. }
  355. //
  356. // Create well-known SIDs
  357. //
  358. if (! NT_SUCCESS(ntStatus = ScCreateWellKnownSids())) {
  359. SC_LOG1(ERROR, "ScCreateWellKnownSids failed: %08lx\n", ntStatus);
  360. goto CleanExit;
  361. }
  362. ScInitState |= WELL_KNOWN_SIDS_CREATED;
  363. //
  364. // Set up the provider information for mpr.dll
  365. //
  366. dwStatus = ScRegOpenKeyExW(HKEY_LOCAL_MACHINE,
  367. PROVIDER_KEY_BASE L"\\" PROVIDER_KEY_ORDER,
  368. REG_OPTION_NON_VOLATILE,
  369. KEY_ALL_ACCESS,
  370. &g_hProviderKey);
  371. if (dwStatus == NO_ERROR)
  372. {
  373. hProviderEvent = CreateEvent(NULL,
  374. TRUE, // Manual-reset
  375. FALSE, // Nonsignaled
  376. NULL);
  377. if (hProviderEvent != NULL)
  378. {
  379. ScHandleProviderChange(hProviderEvent, FALSE);
  380. }
  381. else
  382. {
  383. SC_LOG1(ERROR,
  384. "SvcctrlMain: CreateEvent for provider event FAILED %d\n",
  385. GetLastError());
  386. ScRegCloseKey(g_hProviderKey);
  387. g_hProviderKey = NULL;
  388. }
  389. }
  390. else
  391. {
  392. SC_LOG1(ERROR,
  393. "SvcctrlMain: Unable to open provider key %d\n",
  394. dwStatus);
  395. }
  396. //
  397. // Create the event that the OpenSCManager will use to wait on the
  398. // service controller with.
  399. //
  400. if (!ScGetStartEvent(&ScStartEvent)) {
  401. SC_LOG0(ERROR,"SvcctrlMain: ScGetStartEvent Failed\n");
  402. goto CleanExit;
  403. }
  404. ScInitState |= SC_NAMED_EVENT_CREATED;
  405. //
  406. // Create security descriptor for SC Manager object to protect
  407. // the SC Manager databases
  408. //
  409. if (ScCreateScManagerObject() != NO_ERROR) {
  410. SC_LOG0(ERROR, "ScCreateScManagerObject failed\n");
  411. goto CleanExit;
  412. }
  413. ScInitState |= SC_MANAGER_OBJECT_CREATED;
  414. //
  415. // Get the ProductType.
  416. //
  417. if (!RtlGetNtProductType(&ScGlobalProductType)) {
  418. SC_LOG0(ERROR, "GetNtProductType failed\n");
  419. goto CleanExit;
  420. }
  421. //
  422. // Check the Boot Configuration and assure that the LastKnownGood
  423. // ControlSet is safe, and pointers are correct.
  424. // This function initializes the ScGlobalLastKnownGood flag.
  425. //
  426. if (!ScCheckLastKnownGood()) {
  427. SC_LOG0(ERROR, "ScCheckLastKnownGood failed\n");
  428. goto CleanExit;
  429. }
  430. //
  431. // Initialize data structures required to remove a service account.
  432. // They will be cleaned up by ScEndServiceAccount.
  433. //
  434. // NOTE: ScGetComputerNameAndMutex must be called before call to
  435. // ScInitDatabase because ScInitDatabase may delete a service
  436. // entry that was marked for delete from a previous boot.
  437. //
  438. if (! ScGetComputerNameAndMutex()) {
  439. SC_LOG0(ERROR, "ScGetComputerName failed\n");
  440. goto CleanExit;
  441. }
  442. //
  443. // Read installed services into memory
  444. //
  445. if (! ScInitDatabase()) {
  446. SC_LOG0(ERROR, "ScInitDatabase failed\n");
  447. goto CleanExit;
  448. }
  449. ScInitState |= SC_DATABASE_INITIALIZED;
  450. //
  451. // Initialize accounts functionality.
  452. //
  453. if (! ScInitServiceAccount()) {
  454. SC_LOG0(ERROR, "ScInitServiceAccount failed\n");
  455. goto CleanExit;
  456. }
  457. //
  458. // Create critical sections
  459. //
  460. ScInitStartImage();
  461. ScInitTransactNamedPipe();
  462. ScInitState |= CRITICAL_SECTIONS_CREATED;
  463. if (!CWorkItemContext::Init()) {
  464. SC_LOG0(ERROR, "CWorkItemContext::Init failed\n");
  465. goto CleanExit;
  466. }
  467. //
  468. // look to see if we booted in safeboot mode
  469. //
  470. dwStatus = RegOpenKey(HKEY_LOCAL_MACHINE,
  471. L"system\\currentcontrolset\\control\\safeboot\\option",
  472. &hKeySafeBoot);
  473. if (dwStatus == ERROR_SUCCESS) {
  474. //
  475. // we did in fact boot under safeboot control
  476. //
  477. ThreadId = sizeof(DWORD);
  478. dwStatus = RegQueryValueEx(hKeySafeBoot,
  479. L"OptionValue",
  480. NULL,
  481. NULL,
  482. (LPBYTE)&g_SafeBootEnabled,
  483. &ThreadId);
  484. if (dwStatus != ERROR_SUCCESS) {
  485. g_SafeBootEnabled = 0;
  486. }
  487. RegCloseKey(hKeySafeBoot);
  488. if (g_SafeBootEnabled) {
  489. g_dwSafebootLen = SAFEBOOT_KEY_LENGTH;
  490. switch (g_SafeBootEnabled) {
  491. case SAFEBOOT_MINIMAL:
  492. wcscpy(g_szSafebootKey + g_dwSafebootLen, SAFEBOOT_MINIMAL_STR_W);
  493. g_dwSafebootLen += (sizeof(SAFEBOOT_MINIMAL_STR_W) / sizeof(WCHAR)) - 1;
  494. break;
  495. case SAFEBOOT_NETWORK:
  496. wcscpy(g_szSafebootKey + g_dwSafebootLen, SAFEBOOT_NETWORK_STR_W);
  497. g_dwSafebootLen += (sizeof(SAFEBOOT_NETWORK_STR_W) / sizeof(WCHAR)) - 1;
  498. break;
  499. case SAFEBOOT_DSREPAIR:
  500. wcscpy(g_szSafebootKey + g_dwSafebootLen, SAFEBOOT_DSREPAIR_STR_W);
  501. g_dwSafebootLen += (sizeof(SAFEBOOT_DSREPAIR_STR_W) / sizeof(WCHAR)) - 1;
  502. break;
  503. default:
  504. SC_ASSERT(FALSE);
  505. break;
  506. }
  507. wcscpy(g_szSafebootKey + g_dwSafebootLen, L"\\");
  508. g_dwSafebootLen += 1;
  509. }
  510. }
  511. //
  512. // Perform initialization related to network drive arrival broadcasts.
  513. // (This addes another work item to the object watcher work list.)
  514. //
  515. ScInitBSM();
  516. //
  517. // Get the latest state of drivers started up by boot and system
  518. // init.
  519. //
  520. ScGetBootAndSystemDriverState();
  521. //
  522. // Create semaphores needed for handling start dependencies
  523. //
  524. if (! ScInitAutoStart()) {
  525. SC_LOG0(ERROR, "ScInitAutoStart failed\n");
  526. goto CleanExit;
  527. }
  528. ScInitState |= AUTO_START_INITIALIZED;
  529. //
  530. // Register this process with User32. This tells User32 to use the
  531. // value from HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control
  532. // \WaitToKillServiceTimeout (if it exists), rather than
  533. // HKEY_CURRENT_USER\Control Panel\Desktop\WaitToKillAppTimeout,
  534. // to decide how long to wait before killing us on shutdown.
  535. //
  536. if (! RegisterServicesProcess(GetCurrentProcessId())) {
  537. SC_LOG0(ERROR, "RegisterServicesProcess failed\n");
  538. }
  539. //
  540. // Lock the database until autostart is complete
  541. //
  542. status = ScLockDatabase(TRUE, SERVICES_ACTIVE_DATABASEW, &Lock);
  543. if (status != NO_ERROR) {
  544. SC_LOG1(ERROR, "ScLockDatabase failed during init %d\n",status);
  545. goto CleanExit;
  546. }
  547. //
  548. // Start the RPC server
  549. //
  550. SC_LOG0(TRACE, "Getting ready to start RPC server\n");
  551. //
  552. // Listen to common LRPC port.
  553. //
  554. PSECURITY_DESCRIPTOR pSD;
  555. status = ScCreateRpcEndpointSD(&pSD);
  556. if (!NT_SUCCESS(status))
  557. {
  558. status = RtlNtStatusToDosError(status);
  559. SC_LOG1(ERROR,
  560. "SvcctrlMain: ScCreateRpcEndpointSD failed %d\n",
  561. status);
  562. goto CleanExit;
  563. }
  564. status = RpcServerUseProtseqEp((unsigned short *)SVCS_LRPC_PROTOCOL,
  565. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  566. (unsigned short *)SVCS_LRPC_PORT,
  567. pSD);
  568. RtlDeleteSecurityObject(&pSD);
  569. pSD = NULL;
  570. if (status != RPC_S_OK)
  571. {
  572. SC_LOG1(ERROR, "RpcServerUseProtseqEp on LRPC failed: %d\n", status);
  573. goto CleanExit;
  574. }
  575. // Listen to named pipe endpoint and register interface.
  576. status = RpcpStartRpcServer(
  577. SVCS_RPC_PIPE,
  578. svcctl_ServerIfHandle);
  579. if (!NT_SUCCESS(status))
  580. {
  581. SC_LOG1(ERROR, "RpcpStartRpcServer: %lx\n",status);
  582. goto CleanExit;
  583. }
  584. ScInitState |= RPC_SERVER_STARTED;
  585. //
  586. // Signal the event that indicates that we are completely started.
  587. //
  588. if (!SetEvent(ScStartEvent))
  589. {
  590. SC_LOG1(ERROR, "Unable to set StartEvent: %d\n", GetLastError());
  591. }
  592. SC_LOG0(INFO,"Service Controller successfully initialized\n");
  593. //
  594. // Set up for proper shutdown.
  595. //
  596. if (!SetConsoleCtrlHandler(ScShutdownNotificationRoutine, TRUE))
  597. {
  598. SC_LOG1(ERROR, "SetConsoleCtrlHandler call failed %d\n",GetLastError());
  599. }
  600. if (!SetProcessShutdownParameters(SVCCTRL_SHUTDOWN_LEVEL, SHUTDOWN_NORETRY))
  601. {
  602. SC_LOG1(ERROR, "SetProcessShutdownParameters call failed %d\n",
  603. GetLastError());
  604. }
  605. SC_LOG0(TRACE,"** ** Service Controller can now accept shutdown system request\n");
  606. //
  607. // init SCE server. if it fails to intialize, the process will terminate
  608. //
  609. dwStatus = ScesrvInitializeServer(RpcpStartRpcServer);
  610. if (ERROR_SUCCESS != dwStatus)
  611. {
  612. //
  613. // event log is not up running yet.
  614. // just log a message to debugger
  615. // no need to shutdown services
  616. //
  617. SC_LOG(ERROR,"ScesrvInitializeServer failed to initialize! %lu\n", dwStatus);
  618. goto CleanExit;
  619. }
  620. //
  621. // Initialization is done, so give PnP a callback routine for them to call
  622. // when a service needs to receive a PnP event (callback in control.cxx) and
  623. // to validate a service calling RegisterDeviceNotification.
  624. //
  625. RegisterScmCallback(&ScSendPnPMessage, &ScValidatePnPService);
  626. SvcStartRPCProxys();
  627. //
  628. // Init the WMI events.
  629. //
  630. InitNCEvents();
  631. //
  632. // Auto-start services
  633. //
  634. dwStatus = ScAutoStartServices(&Lock);
  635. if (dwStatus != NO_ERROR)
  636. {
  637. SC_LOG1(ERROR,
  638. "SvcctrlMain: ScAutoStartServices failed %d\n",
  639. dwStatus);
  640. goto CleanExit;
  641. }
  642. //
  643. // Log event if any boot/system start drivers failed.
  644. //
  645. if (ScFailedDrivers != NULL)
  646. {
  647. LPWSTR DriverList;
  648. ScMakeFailedDriversOneString(&DriverList);
  649. ScLogEvent(
  650. NEVENT_BOOT_SYSTEM_DRIVERS_FAILED,
  651. DriverList
  652. );
  653. LocalFree(DriverList);
  654. ScDestroyFailedDriverList();
  655. }
  656. //
  657. // Spin a thread to put up popup if a service specified to start
  658. // automatically at boot has failed to start, or we are running the
  659. // last-known-good configuration.
  660. //
  661. // Only popup a message if we're running on a server -- Workstation
  662. // users get confused by the message and don't know where to look
  663. // to figure out what went wrong. Note that IsServer is not valid
  664. // during GUI-mode setup (the product type may be changing), but
  665. // the later call to SetupInProgress handles this.
  666. //
  667. // Don't popup any messages if we're booting into safe mode, since
  668. // several boot and system drivers are explicitly not started and
  669. // will result in a "false error" when the SCM notices they "failed"
  670. // to start.
  671. //
  672. // Don't popup any messages during setup/upgrade. (The most common
  673. // cause of messages during upgrade is dependence on netlogon, which
  674. // is disabled.)
  675. //
  676. if ((ScPopupStartFail || (ScGlobalLastKnownGood & REVERTED_TO_LKG))
  677. &&
  678. IsServer()
  679. &&
  680. !g_SafeBootEnabled
  681. &&
  682. (! SetupInProgress(NULL, NULL))) {
  683. //
  684. // Suppress the popups if NoPopupsOnBoot is indicated in the registry.
  685. //
  686. DWORD PopupStatus;
  687. BOOLEAN bPopups = TRUE; // FALSE means suppress popups on boot
  688. HKEY WindowsKey=NULL;
  689. PopupStatus = ScRegOpenKeyExW(
  690. HKEY_LOCAL_MACHINE,
  691. CONTROL_WINDOWS_KEY_W,
  692. REG_OPTION_NON_VOLATILE, // options
  693. KEY_READ, // desired access
  694. &WindowsKey
  695. );
  696. if (PopupStatus == ERROR_SUCCESS) {
  697. DWORD Type;
  698. DWORD Data;
  699. DWORD cbData = sizeof(Data);
  700. PopupStatus = ScRegQueryValueExW(
  701. WindowsKey,
  702. NOBOOTPOPUPS_VALUENAME_W,
  703. NULL,
  704. &Type,
  705. (LPBYTE) &Data,
  706. &cbData
  707. );
  708. //
  709. // Popups are suppressed if the NOBOOTPOPUPS_VALUENAME_W value is
  710. // present, is a REG_DWORD and is non-zero.
  711. //
  712. if (PopupStatus == ERROR_SUCCESS &&
  713. Type == REG_DWORD &&
  714. Data != 0) {
  715. bPopups = FALSE;
  716. }
  717. ScRegCloseKey(WindowsKey);
  718. }
  719. if (bPopups) {
  720. ThreadHandle = CreateThread(
  721. NULL,
  722. 0L,
  723. (LPTHREAD_START_ROUTINE) ScPopupThread,
  724. (LPVOID)(DWORD_PTR) ScPopupStartFail,
  725. 0L,
  726. &ThreadId
  727. );
  728. if (ThreadHandle == (HANDLE) NULL) {
  729. SC_LOG(TRACE,"CreateThread ScPopupThread failed %lu\n",
  730. GetLastError());
  731. }
  732. else {
  733. (void) CloseHandle(ThreadHandle);
  734. }
  735. }
  736. }
  737. //
  738. // Now we can allow database modifications from RPC callers.
  739. //
  740. ScUnlockDatabase(&Lock);
  741. #ifdef TIMING_TEST
  742. TickCount2 = GetTickCount();
  743. #endif
  744. //
  745. // Now switch to high priority class
  746. //
  747. (void) NtSetInformationProcess(
  748. NtCurrentProcess(),
  749. ProcessBasePriority,
  750. &NewBasePriority,
  751. sizeof(NewBasePriority));
  752. //
  753. // If we get this far, then from our point of view, the boot is
  754. // acceptable. We will now call the Accept Boot Program. This program
  755. // will decide whether or not the boot was good (from the administrators)
  756. // point of view.
  757. // Our default program simply says the boot was good - thus causing
  758. // LastKnownGood to be updated to the current boot.
  759. //
  760. ScRunAcceptBootPgm();
  761. //
  762. // Now that the Auto-start services have been started, notify
  763. // Terminal Server so that additional Sessions can be started.
  764. //
  765. if ( AutoStartHandle )
  766. NtSetEvent( AutoStartHandle, NULL );
  767. //
  768. // Setup complete -
  769. // This thread will become the service process watcher. Service
  770. // process handles are stored in an array of waitble objects that
  771. // the watcher thread waits on. When any ProcessHandle becomes
  772. // signaled while in this array, this indicates that the process has
  773. // terminated unexpectedly. The watcher thread then cleans up the
  774. // service controller database.
  775. //
  776. ScStillInitializing = FALSE;
  777. #ifdef TIMING_TEST
  778. TickCount3 = GetTickCount();
  779. DbgPrint("[SC_TIMING] Tick Count for autostart complete \t %d\n",TickCount2);
  780. DbgPrint("[SC-TIMING] MSec for Autostart: \t%d\n",TickCount2-TickCount1);
  781. DbgPrint("[SC-TIMING] MSec for LKG work: \t%d\n",TickCount3-TickCount2);
  782. DbgPrint("[SC-TIMING] MSec to complete init:\t%d\n",TickCount3-TickCount1);
  783. #endif
  784. ExitThread(NO_ERROR);
  785. CleanExit:
  786. //
  787. // Do minimal cleanup and let process cleanup take care of the rest.
  788. // Note that the full-blown cleanup was removed in January, 2000 as
  789. // it was for the most part unnecessary. If some of it ends up being
  790. // needed, it should be available via the checkin history.
  791. //
  792. ScStillInitializing = FALSE;
  793. ScEndServiceAccount();
  794. SvcStopRPCProxys();
  795. //
  796. // Shut down the RPC server.
  797. //
  798. SC_LOG0(TRACE,"Shutting down the RPC interface for the Service Controller\n");
  799. if (ScInitState & RPC_SERVER_STARTED)
  800. {
  801. status = RpcpStopRpcServer(svcctl_ServerIfHandle);
  802. }
  803. if (Lock != NULL)
  804. {
  805. ScUnlockDatabase(&Lock);
  806. }
  807. //
  808. // terminate SCE server
  809. //
  810. ScesrvTerminateServer( (PSVCS_STOP_RPC_SERVER) RpcpStopRpcServer );
  811. SC_LOG0(ERROR,"The Service Controller is Terminating.\n");
  812. ExitThread(0);
  813. return;
  814. }
  815. BOOL
  816. ScShutdownNotificationRoutine(
  817. DWORD dwCtrlType
  818. )
  819. /*++
  820. Routine Description:
  821. This routine is called by the system when system shutdown is occuring.
  822. Arguments:
  823. Return Value:
  824. --*/
  825. {
  826. if (dwCtrlType == CTRL_SHUTDOWN_EVENT) {
  827. SC_LOG0(TRACE," ! SHUTDOWN ! - - In ScShutdownNotificationRoutine\n");
  828. #ifndef SC_DEBUG
  829. //
  830. // First quiet all RPC interfaces
  831. //
  832. ScShutdownInProgress = TRUE;
  833. #endif
  834. //
  835. // Then shut down all services
  836. //
  837. SC_LOG0(TRACE,"[Shutdown] Begin Service Shutdown\n");
  838. ScShutdownAllServices();
  839. }
  840. return(TRUE);
  841. }
  842. VOID
  843. ScLogControlEvent(
  844. DWORD dwEvent,
  845. LPCWSTR lpServiceName,
  846. DWORD dwControl
  847. )
  848. /*++
  849. Routine Description:
  850. Wrapper for logging service control events
  851. Arguments:
  852. Return Value:
  853. --*/
  854. {
  855. WCHAR wszControlString[50];
  856. DWORD dwStringBase;
  857. //
  858. // Load the string that corresponts to this control
  859. //
  860. switch (dwEvent)
  861. {
  862. case NEVENT_SERVICE_CONTROL_SUCCESS:
  863. dwStringBase = IDS_SC_CONTROL_BASE;
  864. break;
  865. case NEVENT_SERVICE_STATUS_SUCCESS:
  866. dwStringBase = IDS_SC_STATUS_BASE;
  867. break;
  868. case NEVENT_SERVICE_CONFIG_BACKOUT_FAILED:
  869. dwStringBase = 0; // dwControl is the resource ID
  870. break;
  871. default:
  872. ASSERT(FALSE);
  873. return;
  874. }
  875. if (!LoadString(GetModuleHandle(NULL),
  876. dwStringBase + dwControl,
  877. wszControlString,
  878. LENGTH(wszControlString)))
  879. {
  880. //
  881. // The control has no string associated with it
  882. // (i.e., not a control we log).
  883. //
  884. return;
  885. }
  886. if (dwEvent == NEVENT_SERVICE_CONTROL_SUCCESS)
  887. {
  888. //
  889. // Include the user that sent the control. Use the empty
  890. // string on failure (better that than dropping the event).
  891. //
  892. PTOKEN_USER pToken = NULL;
  893. LPWSTR lpStringSid = NULL;
  894. if (ScGetClientSid(&pToken) == NO_ERROR)
  895. {
  896. if (!ConvertSidToStringSid(pToken->User.Sid, &lpStringSid))
  897. {
  898. lpStringSid = NULL;
  899. }
  900. }
  901. else
  902. {
  903. pToken = NULL;
  904. }
  905. ScLogEvent(dwEvent,
  906. lpServiceName,
  907. wszControlString,
  908. lpStringSid);
  909. LocalFree(lpStringSid);
  910. LocalFree(pToken);
  911. }
  912. else
  913. {
  914. ScLogEvent(dwEvent,
  915. lpServiceName,
  916. wszControlString);
  917. }
  918. }
  919. BOOL
  920. ScGetStartEvent(
  921. LPHANDLE pScStartEvent
  922. )
  923. /*++
  924. Routine Description:
  925. This function gets a handle to the SC_INTERNAL_START_EVENT that is
  926. used to wait on the service controller when calling OpenSCManager.
  927. Arguments:
  928. pScStartEvent - This is a pointer to the location where the handle
  929. to the event is to be placed.
  930. Return Value:
  931. TRUE - If a handle was obtained.
  932. FALSE - If a handle was not obtained.
  933. --*/
  934. {
  935. DWORD status;
  936. HANDLE ScStartEvent = NULL;
  937. SECURITY_ATTRIBUTES SecurityAttributes;
  938. PSECURITY_DESCRIPTOR SecurityDescriptor=NULL;
  939. //
  940. // Initialize the status so that if we fail to create the security
  941. // descriptor, we will still try to open the event.
  942. //
  943. status = ERROR_ALREADY_EXISTS;
  944. //
  945. // Create the event that the OpenSCManager will use to wait on the
  946. // service controller with.
  947. //
  948. status = ScCreateStartEventSD(&SecurityDescriptor);
  949. if (status == NO_ERROR) {
  950. SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  951. SecurityAttributes.bInheritHandle = FALSE;
  952. SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
  953. ScStartEvent = CreateEventW(
  954. &SecurityAttributes,
  955. TRUE, // Must be manually reset
  956. FALSE, // The event is initially not signalled
  957. SC_INTERNAL_START_EVENT );
  958. if (ScStartEvent == NULL) {
  959. status = GetLastError();
  960. }
  961. LocalFree(SecurityDescriptor);
  962. }
  963. else {
  964. SC_LOG0(ERROR,"ScGetStartEvent: Couldn't allocate for SecurityDesc\n");
  965. }
  966. if (ScStartEvent == NULL){
  967. //
  968. // If the event already exists, some other process beat us to
  969. // creating it. Just open it.
  970. //
  971. if ( status == ERROR_ALREADY_EXISTS ) {
  972. ScStartEvent = OpenEvent(
  973. GENERIC_WRITE,
  974. FALSE,
  975. SC_INTERNAL_START_EVENT );
  976. }
  977. if (ScStartEvent == NULL ) {
  978. SC_LOG1(ERROR,"GetStartEvent: OpenEvent (StartEvent) Failed "
  979. FORMAT_DWORD "\n", status);
  980. return(FALSE);
  981. }
  982. }
  983. *pScStartEvent = ScStartEvent;
  984. return(TRUE);
  985. }
  986. VOID
  987. ScPopupThread(
  988. DWORD StartFailFlag
  989. )
  990. /*++
  991. Routine Description:
  992. This function reports the state of the system that has just booted.
  993. If we are running last-known-good:
  994. 1) Raise an admin alert
  995. 2) Put up a message box popup
  996. If a service has failed to start (StartFailFlag is TRUE):
  997. 1) Put up a message box popup
  998. The reason the StartFailFlag is a parameter is because its value
  999. may change while we are in this thread. We only care about
  1000. its value at the time this thread is created.
  1001. Arguments:
  1002. StartFailFlag - Supplies a flag which indicates whether to put
  1003. up a popup due to services which failed to start.
  1004. Return Value:
  1005. None.
  1006. --*/
  1007. {
  1008. #define POPUP_BUFFER_CHARS 256
  1009. DWORD MessageSize;
  1010. HMODULE NetEventDll;
  1011. WCHAR Buffer[POPUP_BUFFER_CHARS];
  1012. WCHAR Title[POPUP_BUFFER_CHARS];
  1013. LPWSTR pTitle=NULL;
  1014. HMODULE NetApi32Dll = NULL;
  1015. PF_NetAlertRaiseEx ScNetAlertRaiseEx = NULL;
  1016. KPRIORITY NewBasePriority = SCREG_BASE_PRIORITY;
  1017. if (ScGlobalLastKnownGood & REVERTED_TO_LKG) {
  1018. //
  1019. // Get address to API NetAlertRaiseEx to raise an Admin alert
  1020. //
  1021. NetApi32Dll = LoadLibraryW(L"netapi32.dll");
  1022. if (NetApi32Dll != NULL) {
  1023. ScNetAlertRaiseEx = (PF_NetAlertRaiseEx) GetProcAddress(
  1024. NetApi32Dll,
  1025. "NetAlertRaiseEx"
  1026. );
  1027. if (ScNetAlertRaiseEx != NULL) {
  1028. PADMIN_OTHER_INFO Admin;
  1029. //
  1030. // Raise an admin alert
  1031. //
  1032. Admin = (PADMIN_OTHER_INFO) Buffer;
  1033. Admin->alrtad_errcode = ALERT_SC_IsLastKnownGood;
  1034. Admin->alrtad_numstrings = 0;
  1035. (void) ScNetAlertRaiseEx(
  1036. ALERT_ADMIN_EVENT,
  1037. Buffer,
  1038. sizeof(ADMIN_OTHER_INFO),
  1039. SCM_NAMEW
  1040. );
  1041. }
  1042. FreeLibrary(NetApi32Dll);
  1043. }
  1044. }
  1045. NetEventDll = LoadLibraryW(L"netevent.dll");
  1046. if (NetEventDll == NULL) {
  1047. return;
  1048. }
  1049. MessageSize = FormatMessageW(
  1050. FORMAT_MESSAGE_FROM_HMODULE,
  1051. (LPVOID) NetEventDll,
  1052. TITLE_SC_MESSAGE_BOX,
  1053. 0,
  1054. Title,
  1055. POPUP_BUFFER_CHARS,
  1056. NULL
  1057. );
  1058. if (MessageSize == 0 ) {
  1059. pTitle = SCM_NAMEW;
  1060. }
  1061. else {
  1062. pTitle = Title;
  1063. }
  1064. if (ScGlobalLastKnownGood & REVERTED_TO_LKG) {
  1065. MessageSize = FormatMessageW(
  1066. FORMAT_MESSAGE_FROM_HMODULE,
  1067. (LPVOID) NetEventDll,
  1068. EVENT_RUNNING_LASTKNOWNGOOD,
  1069. 0,
  1070. Buffer,
  1071. POPUP_BUFFER_CHARS,
  1072. NULL
  1073. );
  1074. if (MessageSize != 0) {
  1075. (void) MessageBoxW(
  1076. NULL,
  1077. Buffer,
  1078. pTitle,
  1079. MB_OK | MB_SETFOREGROUND | MB_ICONEXCLAMATION |
  1080. MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION
  1081. );
  1082. //
  1083. // Now switch back to proper priority
  1084. //
  1085. NtSetInformationProcess(NtCurrentProcess(),
  1086. ProcessBasePriority,
  1087. &NewBasePriority,
  1088. sizeof(NewBasePriority));
  1089. }
  1090. else {
  1091. SC_LOG1(TRACE, "FormatMessage failed %lu\n", GetLastError());
  1092. }
  1093. }
  1094. //
  1095. // Popup a message if a service failed to start
  1096. //
  1097. if (StartFailFlag) {
  1098. MessageSize = FormatMessageW(
  1099. FORMAT_MESSAGE_FROM_HMODULE,
  1100. (LPVOID) NetEventDll,
  1101. EVENT_SERVICE_START_AT_BOOT_FAILED,
  1102. 0,
  1103. Buffer,
  1104. POPUP_BUFFER_CHARS,
  1105. NULL
  1106. );
  1107. if (MessageSize != 0) {
  1108. MessageBoxW(NULL,
  1109. Buffer,
  1110. pTitle,
  1111. MB_OK | MB_SETFOREGROUND | MB_ICONEXCLAMATION |
  1112. MB_SYSTEMMODAL | MB_SERVICE_NOTIFICATION);
  1113. //
  1114. // Now switch back to proper priority
  1115. //
  1116. NtSetInformationProcess(NtCurrentProcess(),
  1117. ProcessBasePriority,
  1118. &NewBasePriority,
  1119. sizeof(NewBasePriority));
  1120. }
  1121. else {
  1122. SC_LOG1(TRACE, "FormatMessage failed %lu\n", GetLastError());
  1123. }
  1124. }
  1125. FreeLibrary(NetEventDll);
  1126. //
  1127. // Now switch to high priority class
  1128. //
  1129. ExitThread(0);
  1130. }
  1131. DWORD
  1132. ScAddFailedDriver(
  1133. LPWSTR Driver
  1134. )
  1135. {
  1136. DWORD StrSize = (DWORD) WCSSIZE(Driver);
  1137. LPFAILED_DRIVER NewEntry;
  1138. LPFAILED_DRIVER Entry;
  1139. NewEntry = (LPFAILED_DRIVER) LocalAlloc(
  1140. LMEM_ZEROINIT,
  1141. (UINT) sizeof(FAILED_DRIVER) + StrSize
  1142. );
  1143. if (NewEntry == NULL) {
  1144. return ERROR_NOT_ENOUGH_MEMORY;
  1145. }
  1146. //
  1147. // Each string will be separated from the previous one a CR and
  1148. // LF character. We already included one for NULL terminator of each
  1149. // driver so add one more.
  1150. //
  1151. ScTotalSizeFailedDrivers += StrSize + sizeof(WCHAR);
  1152. wcscpy((LPWSTR) NewEntry->DriverName, Driver);
  1153. //
  1154. // Insert new entry into ScFailedDrivers global list
  1155. //
  1156. //
  1157. // Special case empty list
  1158. //
  1159. if (ScFailedDrivers == NULL) {
  1160. ScFailedDrivers = NewEntry;
  1161. return NO_ERROR;
  1162. }
  1163. //
  1164. // Otherwise look for end of the list and insert new entry
  1165. //
  1166. Entry = ScFailedDrivers;
  1167. while (Entry->Next != NULL) {
  1168. Entry = Entry->Next;
  1169. }
  1170. Entry->Next = NewEntry;
  1171. return NO_ERROR;
  1172. }
  1173. VOID
  1174. ScDestroyFailedDriverList(
  1175. VOID
  1176. )
  1177. {
  1178. LPFAILED_DRIVER DeleteEntry;
  1179. while (ScFailedDrivers != NULL) {
  1180. DeleteEntry = ScFailedDrivers;
  1181. ScFailedDrivers = ScFailedDrivers->Next;
  1182. LocalFree(DeleteEntry);
  1183. }
  1184. }
  1185. DWORD
  1186. ScMakeFailedDriversOneString(
  1187. LPWSTR *DriverList
  1188. )
  1189. {
  1190. LPFAILED_DRIVER Entry = ScFailedDrivers;
  1191. //
  1192. // Allocate space for concatenated string of all the drivers that
  1193. // failed plus the terminator character.
  1194. //
  1195. *DriverList = (LPWSTR) LocalAlloc(
  1196. LMEM_ZEROINIT,
  1197. (UINT) ScTotalSizeFailedDrivers + sizeof(WCHAR)
  1198. );
  1199. if (*DriverList == NULL) {
  1200. return ERROR_NOT_ENOUGH_MEMORY;
  1201. }
  1202. while (Entry != NULL) {
  1203. wcscat(*DriverList, L"\r\n");
  1204. wcscat(*DriverList, (LPWSTR) Entry->DriverName);
  1205. Entry = Entry->Next;
  1206. }
  1207. return NO_ERROR;
  1208. }
  1209. LONG
  1210. WINAPI
  1211. ScUnhandledExceptionFilter(
  1212. struct _EXCEPTION_POINTERS *ExceptionInfo
  1213. )
  1214. {
  1215. return RtlUnhandledExceptionFilter(ExceptionInfo);
  1216. }
  1217. NTSTATUS
  1218. SvcStartRPCProxys(
  1219. VOID
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. This function calls the RPC Proxy startup routines for the
  1224. services that were moved out of services.exe, but have existing
  1225. clients that rely on the services.exe named pipe
  1226. Arguments:
  1227. Return Value:
  1228. STATUS_SUCCESS - If proxys were started
  1229. --*/
  1230. {
  1231. NTSTATUS dwStatus = STATUS_SUCCESS;
  1232. dwStatus = StartCryptServiceStubs(RpcpStartRpcServer,
  1233. SVCS_RPC_PIPE);
  1234. // Start the RPC stubs for the distributed link tracking client service.
  1235. dwStatus = StartTrkWksServiceStubs( RpcpStartRpcServer,
  1236. SVCS_RPC_PIPE );
  1237. return dwStatus;
  1238. }
  1239. NTSTATUS
  1240. SvcStopRPCProxys(
  1241. VOID
  1242. )
  1243. /*++
  1244. Routine Description:
  1245. This function calls the RPC Proxy startup routines for the
  1246. services that were moved out of services.exe, but have existing
  1247. clients that rely on the services.exe named pipe
  1248. Arguments:
  1249. Return Value:
  1250. STATUS_SUCCESS - If proxys were started
  1251. --*/
  1252. {
  1253. NTSTATUS dwStatus = STATUS_SUCCESS;
  1254. dwStatus = StopCryptServiceStubs(RpcpStopRpcServer);
  1255. // Stop the RPC stubs for the distributed link tracking client service.
  1256. dwStatus = StopTrkWksServiceStubs(RpcpStopRpcServer);
  1257. return dwStatus;
  1258. }
  1259. NTSTATUS
  1260. ScCreateRpcEndpointSD(
  1261. PSECURITY_DESCRIPTOR *ppSD
  1262. )
  1263. /*++
  1264. Routine Description:
  1265. This function builds a security descriptor for the SCM's
  1266. shared LPC endpoint. Everybody needs access to call it.
  1267. Arguments:
  1268. ppSD -- pointer to an SD that this routine will allocate
  1269. Return Value:
  1270. STATUS_SUCCESS - if SD was successfully created
  1271. --*/
  1272. {
  1273. #define SC_ENDPOINT_ACECOUNT 3
  1274. SC_ACE_DATA AceData[SC_ENDPOINT_ACECOUNT] = {
  1275. { ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  1276. GENERIC_ALL,
  1277. &LocalSystemSid },
  1278. { ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  1279. GENERIC_ALL,
  1280. &AliasAdminsSid },
  1281. { ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  1282. GENERIC_READ | GENERIC_WRITE |
  1283. GENERIC_EXECUTE | SYNCHRONIZE,
  1284. &WorldSid }
  1285. };
  1286. return ScCreateAndSetSD(AceData,
  1287. SC_ENDPOINT_ACECOUNT,
  1288. NULL, // owner
  1289. NULL, // group
  1290. ppSD);
  1291. #undef SC_ENDPOINT_ACECOUNT
  1292. }