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.

2331 lines
72 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. control.cxx
  5. Abstract:
  6. Contains code for setting up and maintaining the control interface
  7. and sending controls to services. Functions in this module:
  8. RControlService
  9. RI_ScSendTSMessage
  10. ScCreateControlInstance
  11. ScWaitForConnect
  12. ScSendControl
  13. ScInitTransactNamedPipe
  14. ScShutdownAllServices
  15. Author:
  16. Dan Lafferty (danl) 20-Mar-1991
  17. Environment:
  18. User Mode -Win32
  19. Revision History:
  20. 13-Mar-1999 jschwart
  21. Added per-account security on the SCM <--> service control pipe
  22. 07-Apr-1998 jschwart
  23. ScInitTransactNamedPipe: Check registry for a user-supplied named
  24. pipe timeout value before setting it to the default. With the old
  25. default (30000 ms), services could be double-started on a heavily
  26. loaded machine when the server would send to the client, the client's
  27. response would time out, and the server would assume it hadn't started.
  28. 10-Mar-1998 jschwart
  29. Added ScSendPnPMessage and code to ScSendControl to enable passing
  30. of PnP-related service controls to services. Got rid of flag added
  31. on 06-Aug-1997 since we can just check the passed-in OpCode instead
  32. 06-Aug-1997 jschwart
  33. SendControl: Added flag to tell SendControl if it is sending a
  34. shutdown message. If so, it uses WriteFile, since using
  35. TransactNamedPipe with a poorly behaved service (that doesn't send
  36. an ACK back to the SCM) otherwise hangs the SCM.
  37. ShutdownAllServices: Since SendControl now uses WriteFile (asynch
  38. write), added a case to the switch that checks to see if any services
  39. are still running. If so, it gives them 30 seconds to become
  40. STOP_PENDING before it gives up and shuts itself down.
  41. 05-Mar-1997 AnirudhS
  42. Eliminated limit of 100 pipe instances.
  43. 04-Mar-1997 AnirudhS
  44. Added PARAMCHANGE, NETBINDADD, etc. controls for Plug and Play.
  45. 28-May-1996 AnirudhS
  46. ScSendControl, ScWaitForConnect and ScCleanoutPipe: If we time out
  47. waiting for a named pipe operation to complete, cancel it before
  48. returning. Otherwise it trashes the stack if it does complete later.
  49. 21-Feb-1995 AnirudhS
  50. ScShutdownAllServices: Fixed logic to wait for services in pending
  51. stop state.
  52. 19-Oct-1993 Danl
  53. Initialize the Overlapped structures that are allocated on the stack.
  54. 20-Jul-1993 danl
  55. SendControl: If we get ERROR_PIPE_BUSY back from the transact call,
  56. then we need to clean out the pipe by reading it first - then do
  57. the transact.
  58. 29-Dec-1992 danl
  59. Simplified calculation of elapsed time. This removed complier
  60. warning about overflow in constant arithmetic.
  61. 06-Mar-1992 danl
  62. SendControl: Fixed heap trashing problem where it didn't allocate
  63. the 4 extra alignment bytes in the case where there are no arguments.
  64. The registry name path becomes an argument even if there are no
  65. other agruments. Therefore it requires alignment for any start cmd.
  66. 20-Feb-1992 danl
  67. Get Pipe Handle only after we know we have an active service & the
  68. image record is good.
  69. 20-Feb-1992 danl
  70. Only add 4 extra alignment bytes to control buffer when there
  71. are arguments to pass.
  72. 31-Oct-1991 danl
  73. Fixed the logic governing the behavior under various service state
  74. and control opcode conditions. Added State Table to description.
  75. This logic was taken directly from LM2.0.
  76. 03-Sept-1991 danl
  77. Fixed alignment problem when marshalling args in ScSendControl.
  78. The array of offsets needs to be 4 byte aligned after the Service
  79. Name.
  80. 20-Mar-1991 danl
  81. created
  82. --*/
  83. //
  84. // INCLUDES
  85. //
  86. #include "precomp.hxx"
  87. #include <stdlib.h> // wide character c runtimes.
  88. #include <tstr.h> // Unicode string macros
  89. #include <align.h> // ROUND_UP_POINTER macro
  90. #include <control.h>
  91. #include <scseclib.h> // ScCreateAndSetSD
  92. #include "depend.h" // ScDependentsStopped()
  93. #include "driver.h" // ScControlDriver()
  94. #include "sclib.h" // ScIsValidServiceName()
  95. #include "scsec.h" // ScStatusAccessCheck()
  96. #include "valid.h" // MAX_SERVICE_NAME_LENGTH
  97. #include <dbt.h> // PDEV_BROADCAST_HDR
  98. #include <ntrpcp.h> // Rpcp... function prototypes
  99. #include <svcs.h> // SVCS_RPC_PIPE, SVCS_LRPC_PROTOCOl, SVCS_LRPC_PORT
  100. #include <scesrv.h>
  101. //
  102. // Constants
  103. //
  104. #define SC_DEFAULT_PIPE_TRANSACT_TIMEOUT 30000 // 30 sec
  105. #define SC_PIPE_CLEANOUT_TIMEOUT 30 // 30 msec
  106. //
  107. // Registry key and value for the pipe timeout value
  108. //
  109. #define REGKEY_PIPE_TIMEOUT L"System\\CurrentControlSet\\Control"
  110. #define REGVAL_PIPE_TIMEOUT L"ServicesPipeTimeout"
  111. //
  112. // Registry key, value, and constant for the shutdown performance metric
  113. //
  114. // #define SC_SHUTDOWN_METRIC
  115. #ifdef SC_SHUTDOWN_METRIC
  116. #define REGKEY_SHUTDOWN_TIMEOUT L"System\\CurrentControlSet\\Control"
  117. #define REGVAL_SHUTDOWN_TIMEOUT L"ShutdownTimeout"
  118. #endif // SC_SHUTDOWN_METRIC
  119. //
  120. // STATIC DATA
  121. //
  122. /* static */ CRITICAL_SECTION ScTransactNPCriticalSection;
  123. //
  124. // Globals
  125. //
  126. DWORD g_dwScPipeTransactTimeout = SC_DEFAULT_PIPE_TRANSACT_TIMEOUT;
  127. //
  128. // Local Structure/Function Prototypes
  129. //
  130. typedef struct
  131. {
  132. WCHAR lpServiceName[MAX_SERVICE_NAME_LENGTH + 1];
  133. WCHAR lpDisplayName[MAX_SERVICE_NAME_LENGTH + 1];
  134. HANDLE hPipe;
  135. }
  136. TS_CONTROL_INFO, *PTS_CONTROL_INFO, *LPTS_CONTROL_INFO;
  137. VOID
  138. ScCleanOutPipe(
  139. HANDLE PipeHandle
  140. );
  141. /****************************************************************************/
  142. DWORD
  143. RControlService (
  144. IN SC_RPC_HANDLE hService,
  145. IN DWORD OpCode,
  146. OUT LPSERVICE_STATUS lpServiceStatus
  147. )
  148. /*++
  149. Routine Description:
  150. RPC entry point for the RControlService API function.
  151. The following state table describes what is to happen under various
  152. state/Opcode conditions:
  153. [OpCode]
  154. STOP INTERROGATE OTHER
  155. [Current State] _____________________________________
  156. | | | |
  157. STOPPED | (c) | (c) | (c) |
  158. | | | |
  159. STOP_PENDING | (b) | (b) | (b) |
  160. | | | |
  161. START_PEND | (a) | (d) | (b) |
  162. | | | |
  163. RUNNING | (a) | (a) | (a) |
  164. | | | |
  165. CONTINUE_PEND | (a) | (a) | (a) |
  166. | | | |
  167. PAUSE_PENDING | (a) | (a) | (a) |
  168. | | | |
  169. PAUSED | (a) | (a) | (a) |
  170. |___________|____________|____________|
  171. (a) Send control code to the service if the service is set up
  172. to receive this type of opcode. If it is not set up to
  173. receive the opcode, return ERROR_INVALID_SERVICE_CONTROL.
  174. An example of this would be the case of sending a PAUSE to a
  175. service that is listed as NOT_PAUSABLE.
  176. (b) Do NOT send control code to the service. Instead return
  177. ERROR_SERVICE_CANNOT_ACCEPT_CTRL.
  178. (c) Do NOT send control code to the service. Instead, return
  179. ERROR_SERVICE_NOT_ACTIVE.
  180. (d) Do NOT send control code to the service. Instead, return
  181. the last known state of the service with a SUCCESS status.
  182. NOTE -- this case (and this case only) differs from the
  183. SDK doc, which hides the fact that you can interrogate a
  184. service that's in the START_PENDING state
  185. Arguments:
  186. hService - This is a handle to the service. It is actually a pointer
  187. to a service handle structure.
  188. OpCode - The control request code.
  189. lpServiceStatus - pointer to a location where the service status is to
  190. be returned. If this pointer is invalid, it will be set to NULL
  191. upon return.
  192. Return Value:
  193. The returned lpServiceStatus structure is valid as long as the returned
  194. status is NO_ERROR.
  195. NO_ERROR - The operation was successful.
  196. ERROR_INVALID_HANDLE - The handle passed in was not a valid hService
  197. handle.
  198. NERR_InternalError - LocalAlloc or TransactNamedPipe failed, or
  199. TransactNamedPipe returned fewer bytes than expected.
  200. ERROR_SERVICE_REQUEST_TIMEOUT - The service did not respond with a status
  201. message within the fixed timeout limit (RESPONSE_WAIT_TIMEOUT).
  202. NERR_ServiceKillProc - The service process had to be killed because
  203. it wouldn't terminate when requested.
  204. ERROR_SERVICE_CANNOT_ACCEPT_CTRL - The service cannot accept control
  205. messages at this time.
  206. ERROR_INVALID_SERVICE_CONTROL - The request is not valid for this service.
  207. For instance, a PAUSE request is not valid for a service that
  208. lists itself as NOT_PAUSABLE.
  209. ERROR_INVALID_PARAMETER - The requested control is not valid.
  210. ERROR_ACCESS_DENIED - This is a status response from the service
  211. security check.
  212. Note:
  213. Because there are multiple services in a process, we cannot simply
  214. kill the process if the service does not respond to a terminate
  215. request. This situation is handled by first checking to see if
  216. this is the last service in the process. If it is, then it is
  217. removed from the installed database, and the process is terminated.
  218. If it isn't the last service, then we indicate timeout and do
  219. nothing.
  220. --*/
  221. {
  222. DWORD status = NO_ERROR;
  223. LPSERVICE_RECORD serviceRecord;
  224. DWORD currentState;
  225. DWORD controlsAccepted;
  226. DWORD controlsAcceptedMask = 0;
  227. HANDLE pipeHandle = NULL;
  228. LPWSTR serviceName = NULL;
  229. LPWSTR displayName = NULL;
  230. ACCESS_MASK desiredAccess;
  231. if (ScShutdownInProgress)
  232. {
  233. return(ERROR_SHUTDOWN_IN_PROGRESS);
  234. }
  235. //
  236. // Check the handle.
  237. //
  238. if (!ScIsValidServiceHandle(hService))
  239. {
  240. return ERROR_INVALID_HANDLE;
  241. }
  242. //
  243. // Set the desired access based on the control requested.
  244. // Figure out which "controls accepted" bits must be set for the
  245. // service to accept the control.
  246. //
  247. switch (OpCode) {
  248. case SERVICE_CONTROL_STOP:
  249. desiredAccess = SERVICE_STOP;
  250. controlsAcceptedMask = SERVICE_ACCEPT_STOP;
  251. break;
  252. case SERVICE_CONTROL_PAUSE:
  253. case SERVICE_CONTROL_CONTINUE:
  254. desiredAccess = SERVICE_PAUSE_CONTINUE;
  255. controlsAcceptedMask = SERVICE_ACCEPT_PAUSE_CONTINUE;
  256. break;
  257. case SERVICE_CONTROL_INTERROGATE:
  258. desiredAccess = SERVICE_INTERROGATE;
  259. break;
  260. case SERVICE_CONTROL_PARAMCHANGE:
  261. desiredAccess = SERVICE_PAUSE_CONTINUE;
  262. controlsAcceptedMask = SERVICE_ACCEPT_PARAMCHANGE;
  263. break;
  264. case SERVICE_CONTROL_NETBINDADD:
  265. case SERVICE_CONTROL_NETBINDREMOVE:
  266. case SERVICE_CONTROL_NETBINDENABLE:
  267. case SERVICE_CONTROL_NETBINDDISABLE:
  268. desiredAccess = SERVICE_PAUSE_CONTINUE;
  269. controlsAcceptedMask = SERVICE_ACCEPT_NETBINDCHANGE;
  270. break;
  271. default:
  272. if ((OpCode >= OEM_LOWER_LIMIT) &&
  273. (OpCode <= OEM_UPPER_LIMIT))
  274. {
  275. desiredAccess = SERVICE_USER_DEFINED_CONTROL;
  276. }
  277. else
  278. {
  279. return ERROR_INVALID_PARAMETER;
  280. }
  281. }
  282. //
  283. // Was the handle opened with desired control access?
  284. //
  285. if (! RtlAreAllAccessesGranted(
  286. ((LPSC_HANDLE_STRUCT)hService)->AccessGranted,
  287. desiredAccess))
  288. {
  289. return(ERROR_ACCESS_DENIED);
  290. }
  291. serviceRecord = ((LPSC_HANDLE_STRUCT)hService)->Type.ScServiceObject.ServiceRecord;
  292. //
  293. // If this control is for a driver, call ScControlDriver and return.
  294. //
  295. if (serviceRecord->ServiceStatus.dwServiceType & SERVICE_DRIVER)
  296. {
  297. return(ScControlDriver(OpCode, serviceRecord, lpServiceStatus));
  298. }
  299. //
  300. // Obtain a shared lock on the database - read the data we need,
  301. // Then free the lock.
  302. //
  303. {
  304. CServiceRecordSharedLock RLock;
  305. //
  306. // Once we get to this point, copy in the last known
  307. // status to return to the caller (Bug #188874)
  308. //
  309. RtlCopyMemory(lpServiceStatus,
  310. &(serviceRecord->ServiceStatus),
  311. sizeof(SERVICE_STATUS));
  312. currentState = serviceRecord->ServiceStatus.dwCurrentState;
  313. controlsAccepted = serviceRecord->ServiceStatus.dwControlsAccepted;
  314. serviceName = (LPWSTR) LocalAlloc(LMEM_FIXED,
  315. 2 * (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR));
  316. if (serviceName == NULL)
  317. {
  318. status = ERROR_NOT_ENOUGH_MEMORY;
  319. }
  320. else
  321. {
  322. displayName = serviceName + MAX_SERVICE_NAME_LENGTH + 1;
  323. wcscpy(serviceName, serviceRecord->ServiceName);
  324. wcscpy(displayName, serviceRecord->DisplayName);
  325. //
  326. // If we can obtain a pipe handle, do so. Otherwise, return an error.
  327. // (but first release the lock). Refcount the pipe handle to make sure
  328. // it doesn't go away while we're sending this control as ScSendControl
  329. // doesn't hold locks around the transact.
  330. //
  331. if ((currentState != SERVICE_STOPPED) &&
  332. (serviceRecord->ImageRecord != NULL))
  333. {
  334. if (!DuplicateHandle(GetCurrentProcess(),
  335. serviceRecord->ImageRecord->PipeHandle,
  336. GetCurrentProcess(),
  337. &pipeHandle,
  338. 0,
  339. FALSE,
  340. DUPLICATE_SAME_ACCESS))
  341. {
  342. pipeHandle = NULL;
  343. status = GetLastError();
  344. }
  345. }
  346. else
  347. {
  348. status = ERROR_SERVICE_NOT_ACTIVE;
  349. }
  350. }
  351. }
  352. if (status != NO_ERROR)
  353. {
  354. goto CleanExit;
  355. }
  356. //
  357. // The control is not sent to the service if the service is in
  358. // either the STOP_PENDING or START_PENDING state EXCEPT - we
  359. // allow STOP controls to a service that is START_PENDING.
  360. //
  361. // If we decide not to allow the control to be sent, we either
  362. // return current info (INTERROGATE) or an error (any other opcode).
  363. //
  364. if (currentState == SERVICE_STOP_PENDING)
  365. {
  366. status = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
  367. goto CleanExit;
  368. }
  369. else if (currentState == SERVICE_START_PENDING)
  370. {
  371. switch (OpCode)
  372. {
  373. case SERVICE_CONTROL_INTERROGATE:
  374. //
  375. // Just return the last known status. This behavior is unpublished.
  376. //
  377. status = NO_ERROR;
  378. goto CleanExit;
  379. case SERVICE_CONTROL_STOP:
  380. break;
  381. default:
  382. status = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
  383. goto CleanExit;
  384. }
  385. }
  386. //
  387. // Check if the service accepts the control.
  388. //
  389. if ( (controlsAccepted & controlsAcceptedMask) != controlsAcceptedMask )
  390. {
  391. status = ERROR_INVALID_SERVICE_CONTROL;
  392. goto CleanExit;
  393. }
  394. //
  395. // Check for dependent services still running
  396. //
  397. BOOL fLastService = FALSE;
  398. if (OpCode == SERVICE_CONTROL_STOP)
  399. {
  400. CServiceRecordSharedLock RLock;
  401. if (! ScDependentsStopped(serviceRecord))
  402. {
  403. status = ERROR_DEPENDENT_SERVICES_RUNNING;
  404. goto CleanExit;
  405. }
  406. if (serviceRecord->ImageRecord != NULL &&
  407. serviceRecord->ImageRecord->ServiceCount == 1)
  408. {
  409. fLastService = TRUE;
  410. }
  411. }
  412. //
  413. // Send the control request to the target service
  414. //
  415. status = ScSendControl(serviceName, // ServiceName
  416. displayName, // DisplayName
  417. pipeHandle, // pipeHandle
  418. OpCode, // Opcode
  419. NULL, // CmdArgs (vector ptr)
  420. 0L, // NumArgs
  421. NULL); // Ignore handler return value
  422. if (status == NO_ERROR)
  423. {
  424. //
  425. // If no errors occured, copy the latest status into the return
  426. // buffer. The shared lock is required for this.
  427. //
  428. CServiceRecordSharedLock RLock;
  429. RtlCopyMemory(lpServiceStatus,
  430. &(serviceRecord->ServiceStatus),
  431. sizeof(SERVICE_STATUS));
  432. }
  433. else
  434. {
  435. SC_LOG2(ERROR,"RControlService:SendControl to %ws service failed %ld\n",
  436. serviceRecord->ServiceName, status);
  437. if (OpCode == SERVICE_CONTROL_STOP)
  438. {
  439. //
  440. // If sending the control failed, and the control was a request
  441. // to stop, and if this service is the only running service in
  442. // the process, we can force the process to stop. ScRemoveService
  443. // will handle this if the ServiceCount is one.
  444. //
  445. if (fLastService)
  446. {
  447. SC_LOG0(TRACE,"RControlService:Forcing Service Shutdown\n");
  448. ScRemoveService(serviceRecord);
  449. }
  450. }
  451. }
  452. CleanExit:
  453. LocalFree(serviceName);
  454. if (pipeHandle != NULL)
  455. {
  456. CloseHandle(pipeHandle);
  457. }
  458. return status;
  459. }
  460. /****************************************************************************/
  461. DWORD
  462. ScCreateControlInstance (
  463. OUT LPHANDLE PipeHandlePtr,
  464. IN DWORD dwCurrentService,
  465. IN PSID pAccountSid
  466. )
  467. /*++
  468. Routine Description:
  469. This function creates an instance of the control pipe
  470. Arguments:
  471. PipeHandlePtr - This is a pointer to a location where the pipe handle
  472. is to be placed upon return.
  473. dwCurrentService - This is used to create a uniquely-named pipe
  474. pAccountSid - The SID of the account that is allowed to access this pipe
  475. Return Value:
  476. NO_ERROR - The operation was successful.
  477. other - Any error returned by CreateNamedPipe could be returned.
  478. --*/
  479. {
  480. DWORD status;
  481. NTSTATUS ntstatus;
  482. SECURITY_ATTRIBUTES SecurityAttr;
  483. PSECURITY_DESCRIPTOR SecurityDescriptor;
  484. WCHAR wszPipeName[sizeof(CONTROL_PIPE_NAME) / sizeof(WCHAR) + PID_LEN] = CONTROL_PIPE_NAME;
  485. SC_ACE_DATA AceData[1] = {
  486. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  487. GENERIC_ALL, &pAccountSid}
  488. };
  489. //
  490. // Generate the pipe name
  491. //
  492. _itow(dwCurrentService, wszPipeName + sizeof(CONTROL_PIPE_NAME) / sizeof(WCHAR) - 1, 10);
  493. //
  494. // Create a security descriptor for the control named pipe so
  495. // that we can grant access to it solely to the service's account
  496. //
  497. ntstatus = ScCreateAndSetSD(
  498. AceData,
  499. 1,
  500. LocalSystemSid,
  501. LocalSystemSid,
  502. &SecurityDescriptor
  503. );
  504. if (! NT_SUCCESS(ntstatus)) {
  505. SC_LOG1(ERROR, "ScCreateAndSetSD failed " FORMAT_NTSTATUS
  506. "\n", ntstatus);
  507. return (RtlNtStatusToDosError(ntstatus));
  508. }
  509. SecurityAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  510. SecurityAttr.lpSecurityDescriptor = SecurityDescriptor;
  511. SecurityAttr.bInheritHandle = FALSE;
  512. //
  513. // Create the service controller's end of the named pipe that will
  514. // be used for communicating control requests to the service process.
  515. // Use FILE_FLAG_FIRST_PIPE_INSTANCE to make sure that we're the
  516. // creator of the named pipe (vs. a malicious process that creates
  517. // the pipe first and thereby gains access to the client service
  518. // that connects to it).
  519. //
  520. *PipeHandlePtr = CreateNamedPipe (
  521. wszPipeName,
  522. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
  523. PIPE_WAIT | PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE,
  524. 1, // one instance per process
  525. 8000,
  526. sizeof(PIPE_RESPONSE_MSG),
  527. CONTROL_TIMEOUT, // Default Timeout
  528. &SecurityAttr); // Security Descriptor
  529. status = NO_ERROR;
  530. if (*PipeHandlePtr == INVALID_HANDLE_VALUE) {
  531. status = GetLastError();
  532. SC_LOG1(ERROR,
  533. "CreateControlInstance: CreateNamedPipe failed, %ld\n",status);
  534. }
  535. (void) RtlDeleteSecurityObject(&SecurityDescriptor);
  536. return(status);
  537. }
  538. /****************************************************************************/
  539. DWORD
  540. ScWaitForConnect (
  541. IN HANDLE PipeHandle,
  542. IN HANDLE hProcess OPTIONAL,
  543. IN LPWSTR lpDisplayName,
  544. OUT LPDWORD ProcessIdPtr
  545. )
  546. /*++
  547. Routine Description:
  548. This function waits until a connection is made to the pipe handle.
  549. It then waits for the first status message to be sent from the
  550. service process.
  551. The first message from the service contains the processId. This
  552. helps to verify that we are talking to the correct process.
  553. Arguments:
  554. PipeHandle - This is the handle to the pipe instance that is waiting
  555. for a connect.
  556. hProcess - The handle to the service process. We wait on this handle
  557. and the pipe handle in case the process exits before the
  558. pipe transaction times out.
  559. lpDisplayName - The name of the service for which we're waiting.
  560. ProcessIdPtr - This is a pointer to the location where the processId is
  561. to be stored.
  562. Return Value:
  563. NO_ERROR - The pipe is in the connected state.
  564. any error that ReadFile can produce may be returned.
  565. Note:
  566. The ConnectNamedPipe called is done asynchronously and we wait
  567. on its completion using the pipe handle. This can only work
  568. correctly when it is guaranteed that no other IO is issued
  569. while we are waiting on the pipe handle (except for the service
  570. itself to connect to the pipe with call to CreateFile).
  571. --*/
  572. {
  573. PIPE_RESPONSE_MSG serviceResponseBuffer;
  574. DWORD numBytesRead;
  575. BOOL status;
  576. DWORD apiStatus;
  577. OVERLAPPED overlapped={0,0,0,0,0};// overlapped structure to implement
  578. // timeout on TransactNamedPipe
  579. CONST HANDLE phHandles[] = { PipeHandle, hProcess };
  580. DWORD dwCount = (hProcess == NULL ? 1 : 2);
  581. #if DBG
  582. DWORD dwStartTick;
  583. DWORD dwTotalTime;
  584. #endif // DBG
  585. SC_LOG(TRACE,"ServiceController waiting for pipe connect\n",0);
  586. overlapped.hEvent = (HANDLE) NULL; // Wait on pipe handle
  587. //
  588. // Wait for the service to connect.
  589. //
  590. status = ConnectNamedPipe(PipeHandle, &overlapped);
  591. if (status == FALSE) {
  592. apiStatus = GetLastError();
  593. if (apiStatus == ERROR_IO_PENDING) {
  594. #if DBG
  595. dwStartTick = GetTickCount();
  596. #endif // DBG
  597. //
  598. // Connection is pending
  599. //
  600. apiStatus = WaitForMultipleObjects(dwCount,
  601. phHandles,
  602. FALSE, // Wait for any
  603. g_dwScPipeTransactTimeout);
  604. #if DBG
  605. dwTotalTime = GetTickCount() - dwStartTick;
  606. if (dwTotalTime > SC_DEFAULT_PIPE_TRANSACT_TIMEOUT) {
  607. SC_LOG1(ERROR,
  608. "ScWaitForConnect: Wait on ConnectNamedPipe took %u milliseconds\n",
  609. dwTotalTime);
  610. }
  611. #endif // DBG
  612. if (apiStatus == WAIT_OBJECT_0) {
  613. //
  614. // Wait completed successfully -- the object that
  615. // signalled was the pipe handle
  616. //
  617. status = GetOverlappedResult(
  618. PipeHandle,
  619. &overlapped,
  620. &numBytesRead,
  621. TRUE
  622. );
  623. if (status == FALSE) {
  624. apiStatus = GetLastError();
  625. SC_LOG(ERROR,
  626. "ScWaitForConnect: GetOverlappedResult failed, rc=%lu\n",
  627. apiStatus);
  628. return apiStatus;
  629. }
  630. }
  631. else {
  632. //
  633. // Either the connection timed out or the service process
  634. // exited before calling StartServiceCtrlDispatcher
  635. //
  636. SC_LOG2(ERROR,
  637. "ScWaitForConnect: Wait for connection for %u secs timed out --"
  638. "service process DID %s exit\n",
  639. g_dwScPipeTransactTimeout / 1000,
  640. (apiStatus == WAIT_TIMEOUT ? "NOT" : ""));
  641. //
  642. // The service didn't respond. Cancel the named pipe operation.
  643. //
  644. status = CancelIo(PipeHandle);
  645. if (status == FALSE) {
  646. SC_LOG(ERROR, "ScWaitForConnect: CancelIo failed, %lu\n", GetLastError());
  647. }
  648. ScLogEvent(
  649. NEVENT_CONNECTION_TIMEOUT,
  650. g_dwScPipeTransactTimeout,
  651. lpDisplayName
  652. );
  653. return ERROR_SERVICE_REQUEST_TIMEOUT;
  654. }
  655. }
  656. else if (apiStatus != ERROR_PIPE_CONNECTED) {
  657. SC_LOG(ERROR,"ScWaitForConnect: ConnectNamedPipe failed, rc=%lu\n",
  658. apiStatus);
  659. return apiStatus;
  660. }
  661. //
  662. // If we received the ERROR_PIPE_CONNECTED status, then things
  663. // are still ok.
  664. //
  665. }
  666. SC_LOG(TRACE,"WaitForConnect:ConnectNamedPipe Success\n",0);
  667. //
  668. // Wait for initial status message
  669. //
  670. overlapped.hEvent = (HANDLE) NULL; // Wait on pipe handle
  671. status = ReadFile (PipeHandle,
  672. (LPVOID)&serviceResponseBuffer,
  673. sizeof(serviceResponseBuffer),
  674. &numBytesRead,
  675. &overlapped);
  676. if (status == FALSE) {
  677. apiStatus = GetLastError();
  678. if (apiStatus == ERROR_IO_PENDING) {
  679. #if DBG
  680. dwStartTick = GetTickCount();
  681. #endif // DBG
  682. //
  683. // Connection is pending
  684. //
  685. apiStatus = WaitForSingleObject(PipeHandle, g_dwScPipeTransactTimeout);
  686. #if DBG
  687. dwTotalTime = GetTickCount() - dwStartTick;
  688. if (dwTotalTime > SC_DEFAULT_PIPE_TRANSACT_TIMEOUT) {
  689. SC_LOG1(ERROR,
  690. "ScWaitForConnect: Wait on ReadFile took %u milliseconds\n",
  691. dwTotalTime);
  692. }
  693. #endif // DBG
  694. if (apiStatus == WAIT_TIMEOUT) {
  695. SC_LOG(ERROR,
  696. "ScWaitForConnect: Wait for ReadFile for %u secs timed out\n",
  697. g_dwScPipeTransactTimeout / 1000 );
  698. //
  699. // Cancel the named pipe operation.
  700. //
  701. status = CancelIo(PipeHandle);
  702. if (status == FALSE) {
  703. SC_LOG(ERROR, "ScWaitForConnect: CancelIo failed, %lu\n", GetLastError());
  704. }
  705. ScLogEvent(
  706. NEVENT_READFILE_TIMEOUT,
  707. g_dwScPipeTransactTimeout
  708. );
  709. return ERROR_SERVICE_REQUEST_TIMEOUT;
  710. } else if (apiStatus == 0) {
  711. //
  712. // Wait completed successfully
  713. //
  714. status = GetOverlappedResult(PipeHandle,
  715. &overlapped,
  716. &numBytesRead,
  717. TRUE);
  718. if (status == FALSE) {
  719. apiStatus = GetLastError();
  720. SC_LOG(ERROR,
  721. "ScWaitForConnect: GetOverlappedResult for ReadFile failed, rc=%lu\n",
  722. apiStatus);
  723. return apiStatus;
  724. }
  725. }
  726. }
  727. else {
  728. SC_LOG(ERROR,"ScWaitForConnect: ReadFile failed, rc=%lu\n",
  729. apiStatus);
  730. return apiStatus;
  731. }
  732. }
  733. SC_LOG0(TRACE,"WaitForConnect:ReadFile success\n");
  734. SC_LOG(
  735. TRACE,
  736. "WaitForConnect:ReadFile buffer size = %ld\n",
  737. sizeof(serviceResponseBuffer));
  738. SC_LOG(
  739. TRACE,
  740. "WaitForConnect:ReadFile numBytesRead = %ld\n",
  741. numBytesRead);
  742. *ProcessIdPtr = serviceResponseBuffer.dwDispatcherStatus;
  743. return(NO_ERROR);
  744. }
  745. /****************************************************************************/
  746. DWORD
  747. ScValidatePnPService(
  748. IN LPWSTR lpServiceName,
  749. OUT SERVICE_STATUS_HANDLE *lphServiceStatus
  750. )
  751. {
  752. DWORD dwError;
  753. LPSERVICE_RECORD lpServiceRecord;
  754. //
  755. // Make sure PnP is supplying a valid OUT parameter
  756. //
  757. SC_ASSERT(lphServiceStatus != NULL);
  758. //
  759. // Validate the format of the service name.
  760. //
  761. if (! ScIsValidServiceName(lpServiceName))
  762. {
  763. return ERROR_INVALID_NAME;
  764. }
  765. //
  766. // Find the service record in the database.
  767. //
  768. CServiceListSharedLock LLock;
  769. dwError = ScGetNamedServiceRecord(lpServiceName,
  770. &lpServiceRecord);
  771. if (dwError != NO_ERROR)
  772. {
  773. return(dwError);
  774. }
  775. CServiceRecordSharedLock RLock;
  776. //
  777. // Make sure the service specified is the service
  778. // that requested device notification
  779. //
  780. dwError = ScStatusAccessCheck(lpServiceRecord);
  781. if (dwError == NO_ERROR)
  782. {
  783. *lphServiceStatus = (SERVICE_STATUS_HANDLE)lpServiceRecord;
  784. }
  785. return dwError;
  786. }
  787. DWORD
  788. ScSendPnPMessage(
  789. IN SERVICE_STATUS_HANDLE hServiceStatus,
  790. IN DWORD OpCode,
  791. IN DWORD dwEventType,
  792. IN LPARAM EventData,
  793. OUT LPDWORD lpdwHandlerRetVal
  794. )
  795. /*++
  796. Routine Description:
  797. This function is called by PnP when it needs to send a control to a
  798. service that has requested notification. It simply packs the args and
  799. calls ScSendControl.
  800. Arguments:
  801. OpCode - This is the opcode that is to be passed to the service.
  802. dwEventType - The PnP event that has occurred
  803. EventData - Pointer to other information the service may want
  804. Return Value:
  805. ERROR_SERVICE_NOT_ACTIVE - The named service has no image record
  806. In addition, any value passed back from ScGetNamedImageRecord or ScSendControl
  807. --*/
  808. {
  809. LPSERVICE_RECORD lpServiceRecord;
  810. CONTROL_ARGS ControlArgs;
  811. LPWSTR lpServiceName;
  812. LPWSTR lpDisplayName;
  813. HANDLE hPipe;
  814. DWORD dwError = NO_ERROR;
  815. //
  816. // Make sure this handle is valid (in case the service in question
  817. // was deleted and was signed up for device notifications)
  818. //
  819. // BUGBUG -- We should call a PnP callback and have it free up the
  820. // node for the service in question if it's deleted
  821. //
  822. SC_ASSERT(((LPSERVICE_RECORD) hServiceStatus)->Signature == SERVICE_SIGNATURE);
  823. //
  824. // Make sure PnP is giving us a valid OUT parameter
  825. //
  826. SC_ASSERT(lpdwHandlerRetVal != NULL);
  827. lpServiceRecord = (LPSERVICE_RECORD) hServiceStatus;
  828. {
  829. //
  830. // Get the information we need then release the lock
  831. //
  832. CServiceRecordSharedLock RLock;
  833. if (lpServiceRecord->ImageRecord == NULL)
  834. {
  835. return ERROR_SERVICE_NOT_ACTIVE;
  836. }
  837. lpServiceName = (LPWSTR) LocalAlloc(LMEM_FIXED,
  838. 2 * (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR));
  839. if (lpServiceName == NULL)
  840. {
  841. return ERROR_NOT_ENOUGH_MEMORY;
  842. }
  843. lpDisplayName = lpServiceName + MAX_SERVICE_NAME_LENGTH + 1;
  844. wcscpy(lpServiceName, lpServiceRecord->ServiceName);
  845. wcscpy(lpDisplayName, lpServiceRecord->DisplayName);
  846. //
  847. // Refcount the pipe handle to prevent it from going away midway through
  848. // the call as ScSendControl doesn't hold locks around the pipe transact.
  849. //
  850. if (!DuplicateHandle(GetCurrentProcess(),
  851. lpServiceRecord->ImageRecord->PipeHandle,
  852. GetCurrentProcess(),
  853. &hPipe,
  854. 0,
  855. FALSE,
  856. DUPLICATE_SAME_ACCESS))
  857. {
  858. dwError = GetLastError();
  859. LocalFree(lpServiceName);
  860. return dwError;
  861. }
  862. }
  863. //
  864. // If it's a PnP device event, pass along the arguments for the named pipe
  865. //
  866. switch (OpCode)
  867. {
  868. case SERVICE_CONTROL_DEVICEEVENT:
  869. //
  870. // Make sure that either both the size and buffer are
  871. // 0 and NULL or that they're non-zero and non-NULL
  872. //
  873. SC_ASSERT(((PDEV_BROADCAST_HDR)EventData)->dbch_size && EventData ||
  874. !((PDEV_BROADCAST_HDR)EventData)->dbch_size && !EventData);
  875. ControlArgs.PnPArgs.dwEventType = dwEventType;
  876. ControlArgs.PnPArgs.dwEventDataSize = ((PDEV_BROADCAST_HDR)EventData)->dbch_size;
  877. ControlArgs.PnPArgs.EventData = (VOID *)EventData;
  878. break;
  879. case SERVICE_CONTROL_POWEREVENT:
  880. case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
  881. //
  882. // Hardware Profile Change and Power messages have no LPARAM.
  883. // They just tell a service that something noteworthy has happened.
  884. //
  885. SC_ASSERT(EventData == NULL);
  886. ControlArgs.PnPArgs.dwEventType = dwEventType;
  887. ControlArgs.PnPArgs.dwEventDataSize = 0;
  888. ControlArgs.PnPArgs.EventData = NULL;
  889. break;
  890. default:
  891. SC_ASSERT(FALSE);
  892. break;
  893. }
  894. dwError = ScSendControl(lpServiceName,
  895. lpDisplayName,
  896. hPipe,
  897. OpCode,
  898. &ControlArgs,
  899. 3, // 3 PnP arguments
  900. lpdwHandlerRetVal);
  901. LocalFree(lpServiceName);
  902. CloseHandle(hPipe);
  903. return dwError;
  904. }
  905. DWORD
  906. RI_ScSendTSMessage (
  907. IN SC_RPC_HANDLE hSCManager,
  908. IN DWORD OpCode,
  909. IN DWORD dwEvent,
  910. IN DWORD cbData,
  911. IN LPBYTE lpData
  912. )
  913. {
  914. LPSERVICE_RECORD lpServiceRecord;
  915. CONTROL_ARGS ControlArgs;
  916. DWORD dwAcceptedMask;
  917. DWORD dwError = NO_ERROR;
  918. DWORD dwNumServices = 0;
  919. DWORD i;
  920. LPTS_CONTROL_INFO lpControlInfo;
  921. lpServiceRecord = NULL;
  922. ControlArgs.PnPArgs.dwEventType = dwEvent;
  923. ControlArgs.PnPArgs.dwEventDataSize = cbData;
  924. ControlArgs.PnPArgs.EventData = lpData;
  925. if (OpCode != SERVICE_CONTROL_SESSIONCHANGE)
  926. {
  927. ASSERT(OpCode == SERVICE_CONTROL_SESSIONCHANGE);
  928. return ERROR_INVALID_PARAMETER;
  929. }
  930. dwAcceptedMask = SERVICE_ACCEPT_SESSIONCHANGE;
  931. //
  932. // Make sure that the caller is LocalSystem
  933. //
  934. dwError = ScStatusAccessCheck(NULL);
  935. if (dwError != NO_ERROR)
  936. {
  937. SC_LOG1(ERROR,
  938. "RI_ScSendTSMessage: ScStatusAccessCheck failed %d\n",
  939. dwError);
  940. return dwError;
  941. }
  942. {
  943. CServiceListSharedLock LLock;
  944. CServiceRecordExclusiveLock RLock;
  945. //
  946. // Go through the list and copy out the pointer to the service name and
  947. // the pipe handle for each service that wants to receive this control.
  948. // We do this so we can call ScSendControl for each service afterwards
  949. // without holding the locks required to traverse the list.
  950. //
  951. FOR_SERVICES_THAT(lpServiceRecord,
  952. (lpServiceRecord->ServiceStatus.dwServiceType & SERVICE_WIN32) &&
  953. (lpServiceRecord->ServiceStatus.dwCurrentState != SERVICE_STOPPED) &&
  954. (lpServiceRecord->ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING) &&
  955. (lpServiceRecord->ServiceStatus.dwControlsAccepted & dwAcceptedMask) &&
  956. (lpServiceRecord->ImageRecord != NULL)
  957. )
  958. {
  959. dwNumServices++;
  960. }
  961. if (dwNumServices == 0)
  962. {
  963. //
  964. // No services accept the control
  965. //
  966. return NO_ERROR;
  967. }
  968. lpControlInfo = (LPTS_CONTROL_INFO) LocalAlloc(LMEM_ZEROINIT,
  969. dwNumServices * sizeof(TS_CONTROL_INFO));
  970. if (lpControlInfo == NULL)
  971. {
  972. return ERROR_NOT_ENOUGH_MEMORY;
  973. }
  974. dwNumServices = 0;
  975. FOR_SERVICES_THAT(lpServiceRecord,
  976. (lpServiceRecord->ServiceStatus.dwServiceType & SERVICE_WIN32) &&
  977. (lpServiceRecord->ServiceStatus.dwCurrentState != SERVICE_STOPPED) &&
  978. (lpServiceRecord->ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING) &&
  979. (lpServiceRecord->ServiceStatus.dwControlsAccepted & dwAcceptedMask) &&
  980. (lpServiceRecord->ImageRecord != NULL)
  981. )
  982. {
  983. //
  984. // Copy out the information we need
  985. //
  986. wcscpy(lpControlInfo[dwNumServices].lpServiceName, lpServiceRecord->ServiceName);
  987. wcscpy(lpControlInfo[dwNumServices].lpDisplayName, lpServiceRecord->DisplayName);
  988. if (!DuplicateHandle(GetCurrentProcess(),
  989. lpServiceRecord->ImageRecord->PipeHandle,
  990. GetCurrentProcess(),
  991. &lpControlInfo[dwNumServices].hPipe,
  992. 0,
  993. FALSE,
  994. DUPLICATE_SAME_ACCESS))
  995. {
  996. dwError = GetLastError();
  997. goto CleanExit;
  998. }
  999. dwNumServices++;
  1000. }
  1001. }
  1002. for (i = 0; i < dwNumServices; i++)
  1003. {
  1004. //
  1005. // Send the control
  1006. //
  1007. dwError = ScSendControl(lpControlInfo[i].lpServiceName,
  1008. lpControlInfo[i].lpDisplayName,
  1009. lpControlInfo[i].hPipe,
  1010. OpCode,
  1011. &ControlArgs,
  1012. 3,
  1013. NULL);
  1014. //
  1015. // Ignore any errors sending the control
  1016. //
  1017. if (dwError != NO_ERROR)
  1018. {
  1019. SC_LOG2(ERROR,
  1020. "RI_ScSendTSMessage: Error %d sending control to %ws service\n",
  1021. dwError,
  1022. lpControlInfo[i].lpServiceName);
  1023. }
  1024. CloseHandle(lpControlInfo[i].hPipe);
  1025. }
  1026. LocalFree(lpControlInfo);
  1027. return NO_ERROR;
  1028. CleanExit:
  1029. for (i = 0; i < dwNumServices; i++)
  1030. {
  1031. //
  1032. // The only time lpControlInfo[i].hPipe may be NULL is if the DuplicateHandle
  1033. // call for it failed above. In that case, however, dwNumServices wasn't
  1034. // incremented and we jumped straight here, so by looping until dwNumServices,
  1035. // we're guaranteed to be closing valid pipe handles.
  1036. //
  1037. CloseHandle(lpControlInfo[i].hPipe);
  1038. }
  1039. LocalFree(lpControlInfo);
  1040. return dwError;
  1041. }
  1042. /****************************************************************************/
  1043. DWORD
  1044. ScSendControl(
  1045. IN LPWSTR ServiceName,
  1046. IN LPWSTR DisplayName,
  1047. IN HANDLE PipeHandle,
  1048. IN DWORD OpCode,
  1049. IN LPCONTROL_ARGS lpControlArgs OPTIONAL,
  1050. IN DWORD NumArgs,
  1051. OUT LPDWORD lpdwHandlerRetVal OPTIONAL
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. This function sends a control request to a service via a
  1056. TransactNamedPipe call. A buffer is allocated for the transaction,
  1057. and then freed when done.
  1058. LOCKS:
  1059. Normally locks are not held when this function is called. This is
  1060. because we need to allow status messages to come in prior to the
  1061. transact completing. The exception is when we send the message
  1062. to the control dispatcher to shutdown. No status message is sent
  1063. in response to that.
  1064. There is a ScTransactNPCriticalSection that is held during the actual
  1065. Transact.
  1066. Arguments:
  1067. ServiceName - This is a pointer to a NUL terminated service name string.
  1068. PipeHandle - This is the pipe handle to which the request is directed.
  1069. OpCode - This is the opcode that is to be passed to the service.
  1070. lpControlArgs - This is an optional pointer to a CONTROL_ARGS union,
  1071. which can contain either an array of pointers to NUL-terminated
  1072. strings (for the SERVICE_CONTROL_START case) or a structure that
  1073. holds Plug-and-Play arguments (for the SERVICE_CONTROL_DEVICEEVENT,
  1074. SERVICE_CONTROL_POWEREVENT, SERVICE_CONTROL_HARDWAREPROFILECHANGE,
  1075. and SERVICE_CONTROL_SESSIONCHANGE cases).
  1076. NumArgs - This indicates how many arguments are in the structure
  1077. lpControlArgs contains. For SERVICE_CONTROL_START, it's the number
  1078. of strings in the argument array. For Plug-and-Play events, it's
  1079. the number of arguments in a Plug-and-Play message (currently 3)
  1080. lpdwHandlerRetVal - The return value from the Service's control handler
  1081. Return Value:
  1082. NO_ERROR - The operation was successful.
  1083. ERROR_GEN_FAILURE - An incorrect number of bytes was received
  1084. in the response message.
  1085. ERROR_ACCESS_DENIED - This is a status response from the service
  1086. security check by the Control Dispatcher on the other end of the
  1087. pipe.
  1088. ERROR_NOT_ENOUGH_MEMORY - Unable to allocate memory for the transaction
  1089. buffer. (Local Alloc failed).
  1090. other - Any error from TransactNamedPipe could be returned - Or any
  1091. error from the Control Dispatcher on the other end of the pipe.
  1092. --*/
  1093. {
  1094. DWORD returnStatus = NO_ERROR;
  1095. LPCTRL_MSG_HEADER lpcmhBuffer; // Message buffer
  1096. DWORD serviceNameSize;
  1097. DWORD sendBufferSize;
  1098. BOOL status;
  1099. PIPE_RESPONSE_MSG serviceResponseBuffer;
  1100. DWORD bytesRead;
  1101. DWORD i;
  1102. static OVERLAPPED overlapped={0,0,0,0,0}; // overlapped structure to implement
  1103. // timeout on TransactNamedPipe
  1104. // static because on shutdown, we'll
  1105. // be firing off a bunch of async
  1106. // writes, which write to the overlapped
  1107. // structure upon completion, and we
  1108. // don't want them trashing the stack
  1109. if (ARGUMENT_PRESENT(lpdwHandlerRetVal))
  1110. {
  1111. //
  1112. // Initialize the OUT pointer
  1113. //
  1114. *lpdwHandlerRetVal = NO_ERROR;
  1115. }
  1116. serviceNameSize = (DWORD) WCSSIZE(ServiceName);
  1117. sendBufferSize = serviceNameSize + sizeof(CTRL_MSG_HEADER);
  1118. //
  1119. // Add an extra PVOID size to help settle alignment problems that
  1120. // may occur when the array of pointers follows the service name string.
  1121. //
  1122. sendBufferSize += sizeof(PVOID);
  1123. //
  1124. // There are control arguments, so add their size to the buffer size
  1125. //
  1126. if (lpControlArgs != NULL) {
  1127. if (OpCode == SERVICE_CONTROL_START_SHARE ||
  1128. OpCode == SERVICE_CONTROL_START_OWN) {
  1129. //
  1130. // Service is starting
  1131. //
  1132. for (i = 0; i < NumArgs; i++) {
  1133. sendBufferSize += (DWORD) WCSSIZE(lpControlArgs->CmdArgs[i]) +
  1134. sizeof(LPWSTR);
  1135. }
  1136. }
  1137. else {
  1138. SC_ASSERT(OpCode == SERVICE_CONTROL_DEVICEEVENT ||
  1139. OpCode == SERVICE_CONTROL_HARDWAREPROFILECHANGE ||
  1140. OpCode == SERVICE_CONTROL_POWEREVENT ||
  1141. OpCode == SERVICE_CONTROL_SESSIONCHANGE);
  1142. //
  1143. // PnP event
  1144. //
  1145. sendBufferSize += sizeof(lpControlArgs->PnPArgs.dwEventType);
  1146. sendBufferSize += sizeof(lpControlArgs->PnPArgs.dwEventDataSize);
  1147. sendBufferSize += lpControlArgs->PnPArgs.dwEventDataSize;
  1148. }
  1149. }
  1150. //
  1151. // Allocate the buffer and set a pointer to it that knows the structure
  1152. // of the header.
  1153. //
  1154. lpcmhBuffer = (LPCTRL_MSG_HEADER)LocalAlloc(LMEM_ZEROINIT, sendBufferSize);
  1155. if (lpcmhBuffer == NULL) {
  1156. SC_LOG(TRACE,"SendControl:LocalAlloc failed, rc=%d/n", GetLastError());
  1157. return (ERROR_NOT_ENOUGH_MEMORY);
  1158. }
  1159. /////////////////////////////////////////////////////////////////////
  1160. // Marshall the data into the buffer.
  1161. //
  1162. //
  1163. // The Control Message looks like this for service start:
  1164. // CTRL_MSG_HEADER Header
  1165. // WCHAR ServiceName[?]
  1166. // LPWSTR Argv0 offset
  1167. // LPWSTR Argv1 offset
  1168. // LPWSTR Argv2 offset
  1169. // LPWSTR ...
  1170. // WCHAR Argv0[?]
  1171. // WCHAR Argv1[?]
  1172. // WCHAR Argv2[?]
  1173. // WCHAR ...
  1174. //
  1175. // and like this for PNP events:
  1176. // CTRL_MSG_HEADER Header
  1177. // WCHAR ServiceName[?]
  1178. // DWORD wParam
  1179. // BYTE lParam[?]
  1180. //
  1181. lpcmhBuffer->OpCode = OpCode;
  1182. lpcmhBuffer->Count = sendBufferSize;
  1183. //
  1184. // Copy the service name to buffer and store the offset.
  1185. //
  1186. lpcmhBuffer->ServiceNameOffset = sizeof(CTRL_MSG_HEADER);
  1187. wcscpy((LPWSTR)(lpcmhBuffer + 1), ServiceName);
  1188. //
  1189. // Pack message-specific arguments as necessary
  1190. //
  1191. switch (OpCode) {
  1192. case SERVICE_CONTROL_START_SHARE:
  1193. case SERVICE_CONTROL_START_OWN:
  1194. if (NumArgs > 0) {
  1195. //
  1196. // Service start -- Determine the offset from the top of the argv
  1197. // array to the first argv string. Also determine the pointer value
  1198. // for that location.
  1199. //
  1200. DWORD dwOffset = NumArgs * sizeof(LPWSTR);
  1201. LPWSTR *ppwszArgs;
  1202. //
  1203. // Calculate the beginning of the string area and the beginning
  1204. // of the arg vector area. Align the vector pointer on a PVOID
  1205. // boundary.
  1206. //
  1207. ppwszArgs = (LPWSTR *)((LPBYTE)(lpcmhBuffer + 1) + serviceNameSize);
  1208. ppwszArgs = (LPWSTR *)ROUND_UP_POINTER(ppwszArgs, sizeof(PVOID));
  1209. lpcmhBuffer->ArgvOffset = (DWORD)((LPBYTE)ppwszArgs - (LPBYTE)lpcmhBuffer);
  1210. lpcmhBuffer->NumCmdArgs = NumArgs;
  1211. //
  1212. // Copy the command arg strings to the buffer and update the argv
  1213. // pointers with offsets. Remember - we already have one argument
  1214. // in there for the service registry path.
  1215. //
  1216. for (i = 0; i < NumArgs; i++) {
  1217. wcscpy((LPWSTR) ((LPBYTE)ppwszArgs + dwOffset),
  1218. lpControlArgs->CmdArgs[i]);
  1219. ppwszArgs[i] = (LPWSTR)(DWORD_PTR) dwOffset;
  1220. dwOffset += (DWORD) WCSSIZE(lpControlArgs->CmdArgs[i]);
  1221. }
  1222. }
  1223. break;
  1224. case SERVICE_CONTROL_DEVICEEVENT:
  1225. case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
  1226. case SERVICE_CONTROL_POWEREVENT:
  1227. case SERVICE_CONTROL_SESSIONCHANGE:
  1228. {
  1229. LPDWORD lpdwArgLocation;
  1230. //
  1231. // Calculate the location for the PnP/power arguments.
  1232. // Align the pointer on a PVOID boundary.
  1233. //
  1234. lpdwArgLocation = (LPDWORD)((LPBYTE)(lpcmhBuffer + 1) + serviceNameSize);
  1235. lpdwArgLocation = (LPDWORD)ROUND_UP_POINTER(lpdwArgLocation, sizeof(PVOID));
  1236. lpcmhBuffer->ArgvOffset = (DWORD)((LPBYTE)lpdwArgLocation - (LPBYTE)lpcmhBuffer);
  1237. //
  1238. // Copy the wParam into the buffer
  1239. //
  1240. *lpdwArgLocation = lpControlArgs->PnPArgs.dwEventType;
  1241. //
  1242. // Copy the lParam into the buffer
  1243. //
  1244. RtlCopyMemory(lpdwArgLocation + 1,
  1245. lpControlArgs->PnPArgs.EventData,
  1246. lpControlArgs->PnPArgs.dwEventDataSize);
  1247. break;
  1248. }
  1249. }
  1250. // If the SCM is sending a shutdown message to a service, we want to just
  1251. // use WriteFile instead of TransactNamedPipe, since a badly behaved service
  1252. // that doesn't write back to the pipe leaves the SCM hanging and unable to
  1253. // properly shut down the remaining services
  1254. SC_LOG0(LOCKS,"SendControl: Entering TransactPipe Critical Section.\n");
  1255. EnterCriticalSection(&ScTransactNPCriticalSection);
  1256. if (OpCode == SERVICE_CONTROL_SHUTDOWN) {
  1257. SC_LOG0(SHUTDOWN,
  1258. "ScSendControl: Using WriteFile to send a service shutdown message.\n");
  1259. status = WriteFile(
  1260. PipeHandle,
  1261. lpcmhBuffer,
  1262. sendBufferSize,
  1263. &bytesRead,
  1264. &overlapped);
  1265. if (status || (returnStatus = GetLastError()) == ERROR_IO_PENDING) {
  1266. returnStatus = NO_ERROR;
  1267. }
  1268. SC_LOG(SHUTDOWN, "ScSendControl returning with code %d\n", returnStatus);
  1269. }
  1270. else {
  1271. //
  1272. // The parameters are marshalled, now send the buffer and wait for
  1273. // response.
  1274. //
  1275. SC_LOG(TRACE,"SendControl: Sending a TransactMessage.\n",0);
  1276. returnStatus = NO_ERROR;
  1277. status = TransactNamedPipe(PipeHandle,
  1278. lpcmhBuffer,
  1279. sendBufferSize,
  1280. &serviceResponseBuffer,
  1281. sizeof(PIPE_RESPONSE_MSG),
  1282. &bytesRead,
  1283. &overlapped);
  1284. if (status == FALSE) {
  1285. returnStatus = GetLastError();
  1286. if (returnStatus == ERROR_PIPE_BUSY) {
  1287. SC_LOG(ERROR, "Cleaning out pipe for %ws service\n", ServiceName);
  1288. ScCleanOutPipe(PipeHandle);
  1289. status = TRUE;
  1290. returnStatus = NO_ERROR;
  1291. status = TransactNamedPipe(PipeHandle,
  1292. lpcmhBuffer,
  1293. sendBufferSize,
  1294. &serviceResponseBuffer,
  1295. sizeof(PIPE_RESPONSE_MSG),
  1296. &bytesRead,
  1297. &overlapped);
  1298. if (status == FALSE) {
  1299. returnStatus = GetLastError();
  1300. }
  1301. }
  1302. }
  1303. if (status == FALSE) {
  1304. if (returnStatus != ERROR_IO_PENDING) {
  1305. SC_LOG2(ERROR,
  1306. "SendControl:TransactNamedPipe to %ws service failed, rc=%lu\n",
  1307. ServiceName,
  1308. returnStatus);
  1309. goto CleanUp;
  1310. } else {
  1311. #if DBG
  1312. DWORD dwStartTick = GetTickCount();
  1313. DWORD dwTotalTime;
  1314. #endif // DBG
  1315. //
  1316. // Transaction is pending
  1317. //
  1318. status = WaitForSingleObject(PipeHandle, g_dwScPipeTransactTimeout);
  1319. #if DBG
  1320. dwTotalTime = GetTickCount() - dwStartTick;
  1321. if (dwTotalTime > SC_DEFAULT_PIPE_TRANSACT_TIMEOUT) {
  1322. SC_LOG3(ERROR,
  1323. "ScSendControl: Pipe transaction to service %ws on "
  1324. "control %u took %u milliseconds\n",
  1325. ServiceName,
  1326. OpCode,
  1327. dwTotalTime);
  1328. }
  1329. #endif // DBG
  1330. if (status == WAIT_TIMEOUT) {
  1331. SC_LOG2(ERROR,
  1332. "SendControl: Wait on transact to %ws service for %u millisecs timed out\n",
  1333. ServiceName, g_dwScPipeTransactTimeout);
  1334. //
  1335. // Cancel the named pipe operation.
  1336. // NOTE: CancelIo cancels ALL pending I/O operations issued by
  1337. // this thread on the PipeHandle. Since the service controller
  1338. // functions do nothing but wait after starting asynchronous
  1339. // named pipe operations, there should be no other operations.
  1340. //
  1341. status = CancelIo(PipeHandle);
  1342. if (status == FALSE) {
  1343. SC_LOG(ERROR, "SendControl: CancelIo failed, %lu\n", GetLastError());
  1344. }
  1345. ScLogEvent(
  1346. NEVENT_TRANSACT_TIMEOUT,
  1347. g_dwScPipeTransactTimeout,
  1348. ServiceName
  1349. );
  1350. returnStatus = ERROR_SERVICE_REQUEST_TIMEOUT;
  1351. goto CleanUp;
  1352. } else if (status == 0) {
  1353. //
  1354. // Wait completed successfully
  1355. //
  1356. status = GetOverlappedResult(
  1357. PipeHandle,
  1358. &overlapped,
  1359. &bytesRead,
  1360. TRUE
  1361. );
  1362. if (status == FALSE) {
  1363. returnStatus = GetLastError();
  1364. SC_LOG(ERROR,
  1365. "SendControl: GetOverlappedResult failed, rc=%lu\n",
  1366. returnStatus);
  1367. goto CleanUp;
  1368. }
  1369. }
  1370. }
  1371. }
  1372. //
  1373. // Response received from the control dispatcher
  1374. //
  1375. if (bytesRead != sizeof(PIPE_RESPONSE_MSG)) {
  1376. //
  1377. // Successful transact, but we didn't get proper input.
  1378. // (note: we should never receive more bytes unless there
  1379. // is a bug in TransactNamedPipe).
  1380. //
  1381. SC_LOG(ERROR,
  1382. "SendControl: Incorrect num bytes in response, num=%d",
  1383. bytesRead);
  1384. ScLogEvent(NEVENT_TRANSACT_INVALID);
  1385. returnStatus = ERROR_GEN_FAILURE;
  1386. }
  1387. else {
  1388. returnStatus = serviceResponseBuffer.dwDispatcherStatus;
  1389. if (ARGUMENT_PRESENT(lpdwHandlerRetVal)) {
  1390. *lpdwHandlerRetVal = serviceResponseBuffer.dwHandlerRetVal;
  1391. }
  1392. }
  1393. }
  1394. CleanUp:
  1395. SC_LOG(LOCKS,"SendControl: Leaving TransactPipe Critical Section.\n",0);
  1396. LeaveCriticalSection(&ScTransactNPCriticalSection);
  1397. LocalFree(lpcmhBuffer);
  1398. if (returnStatus == NO_ERROR
  1399. &&
  1400. IS_CONTROL_LOGGABLE(OpCode)
  1401. &&
  1402. DisplayName != NULL && DisplayName[0] != L'\0')
  1403. {
  1404. ScLogControlEvent(NEVENT_SERVICE_CONTROL_SUCCESS,
  1405. DisplayName,
  1406. OpCode);
  1407. }
  1408. return(returnStatus);
  1409. }
  1410. VOID
  1411. ScInitTransactNamedPipe(
  1412. VOID
  1413. )
  1414. /*++
  1415. Routine Description:
  1416. This function initializes the Critical Section that serializes
  1417. calls to TransactNamedPipe and sets the pipe timeout value.
  1418. Arguments:
  1419. none
  1420. Return Value:
  1421. none
  1422. --*/
  1423. {
  1424. DWORD dwStatus;
  1425. HKEY hKeyControl;
  1426. DWORD dwValueType;
  1427. DWORD dwBufSize = sizeof(DWORD);
  1428. InitializeCriticalSection(&ScTransactNPCriticalSection);
  1429. //
  1430. // Read the pipe timeout value from the registry if it exists.
  1431. // If the read fails or the value's not there, use the default.
  1432. //
  1433. dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, // hKey
  1434. REGKEY_PIPE_TIMEOUT, // lpSubKey
  1435. 0,
  1436. KEY_READ, // Read access
  1437. &hKeyControl); // Newly Opened Key Handle
  1438. if (dwStatus == NO_ERROR) {
  1439. dwStatus = RegQueryValueEx(hKeyControl,
  1440. REGVAL_PIPE_TIMEOUT,
  1441. NULL,
  1442. &dwValueType,
  1443. (LPBYTE)&g_dwScPipeTransactTimeout,
  1444. &dwBufSize);
  1445. if (dwStatus != NO_ERROR || dwValueType != REG_DWORD) {
  1446. //
  1447. // The value's either not there or bogus so just use the default
  1448. //
  1449. SC_LOG0(TRACE,
  1450. "ScInitTransactNamedPipe: Can't find ServicesPipeTimeout "
  1451. "value in registry\n");
  1452. }
  1453. RegCloseKey(hKeyControl);
  1454. }
  1455. else {
  1456. //
  1457. // Not an error for this function, although a missing control
  1458. // key is probably relatively bad, so notify everybody
  1459. //
  1460. SC_LOG0(ERROR,
  1461. "ScInitTransactNamedPipe: Can't find Control "
  1462. "key in registry!\n");
  1463. }
  1464. SC_LOG1(TRACE,
  1465. "ScInitTransactNamedPipe: Using pipe timeout value of %u\n",
  1466. g_dwScPipeTransactTimeout);
  1467. }
  1468. VOID
  1469. ScShutdownAllServices(
  1470. VOID
  1471. )
  1472. /*++
  1473. Routine Description:
  1474. (called at system shutdown).
  1475. This function sends shutdown requests to all services that have
  1476. registered an interest in shutdown notification.
  1477. When we leave this routine, to the best of our knowledge, all the
  1478. services that should stop have stopped - or are in some hung state.
  1479. Note: It is expected that the RPC entry points are no longer serviced,
  1480. so we should not be receiving any requests that will add or delete
  1481. service records. Therefore, locks are not used when reading service
  1482. records during the shutdown loop.
  1483. Arguments:
  1484. none
  1485. Return Value:
  1486. none
  1487. Note:
  1488. --*/
  1489. {
  1490. DWORD status;
  1491. LPSERVICE_RECORD *affectedServices;
  1492. DWORD serviceIndex = 0;
  1493. DWORD arrayEnd = 0;
  1494. BOOL ServicesStopping;
  1495. DWORD maxWait = 0;
  1496. DWORD startTime;
  1497. DWORD arraySize;
  1498. #ifdef SC_SHUTDOWN_METRIC
  1499. //
  1500. // Local variables for shutdown performance metrics
  1501. //
  1502. DWORD dwShutdownTimeout = 0;
  1503. HKEY hKeyControl;
  1504. DWORD dwValueType;
  1505. DWORD dwBufSize = sizeof(DWORD);
  1506. #endif // SC_SHUTDOWN_METRIC
  1507. //
  1508. // Allocate a temporary array of services which we're interested in.
  1509. // (This is purely an optimization to avoid repeated traversals of the
  1510. // entire database of installed services.)
  1511. //
  1512. CServiceListSharedLock LLock;
  1513. arraySize = ScGetTotalNumberOfRecords();
  1514. affectedServices = (LPSERVICE_RECORD *)LocalAlloc(
  1515. LMEM_FIXED,
  1516. arraySize * sizeof(LPSERVICE_RECORD));
  1517. if (affectedServices == NULL) {
  1518. SC_LOG0(ERROR,"ScShutdownAllServices: LocalAlloc Failed\n");
  1519. return;
  1520. }
  1521. #ifdef SC_SHUTDOWN_METRIC
  1522. //
  1523. // Read the shutdown timeout value from the registry if it exists.
  1524. // If the read fails or the value's not there, use the default.
  1525. //
  1526. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, // hKey
  1527. REGKEY_SHUTDOWN_TIMEOUT, // lpSubKey
  1528. 0,
  1529. KEY_READ, // Read access
  1530. &hKeyControl) // Handle to newly-opened key
  1531. == ERROR_SUCCESS)
  1532. {
  1533. RegQueryValueEx(hKeyControl,
  1534. REGVAL_SHUTDOWN_TIMEOUT,
  1535. NULL,
  1536. &dwValueType,
  1537. (LPBYTE)&dwShutdownTimeout,
  1538. &dwBufSize);
  1539. RegCloseKey(hKeyControl);
  1540. }
  1541. #endif // SC_SHUTDOWN_METRIC
  1542. //-------------------------------------------------------------------
  1543. //
  1544. // Loop through service list sending stop requests to all that
  1545. // should receive such requests.
  1546. //
  1547. //-------------------------------------------------------------------
  1548. SC_LOG0(SHUTDOWN,"***** BEGIN SENDING STOPS TO SERVICES *****\n");
  1549. FOR_SERVICES_THAT(Service,
  1550. (Service->ServiceStatus.dwServiceType & SERVICE_WIN32) &&
  1551. (Service->ServiceStatus.dwCurrentState != SERVICE_STOPPED) &&
  1552. (Service->ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING) &&
  1553. (Service->ServiceStatus.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) &&
  1554. (Service->ImageRecord != NULL)
  1555. )
  1556. {
  1557. //
  1558. // If the service is not in the stopped or stop pending
  1559. // state, it should be ok to send the control.
  1560. //
  1561. SC_LOG1(SHUTDOWN,"Shutdown: Sending Stop to Service : %ws\n",
  1562. Service->ServiceName);
  1563. status = ScSendControl(Service->ServiceName,
  1564. Service->DisplayName,
  1565. Service->ImageRecord->PipeHandle,
  1566. SERVICE_CONTROL_SHUTDOWN,
  1567. NULL, // CmdArgs
  1568. 0L, // NumArgs
  1569. NULL); // Ignore handler return value
  1570. if (status != NO_ERROR) {
  1571. SC_LOG1(ERROR,"ScShutdownAllServices: ScSendControl "
  1572. "Failed for %ws\n",Service->ServiceName);
  1573. }
  1574. else {
  1575. //
  1576. // Save the services that have been sent stop requests
  1577. // in the temporary array.
  1578. //
  1579. SC_ASSERT(serviceIndex < arraySize);
  1580. if (serviceIndex < arraySize) {
  1581. affectedServices[serviceIndex++] = Service;
  1582. }
  1583. }
  1584. }
  1585. SC_LOG0(SHUTDOWN,"***** DONE SENDING STOPS TO SERVICES *****\n");
  1586. //-------------------------------------------------------------------
  1587. //
  1588. // Now check to see if these services stopped.
  1589. //
  1590. //-------------------------------------------------------------------
  1591. startTime = GetTickCount();
  1592. arrayEnd = serviceIndex;
  1593. ServicesStopping = (serviceIndex != 0);
  1594. SC_LOG(SHUTDOWN,"Waiting for services to stop. Start time is %lu\n",
  1595. startTime);
  1596. while (ServicesStopping) {
  1597. //
  1598. // Wait a bit for the services to become stopped.
  1599. //
  1600. Sleep(500);
  1601. //
  1602. // We are going to check all the services in our shutdown
  1603. // list and see if we still have services to wait on.
  1604. //
  1605. ServicesStopping = FALSE;
  1606. maxWait = 0;
  1607. for (serviceIndex = 0; serviceIndex < arrayEnd ; serviceIndex++) {
  1608. Service = affectedServices[serviceIndex];
  1609. //
  1610. // If the service is in the stop pending state, then wait
  1611. // a bit and check back. Maximum wait time is the maximum
  1612. // wait hint period of all the services. If a service's
  1613. // wait hint is 0, use 20 seconds as its wait hint.
  1614. //
  1615. // Note that this is different from how dwWaitHint is
  1616. // interpreted for all other operations. We ignore
  1617. // dwCheckPoint here.
  1618. //
  1619. switch (Service->ServiceStatus.dwCurrentState) {
  1620. case SERVICE_STOP_PENDING:
  1621. SC_LOG2(SHUTDOWN,
  1622. "%ws Service is still pending, wait hint = %lu\n",
  1623. Service->ServiceName,
  1624. Service->ServiceStatus.dwWaitHint);
  1625. if (Service->ServiceStatus.dwWaitHint == 0) {
  1626. if (maxWait < 20000) {
  1627. maxWait = 20000;
  1628. }
  1629. }
  1630. else {
  1631. if (maxWait < Service->ServiceStatus.dwWaitHint) {
  1632. maxWait = Service->ServiceStatus.dwWaitHint;
  1633. }
  1634. }
  1635. ServicesStopping = TRUE;
  1636. break;
  1637. case SERVICE_STOPPED:
  1638. break;
  1639. case SERVICE_RUNNING:
  1640. if (maxWait < 30000) {
  1641. maxWait = 30000;
  1642. }
  1643. SC_LOG2(SHUTDOWN, "%ws Service is still running, maxWait is %lu\n",
  1644. Service->ServiceName, maxWait);
  1645. ServicesStopping = TRUE;
  1646. break;
  1647. default:
  1648. //
  1649. // This is an error. But we can't do anything about
  1650. // it, so it will be ignored.
  1651. //
  1652. SC_LOG2(SHUTDOWN,"ERROR: %ws Service is in invalid state %#lx\n",
  1653. Service->ServiceName,
  1654. Service->ServiceStatus.dwCurrentState);
  1655. break;
  1656. } // end switch
  1657. } // end for
  1658. //
  1659. // We have examined all the services. If there are still services
  1660. // with the STOP_PENDING, then see if we have timed out the
  1661. // maxWait period yet.
  1662. //
  1663. if (ServicesStopping) {
  1664. #ifdef SC_SHUTDOWN_METRIC
  1665. //
  1666. // Performance hook for service shutdown -- if a shutdown
  1667. // timeout was specified in the registry and it's been
  1668. // longer than the timeout, print out a list of all the
  1669. // unstopped services and break into the debugger. Do this
  1670. // on both free and checked builds. Note that this must be
  1671. // #if'ed out prior to shipping NT 5.0.
  1672. //
  1673. if (dwShutdownTimeout != 0
  1674. &&
  1675. (GetTickCount() - startTime) > dwShutdownTimeout) {
  1676. //
  1677. // Uh oh -- we've exceeded the max shutdown time
  1678. //
  1679. DbgPrint("\n[SC-SHUTDOWN] The following services failed to "
  1680. "shut down in %lu seconds:\n",
  1681. dwShutdownTimeout / 1000);
  1682. for (serviceIndex = 0; serviceIndex < arrayEnd; serviceIndex++) {
  1683. Service = affectedServices[serviceIndex];
  1684. if (Service->ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
  1685. DbgPrint("%ws service is still running (state = %lu)\n",
  1686. Service->ServiceName,
  1687. Service->ServiceStatus.dwCurrentState);
  1688. }
  1689. }
  1690. DebugBreak();
  1691. }
  1692. #endif // SC_SHUTDOWN_METRIC
  1693. if ( (GetTickCount() - startTime) > maxWait ) {
  1694. //
  1695. // The maximum wait period has been exceeded. At this
  1696. // point we should end this shutdown effort. There is
  1697. // no point in forcing shutdown. So we just exit.
  1698. //
  1699. SC_LOG(ERROR,
  1700. "The Services didn't stop within the timeout "
  1701. "period of %lu.\n --- There is still at least one "
  1702. "service running\n",
  1703. maxWait);
  1704. #if DBG
  1705. SC_LOG0(ERROR, "The following Services failed to shut down:\n");
  1706. for (serviceIndex = 0; serviceIndex < arrayEnd ; serviceIndex++) {
  1707. Service = affectedServices[serviceIndex];
  1708. if (Service->ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
  1709. SC_LOG2(ERROR, "%ws Service is still running (Service state = %lu)\n",
  1710. Service->ServiceName, Service->ServiceStatus.dwCurrentState);
  1711. }
  1712. }
  1713. #endif // DBG
  1714. ServicesStopping = FALSE;
  1715. }
  1716. }
  1717. }
  1718. SC_LOG0(SHUTDOWN,"Done Waiting for services to stop\n");
  1719. //
  1720. // With a FAT file system and critical update notification enabled, we
  1721. // need to shut down the SCE's RPC server to avoid a dirty shutdown.
  1722. // If we don't, SCE will access files under %windir%\security after
  1723. // FAT has marked the volumes as clean.
  1724. //
  1725. ScesrvTerminateServer((PSVCS_STOP_RPC_SERVER) RpcpStopRpcServer);
  1726. }
  1727. VOID
  1728. ScCleanOutPipe(
  1729. HANDLE PipeHandle
  1730. )
  1731. /*++
  1732. Routine Description:
  1733. This function reads and throws away all data that is currently in the
  1734. pipe. This function is called if the pipe is busy when it shouldn't be.
  1735. The PIPE_BUSY occurs when (1) the transact never returns, or (2) the
  1736. last transact timed-out, and the return message was eventually placed
  1737. in the pipe after the timeout.
  1738. This function is called to fix the (2) case by cleaning out the pipe.
  1739. Arguments:
  1740. PipeHandle - A Handle to the pipe to be cleaned out.
  1741. Return Value:
  1742. none.
  1743. --*/
  1744. {
  1745. #define EXPUNGE_BUF_SIZE 100
  1746. DWORD status;
  1747. DWORD returnStatus;
  1748. DWORD numBytesRead=0;
  1749. BYTE msg[EXPUNGE_BUF_SIZE];
  1750. OVERLAPPED overlapped={0,0,0,0,0};
  1751. do {
  1752. overlapped.hEvent = (HANDLE) NULL; // Wait on pipe handle
  1753. status = ReadFile (
  1754. PipeHandle,
  1755. msg,
  1756. EXPUNGE_BUF_SIZE,
  1757. &numBytesRead,
  1758. &overlapped);
  1759. if (status == FALSE) {
  1760. returnStatus = GetLastError();
  1761. if (returnStatus == ERROR_IO_PENDING) {
  1762. status = WaitForSingleObject(
  1763. PipeHandle,
  1764. SC_PIPE_CLEANOUT_TIMEOUT);
  1765. if (status == WAIT_TIMEOUT) {
  1766. SC_LOG0(ERROR, "ControlPipe was busy but we were unable to "
  1767. "clean it out in the timeout period\n");
  1768. //
  1769. // Cancel the named pipe operation.
  1770. //
  1771. status = CancelIo(PipeHandle);
  1772. if (status == FALSE) {
  1773. SC_LOG(ERROR,
  1774. "ScCleanOutPipe: CancelIo failed, %lu\n",
  1775. GetLastError());
  1776. }
  1777. }
  1778. }
  1779. else {
  1780. SC_LOG1(ERROR, "ControlPipe was busy. The attempt to clean"
  1781. "it out failed with %d\n", returnStatus);
  1782. }
  1783. }
  1784. }
  1785. while (status == ERROR_MORE_DATA);
  1786. }