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.

1266 lines
39 KiB

  1. /*++
  2. Copyright (c) 1991-92 Microsoft Corporation
  3. Module Name:
  4. info.cxx
  5. Abstract:
  6. Contains entry points for REnumServicesStatusW and RQueryServiceStatus as
  7. well as support routines. This file contains the following external
  8. functions:
  9. REnumServicesStatusW
  10. REnumServicesStatusExW
  11. REnumServiceGroupW
  12. RQueryServiceStatus
  13. RQueryServiceStatusEx
  14. REnumDependentServicesW
  15. Author:
  16. Dan Lafferty (danl) 25-Jan-1992
  17. Environment:
  18. User Mode -Win32
  19. Revision History:
  20. 25-Apr-1996 AnirudhS
  21. Don't popup messages or log events for boot start and system start
  22. drivers that are disabled in the current hardware profile.
  23. 14-Feb-1996 AnirudhS
  24. Add REnumServiceGroupW.
  25. 10-Feb-1993 Danl
  26. Use ROUND_DOWN_COUNT to properly align the enumeration buffer.
  27. 10-Apr-1992 JohnRo
  28. Use ScImagePathsMatch() to allow mixed-case image names.
  29. Changed names of some <valid.h> macros.
  30. 25-Jan-1992 danl
  31. Created.
  32. --*/
  33. //
  34. // INCLUDES
  35. //
  36. #include "precomp.hxx"
  37. #include <stdlib.h> // wide character c runtimes.
  38. #include <tstr.h> // Unicode string macros
  39. #include <align.h> // ROUND_DOWN_COUNT
  40. #include <sclib.h> // ScCopyStringToBufferW(), etc.
  41. #include <valid.h> // ENUM_STATE_INVALID
  42. #include "info.h" // ScQueryServiceStatus
  43. #include "depend.h" // ScEnumDependents, ScInHardwareProfile
  44. #include "driver.h" // ScGetDriverStatus
  45. #include <cfgmgr32.h> // PNP manager functions
  46. #include <scwow.h> // 32/64-bit interop structures
  47. //
  48. // DEFINITIONS
  49. //
  50. #define IS_NOGROUP_STRING(string) (string[0] == L'\0')
  51. //
  52. // Local function declarations
  53. //
  54. DWORD
  55. REnumServiceGroupHelp (
  56. IN SC_RPC_HANDLE hSCManager,
  57. IN DWORD dwServiceType,
  58. IN DWORD dwServiceState,
  59. OUT PBYTE lpBuffer,
  60. IN DWORD cbBufSize,
  61. OUT LPDWORD pcbBytesNeeded,
  62. OUT LPDWORD lpServicesReturned,
  63. IN OUT LPDWORD lpResumeIndex OPTIONAL,
  64. IN LPCWSTR lpLoadOrderGroup OPTIONAL,
  65. IN BOOL fExtended
  66. );
  67. //
  68. // Function implementations
  69. //
  70. DWORD
  71. REnumServicesStatusW (
  72. IN SC_RPC_HANDLE hSCManager,
  73. IN DWORD dwServiceType,
  74. IN DWORD dwServiceState,
  75. OUT PBYTE lpBuffer,
  76. IN DWORD cbBufSize,
  77. OUT LPDWORD pcbBytesNeeded,
  78. OUT LPDWORD lpServicesReturned,
  79. IN OUT LPDWORD lpResumeIndex OPTIONAL
  80. )
  81. /*++
  82. Routine Description:
  83. This function lists the services installed in the Service Controller's
  84. database. The status of each service is returned with the name of
  85. the service.
  86. Arguments:
  87. hSCManager - This is a handle to the service controller. It must
  88. have been opened with SC_MANAGER_ENUMERATE_SERVICE access.
  89. dwServiceType - Value to select the type of services to enumerate.
  90. It must be one of the bitwise OR of the following values:
  91. SERVICE_WIN32 - enumerate Win32 services only.
  92. SERVICE_DRIVER - enumerate Driver services only.
  93. dwServiceState - Value so select the services to enumerate based on the
  94. running state. It must be one or the bitwise OR of the following
  95. values:
  96. SERVICE_ACTIVE - enumerate services that have started.
  97. SERVICE_INACTIVE - enumerate services that are stopped.
  98. lpBuffer - A pointer to a buffer to receive an array of enum status
  99. (or service) entries.
  100. cbBufSize - Size of the buffer in bytes pointed to by lpBuffer.
  101. pcbBytesNeeded - A pointer to a location where the number of bytes
  102. left (to be enumerated) is to be placed. This indicates to the
  103. caller how large the buffer must be in order to complete the
  104. enumeration with the next call.
  105. lpServicesReturned - A pointer to a variable to receive the number of
  106. of service entries returned.
  107. lpResumeIndex - A pointer to a variable which on input specifies the
  108. index of a service entry to begin enumeration. An index of 0
  109. indicates to start at the beginning. On output, if this function
  110. returns ERROR_MORE_DATA, the index returned is the next service
  111. entry to resume the enumeration. The returned index is 0 if this
  112. function returns a NO_ERROR.
  113. Return Value:
  114. NO_ERROR - The operation was successful.
  115. ERROR_MORE_DATA - Not all of the data in the active database could be
  116. returned due to the size of the user's buffer. pcbBytesNeeded
  117. contains the number of bytes required to get the remaining
  118. entries.
  119. ERROR_INVALID_PARAMETER - An illegal parameter value was passed in.
  120. (such as dwServiceType).
  121. ERROR_INVALID_HANDLE - The specified handle was invalid.
  122. Note:
  123. It is expected that the RPC Stub functions will find the following
  124. parameter problems:
  125. Bad pointers for lpBuffer, pcbReturned, pcbBytesNeeded,
  126. lpBuffer, ReturnedServerName, and lpResumeIndex.
  127. --*/
  128. {
  129. return REnumServiceGroupHelp(hSCManager,
  130. dwServiceType,
  131. dwServiceState,
  132. lpBuffer,
  133. cbBufSize,
  134. pcbBytesNeeded,
  135. lpServicesReturned,
  136. lpResumeIndex,
  137. NULL, // Enumerate everything
  138. FALSE); // Regular (non-Ex) enumeration
  139. }
  140. DWORD
  141. REnumServicesStatusExW (
  142. IN SC_RPC_HANDLE hSCManager,
  143. IN SC_ENUM_TYPE InfoLevel,
  144. IN DWORD dwServiceType,
  145. IN DWORD dwServiceState,
  146. OUT PBYTE lpBuffer,
  147. IN DWORD cbBufSize,
  148. OUT LPDWORD pcbBytesNeeded,
  149. OUT LPDWORD lpServicesReturned,
  150. IN OUT LPDWORD lpResumeIndex OPTIONAL,
  151. IN LPCWSTR lpLoadOrderGroup
  152. )
  153. /*++
  154. Routine Description:
  155. This function is analogous to REnumServicesStatusW, with the data
  156. being enumerated being dependent upon the InfoLevel parameter
  157. Arguments:
  158. InfoLevel - An enumerated type that determines what service attributes
  159. are enumerated:
  160. SC_ENUM_PROCESS_INFO - Enumerates all the service information from
  161. REnumServicesStatusW plus the service's PID and flags
  162. lpLoadOrderGroup - Only enumerate services belonging to the given group.
  163. If this parameter is the empty string, services not belonging to
  164. a group are enumerated. If this parameter is NULL, no attention
  165. is paid to group.
  166. Return Value:
  167. NO_ERROR - The operation was successful.
  168. ERROR_MORE_DATA - Not all of the data in the active database could be
  169. returned due to the size of the user's buffer. pcbBytesNeeded
  170. contains the number of bytes required to get the remaining
  171. entries.
  172. ERROR_INVALID_PARAMETER - An illegal parameter value was passed in.
  173. (such as dwServiceType).
  174. ERROR_INVALID_HANDLE - The specified handle was invalid.
  175. ERROR_INVALID_LEVEL - The specified InfoLevel is invalid
  176. Note:
  177. It is expected that the RPC Stub functions will find the following
  178. parameter problems:
  179. Bad pointers for lpBuffer, pcbReturned, pcbBytesNeeded,
  180. lpBuffer, ReturnedServerName, and lpResumeIndex.
  181. --*/
  182. {
  183. switch (InfoLevel) {
  184. case SC_ENUM_PROCESS_INFO:
  185. return REnumServiceGroupHelp(hSCManager,
  186. dwServiceType,
  187. dwServiceState,
  188. lpBuffer,
  189. cbBufSize,
  190. pcbBytesNeeded,
  191. lpServicesReturned,
  192. lpResumeIndex,
  193. lpLoadOrderGroup,
  194. TRUE); // Extended enumeration
  195. default:
  196. return ERROR_INVALID_LEVEL;
  197. }
  198. }
  199. DWORD
  200. REnumServiceGroupW (
  201. IN SC_RPC_HANDLE hSCManager,
  202. IN DWORD dwServiceType,
  203. IN DWORD dwServiceState,
  204. OUT PBYTE lpBuffer,
  205. IN DWORD cbBufSize,
  206. OUT LPDWORD pcbBytesNeeded,
  207. OUT LPDWORD lpServicesReturned,
  208. IN OUT LPDWORD lpResumeIndex OPTIONAL,
  209. IN LPCWSTR lpLoadOrderGroup OPTIONAL
  210. )
  211. /*++
  212. Routine Description:
  213. This function lists the services installed in the Service Controllers
  214. database that belong to a specified group. The status of each service
  215. is returned with the name of the service.
  216. Arguments:
  217. Same as REnumServicesStatusW and one additional argument:
  218. lpLoadOrderGroup - Only services belonging to this group are included in
  219. the enumeration. If this is NULL services are enumerated
  220. regardless of their group membership.
  221. Return Value:
  222. Same as REnumServicesStatusW plus one more:
  223. ERROR_SERVICE_DOES_NOT_EXIST - the group specified by lpLoadOrderGroup
  224. does not exist.
  225. --*/
  226. {
  227. return REnumServiceGroupHelp(hSCManager,
  228. dwServiceType,
  229. dwServiceState,
  230. lpBuffer,
  231. cbBufSize,
  232. pcbBytesNeeded,
  233. lpServicesReturned,
  234. lpResumeIndex,
  235. lpLoadOrderGroup,
  236. FALSE); // Regular (non-Ex) enumeration
  237. }
  238. DWORD
  239. REnumServiceGroupHelp (
  240. IN SC_RPC_HANDLE hSCManager,
  241. IN DWORD dwServiceType,
  242. IN DWORD dwServiceState,
  243. OUT PBYTE lpBuffer,
  244. IN DWORD cbBufSize,
  245. OUT LPDWORD pcbBytesNeeded,
  246. OUT LPDWORD lpServicesReturned,
  247. IN OUT LPDWORD lpResumeIndex OPTIONAL,
  248. IN LPCWSTR lpLoadOrderGroup OPTIONAL,
  249. IN BOOL fExtended
  250. )
  251. /*++
  252. Routine Description:
  253. Helper function that does the work for REnumServiceGroup,
  254. REnumServicesStatusW, and REnumServicesStatusExW
  255. Arguments:
  256. Same as REnumServiceGroup and one additional argument
  257. fExtended -- TRUE if this function was called from the extended version
  258. of REnumServicesStatus, FALSE if not
  259. Return Value:
  260. Same as REnumServiceGroupW
  261. --*/
  262. {
  263. DWORD status = NO_ERROR;
  264. BOOL copyStatus;
  265. LPSERVICE_RECORD serviceRecord;
  266. LPLOAD_ORDER_GROUP Group = NULL; // group being enumerated, if any
  267. DWORD resumeIndex = 0; // resume handle value
  268. LPENUM_SERVICE_STATUS_WOW64 pNextEnumRec; // next enum record
  269. LPENUM_SERVICE_STATUS_WOW64 pEnumRec; // current regular enum record
  270. LPWSTR pStringBuf; // works backwards in enum buf
  271. DWORD serviceState; // temp state holder
  272. BOOL exitEarly = FALSE; // buffer is full - enum not done.
  273. BOOL fNoGroup = FALSE; // enumerate services not in a group
  274. #ifdef TIMING_TEST
  275. DWORD TickCount1;
  276. DWORD TickCount2;
  277. TickCount1 = GetTickCount();
  278. #endif // TIMING_TEST
  279. SC_LOG(TRACE," Inside REnumServicesStatusW\n",0);
  280. if (ScShutdownInProgress) {
  281. return(ERROR_SHUTDOWN_IN_PROGRESS);
  282. }
  283. //
  284. // Check the handle.
  285. //
  286. if (!ScIsValidScManagerHandle(hSCManager))
  287. {
  288. return ERROR_INVALID_HANDLE;
  289. }
  290. //
  291. // Check for invalid parameters. The ServiceType and Service State are
  292. // invalid if neither of the bit masks are set, or if any bit outside
  293. // of the bitmask range is set.
  294. //
  295. if (SERVICE_TYPE_MASK_INVALID(dwServiceType)) {
  296. return (ERROR_INVALID_PARAMETER);
  297. }
  298. if (ENUM_STATE_MASK_INVALID(dwServiceState)) {
  299. return (ERROR_INVALID_PARAMETER);
  300. }
  301. //
  302. // Was the handle opened with SC_MANAGER_ENUMERATE_SERVICE access?
  303. //
  304. if (! RtlAreAllAccessesGranted(
  305. ((LPSC_HANDLE_STRUCT)hSCManager)->AccessGranted,
  306. SC_MANAGER_ENUMERATE_SERVICE
  307. )) {
  308. return(ERROR_ACCESS_DENIED);
  309. }
  310. //
  311. // Initialize some of the return parameters.
  312. //
  313. *lpServicesReturned = 0;
  314. *pcbBytesNeeded = 0;
  315. if (ARGUMENT_PRESENT(lpResumeIndex)) {
  316. resumeIndex = *lpResumeIndex;
  317. }
  318. //
  319. // If a group name was specified, find the group record.
  320. //
  321. if (ARGUMENT_PRESENT(lpLoadOrderGroup)) {
  322. if (!IS_NOGROUP_STRING(lpLoadOrderGroup)) {
  323. ScGroupListLock.GetShared();
  324. Group = ScGetNamedGroupRecord(lpLoadOrderGroup);
  325. if (Group == NULL) {
  326. ScGroupListLock.Release();
  327. return(ERROR_SERVICE_DOES_NOT_EXIST);
  328. }
  329. }
  330. else {
  331. //
  332. // Enumerate services not in a group
  333. //
  334. fNoGroup = TRUE;
  335. }
  336. }
  337. //
  338. // Get a shared (read) lock on the database so that it cannot be changed
  339. // while we're gathering up data.
  340. //
  341. {
  342. CServiceListSharedLock LLock;
  343. CServiceRecordSharedLock RLock;
  344. //
  345. // Point to the start of the database.
  346. //
  347. if (!ScFindEnumStart(resumeIndex, &serviceRecord))
  348. {
  349. //
  350. // There are no service records beyond the resume index.
  351. //
  352. goto CleanExit;
  353. }
  354. //
  355. // Set up a pointer for EnumStatus Structures at the top of the
  356. // buffer, and Strings at the bottom of the buffer.
  357. //
  358. cbBufSize = ROUND_DOWN_COUNT(cbBufSize, ALIGN_WCHAR);
  359. pEnumRec = (LPENUM_SERVICE_STATUS_WOW64) lpBuffer;
  360. pStringBuf = (LPWSTR)((LPBYTE)lpBuffer + cbBufSize);
  361. //
  362. // Loop through, gathering Enum Status into the return buffer.
  363. //
  364. do
  365. {
  366. //
  367. // Examine the data in the service record to see if it meets the
  368. // criteria of the passed in keys.
  369. //
  370. //
  371. // Since driver state can be modified through other means than the
  372. // SCM, make sure we've got the most recent state information if we're
  373. // enumerating drivers.
  374. //
  375. if (serviceRecord->ServiceStatus.dwServiceType & SERVICE_DRIVER)
  376. {
  377. //
  378. // It's OK to use CServiceRecordTEMPORARYEXCLUSIVELOCK
  379. // because the only field of the service record that we
  380. // are relying on here is the SERVICE_DRIVER bits, and
  381. // those are never changed.
  382. //
  383. CServiceRecordTEMPORARYEXCLUSIVELOCK Lock;
  384. //
  385. // Ignore the error and don't ask for the updated info since we'll
  386. // use the fields in the serviceRecord below anyhow for comparisons
  387. // and copying. If the call succeeded, they'll be updated already.
  388. // If not, we'll end up using the most recent state info we have.
  389. //
  390. ScGetDriverStatus(serviceRecord, NULL);
  391. }
  392. serviceState = SERVICE_INACTIVE;
  393. if (serviceRecord->ServiceStatus.dwCurrentState != SERVICE_STOPPED)
  394. {
  395. serviceState = SERVICE_ACTIVE;
  396. }
  397. //
  398. // If the service record meets the criteria of the passed in key,
  399. // put its information into the return buffer. The three checks
  400. // below are:
  401. //
  402. // 1. Enumerate everything
  403. // 2. Enumerate members of a certain group only, so check to see
  404. // if the current service is a member of that group
  405. // 3. Enumerate only services that aren't in a group, so check to
  406. // see if the current service qualifies (NULL MemberOfGroup
  407. // field)
  408. //
  409. if ((Group == NULL && !fNoGroup
  410. || Group && Group == serviceRecord->MemberOfGroup
  411. || fNoGroup && !serviceRecord->MemberOfGroup)
  412. &&
  413. ((dwServiceType & serviceRecord->ServiceStatus.dwServiceType) != 0)
  414. &&
  415. ((dwServiceState & serviceState) != 0))
  416. {
  417. //
  418. // Determine if there is room for any string data in the buffer.
  419. //
  420. if (fExtended)
  421. {
  422. pNextEnumRec =
  423. (LPENUM_SERVICE_STATUS_WOW64)
  424. ((LPENUM_SERVICE_STATUS_PROCESS_WOW64) pEnumRec + 1);
  425. }
  426. else
  427. {
  428. pNextEnumRec = pEnumRec + 1;
  429. }
  430. if ((LPWSTR) pNextEnumRec >= pStringBuf)
  431. {
  432. exitEarly = TRUE;
  433. break;
  434. }
  435. //
  436. // Copy the ServiceName string data.
  437. //
  438. copyStatus = ScCopyStringToBufferW(
  439. serviceRecord->ServiceName,
  440. (DWORD) wcslen(serviceRecord->ServiceName),
  441. (LPWSTR) pNextEnumRec,
  442. &pStringBuf,
  443. (LPWSTR *) &(pEnumRec->dwServiceNameOffset),
  444. lpBuffer);
  445. if (copyStatus == FALSE)
  446. {
  447. SC_LOG(TRACE,
  448. "REnumServicesStatusW:NetpCopyStringToBuf not enough room\n",0);
  449. exitEarly = TRUE;
  450. break;
  451. }
  452. //
  453. // Copy the DisplayName string data.
  454. //
  455. copyStatus = ScCopyStringToBufferW(
  456. serviceRecord->DisplayName,
  457. (DWORD) wcslen(serviceRecord->DisplayName),
  458. (LPWSTR) pNextEnumRec,
  459. &pStringBuf,
  460. (LPWSTR *) &(pEnumRec->dwDisplayNameOffset),
  461. lpBuffer);
  462. if (copyStatus == FALSE)
  463. {
  464. SC_LOG(TRACE,
  465. "REnumServicesStatusW:NetpCopyStringToBuf not enough room\n",0);
  466. exitEarly = TRUE;
  467. break;
  468. }
  469. else
  470. {
  471. //
  472. // Copy the rest of the status information.
  473. //
  474. LPSERVICE_STATUS_PROCESS lpStatusEx = NULL;
  475. //
  476. // If we're enumerating the extended status, assign the
  477. // "helper variable" and initialize the extra fields
  478. //
  479. if (fExtended)
  480. {
  481. lpStatusEx =
  482. &((LPENUM_SERVICE_STATUS_PROCESS_WOW64)pEnumRec)->ServiceStatusProcess;
  483. lpStatusEx->dwProcessId = 0;
  484. lpStatusEx->dwServiceFlags = 0;
  485. }
  486. if (serviceRecord->ServiceStatus.dwServiceType & SERVICE_DRIVER)
  487. {
  488. RtlCopyMemory(&(pEnumRec->ServiceStatus),
  489. &(serviceRecord->ServiceStatus),
  490. sizeof(SERVICE_STATUS));
  491. }
  492. else
  493. {
  494. //
  495. // Otherwise, just copy what is already in the service
  496. // record.
  497. //
  498. RtlCopyMemory(
  499. &(pEnumRec->ServiceStatus),
  500. &(serviceRecord->ServiceStatus),
  501. sizeof(SERVICE_STATUS));
  502. if (fExtended)
  503. {
  504. //
  505. // Only assign the PID and flags if there's an
  506. // image record for the service. If there's no
  507. // image record, the service isn't running.
  508. //
  509. if (serviceRecord->ImageRecord)
  510. {
  511. lpStatusEx->dwProcessId = serviceRecord->ImageRecord->Pid;
  512. if (serviceRecord->ImageRecord->ImageFlags
  513. &
  514. IS_SYSTEM_SERVICE)
  515. {
  516. lpStatusEx->dwServiceFlags |=
  517. SERVICE_RUNS_IN_SYSTEM_PROCESS;
  518. }
  519. }
  520. }
  521. }
  522. (*lpServicesReturned)++;
  523. resumeIndex = serviceRecord->ResumeNum;
  524. //
  525. // Get Location for next Enum Record in the return buffer.
  526. // Note that since we dealt with the pointer addition on
  527. // pNextEnumRec above, it doesn't matter that this is
  528. // being cast to an LPENUM_SERVICE_STATUS_WOW64, even if
  529. // we're returning the extended status.
  530. //
  531. pEnumRec = (LPENUM_SERVICE_STATUS_WOW64) pNextEnumRec;
  532. //
  533. // TODO: Determine how many bytes are being marshalled.
  534. // This is only worthwhile if RPC will pack the
  535. // buffer tighter than this code does.
  536. // Since packstr loads strings from the end of
  537. // the buffer, we end up using the whole width of
  538. // it - even if the middle is basically empty.
  539. //
  540. }
  541. }
  542. //
  543. // Go to the next service record.
  544. //
  545. serviceRecord = serviceRecord->Next;
  546. }
  547. while (serviceRecord != NULL);
  548. //
  549. // If we did not enum the whole database, then
  550. // determine how large a buffer is needed to complete the database on
  551. // the next call.
  552. //
  553. if (exitEarly) {
  554. do {
  555. //
  556. // Examine the data in the service record to see if it meets the
  557. // criteria of the passed in keys.
  558. //
  559. serviceState = SERVICE_INACTIVE;
  560. if (serviceRecord->ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
  561. serviceState = SERVICE_ACTIVE;
  562. }
  563. //
  564. // If the service record meets the criteria of the passed in key,
  565. // add the number of bytes to the running sum. Note that this
  566. // check (and the associated rules) are the same as the one above.
  567. //
  568. if ((Group == NULL && !fNoGroup
  569. || Group && Group == serviceRecord->MemberOfGroup
  570. || fNoGroup && !serviceRecord->MemberOfGroup)
  571. &&
  572. ((dwServiceType & serviceRecord->ServiceStatus.dwServiceType) != 0)
  573. &&
  574. ((dwServiceState & serviceState) != 0))
  575. {
  576. *pcbBytesNeeded += (DWORD)((fExtended ? sizeof(ENUM_SERVICE_STATUS_PROCESS_WOW64) :
  577. sizeof(ENUM_SERVICE_STATUS_WOW64)) +
  578. WCSSIZE(serviceRecord->ServiceName) +
  579. WCSSIZE(serviceRecord->DisplayName));
  580. }
  581. //
  582. // Go to the next service record.
  583. //
  584. serviceRecord = serviceRecord->Next;
  585. }
  586. while (serviceRecord != NULL);
  587. } // exitEarly
  588. else {
  589. //
  590. // exitEarly == FALSE (we went through the whole database)
  591. //
  592. // If no records were read, return a successful status.
  593. //
  594. if (*lpServicesReturned == 0) {
  595. goto CleanExit;
  596. }
  597. }
  598. } // Release RLock and LLock
  599. //
  600. // Determine the proper return status. Indicate if there is more data
  601. // to enumerate than would fit in the buffer.
  602. //
  603. if(*pcbBytesNeeded != 0) {
  604. status = ERROR_MORE_DATA;
  605. }
  606. //
  607. // update the ResumeHandle
  608. //
  609. if (ARGUMENT_PRESENT(lpResumeIndex)) {
  610. if (status == NO_ERROR) {
  611. *lpResumeIndex = 0;
  612. }
  613. else {
  614. *lpResumeIndex = resumeIndex;
  615. }
  616. }
  617. CleanExit:
  618. if (ARGUMENT_PRESENT(lpLoadOrderGroup) && !IS_NOGROUP_STRING(lpLoadOrderGroup)) {
  619. ScGroupListLock.Release();
  620. }
  621. #ifdef TIMING_TEST
  622. TickCount2 = GetTickCount();
  623. DbgPrint("\n[SC_TIMING] Time for Enum = %d\n",TickCount2-TickCount1);
  624. #endif // TIMING_TEST
  625. return (status);
  626. }
  627. DWORD
  628. RQueryServiceStatus(
  629. IN SC_RPC_HANDLE hService,
  630. OUT LPSERVICE_STATUS lpServiceStatus
  631. )
  632. /*++
  633. Routine Description:
  634. This function returns the service status information maintained by
  635. the Service Controller. The status information will be the last status
  636. information that the service reported to the Service Controller.
  637. The service may have just changed its status and may not have updated
  638. the Service Controller yet.
  639. Arguments:
  640. hService - Handle obtained from a previous CreateService or OpenService
  641. call.
  642. lpServiceStatus - A pointer to a buffer to receive a SERVICE_STATUS
  643. information structure.
  644. Return Value:
  645. NO_ERROR - The operation was successful.
  646. ERROR_INVALID_HANDLE - The specified handle was invalid.
  647. ERROR_ACCESS_DENIED - The specified handle was not opened with
  648. SERVICE_QUERY_STATUS access.
  649. ERROR_INSUFFICIENT_BUFFER - The supplied output buffer is too small
  650. for the SERVICE_STATUS information structure. Nothing is written
  651. to the supplied output buffer.
  652. --*/
  653. {
  654. LPSERVICE_RECORD serviceRecord;
  655. STATUS_UNION ServiceStatus;
  656. if (ScShutdownInProgress)
  657. {
  658. return ERROR_SHUTDOWN_IN_PROGRESS;
  659. }
  660. //
  661. // Check the handle.
  662. //
  663. if (!ScIsValidServiceHandle(hService))
  664. {
  665. return ERROR_INVALID_HANDLE;
  666. }
  667. //
  668. // Was the handle opened with SERVICE_QUERY_STATUS access?
  669. //
  670. if (! RtlAreAllAccessesGranted(
  671. ((LPSC_HANDLE_STRUCT)hService)->AccessGranted,
  672. SERVICE_QUERY_STATUS
  673. )) {
  674. return ERROR_ACCESS_DENIED;
  675. }
  676. //
  677. // Get the Service Status from the database.
  678. //
  679. serviceRecord = ((LPSC_HANDLE_STRUCT)hService)->Type.ScServiceObject.ServiceRecord;
  680. ServiceStatus.Regular = lpServiceStatus;
  681. return ScQueryServiceStatus(serviceRecord, ServiceStatus, FALSE);
  682. }
  683. DWORD
  684. RQueryServiceStatusEx(
  685. IN SC_RPC_HANDLE hService,
  686. IN SC_STATUS_TYPE InfoLevel,
  687. OUT LPBYTE lpBuffer,
  688. IN DWORD cbBufSize,
  689. OUT LPDWORD pcbBytesNeeded
  690. )
  691. /*++
  692. Routine Description:
  693. This function is analogous to RQueryServiceStatus, but may return
  694. different status information about the service based on the InfoLevel
  695. Arguments:
  696. hService - Handle obtained from a previous CreateService or OpenService
  697. call.
  698. InfoLevel - An enumerated type that determines what service attributes
  699. are returned:
  700. SC_STATUS_PROCESS_INFO - Returns all the service information
  701. from RQueryServiceStatus plus the service's PID and flags
  702. lpBuffer - Buffer in which to put the status information.
  703. cbBufSize - Size of the buffer, in bytes
  704. pcbBytesNeeded - Number of bytes needed to hold all the status information.
  705. Filled in on both success and failure.
  706. Return Value:
  707. NO_ERROR - The operation was successful.
  708. ERROR_INVALID_HANDLE - The specified handle was invalid.
  709. ERROR_ACCESS_DENIED - The specified handle was not opened with
  710. SERVICE_QUERY_STATUS access.
  711. ERROR_INSUFFICIENT_BUFFER - The supplied output buffer is too small
  712. for the SERVICE_STATUS information structure. Nothing is written
  713. to the supplied output buffer.
  714. ERROR_INVALID_PARAMETER - The cbSize field in the lpServiceStatusEx
  715. structure is not valid
  716. ERROR_INVALID_LEVEL - InfoLevel contains an unsupported value. Note that
  717. this can only happen if there is a bug in RPC
  718. --*/
  719. {
  720. LPSERVICE_RECORD serviceRecord;
  721. if (ScShutdownInProgress)
  722. {
  723. return ERROR_SHUTDOWN_IN_PROGRESS;
  724. }
  725. //
  726. // Check the handle.
  727. //
  728. if (!ScIsValidServiceHandle(hService))
  729. {
  730. return ERROR_INVALID_HANDLE;
  731. }
  732. //
  733. // Was the handle opened with SERVICE_QUERY_STATUS access?
  734. //
  735. if (! RtlAreAllAccessesGranted(
  736. ((LPSC_HANDLE_STRUCT)hService)->AccessGranted,
  737. SERVICE_QUERY_STATUS
  738. )) {
  739. return ERROR_ACCESS_DENIED;
  740. }
  741. //
  742. // Get the Service Status from the database.
  743. //
  744. serviceRecord = ((LPSC_HANDLE_STRUCT)hService)->Type.ScServiceObject.ServiceRecord;
  745. switch (InfoLevel) {
  746. case SC_STATUS_PROCESS_INFO:
  747. {
  748. STATUS_UNION ServiceStatus;
  749. *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
  750. if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS)) {
  751. return ERROR_INSUFFICIENT_BUFFER;
  752. }
  753. ServiceStatus.Ex = (LPSERVICE_STATUS_PROCESS) lpBuffer;
  754. return ScQueryServiceStatus(serviceRecord, ServiceStatus, TRUE);
  755. }
  756. default:
  757. return ERROR_INVALID_LEVEL;
  758. }
  759. }
  760. DWORD
  761. ScQueryServiceStatus(
  762. IN LPSERVICE_RECORD ServiceRecord,
  763. OUT STATUS_UNION ServiceStatus,
  764. IN BOOL fExtendedStatus
  765. )
  766. /*++
  767. Routine Description:
  768. This function copies the service status structure to the output
  769. pointer after having acquired a shared lock.
  770. Arguments:
  771. ServiceRecord - Supplies a pointer to the service record.
  772. ServiceStatus - Receives the service status structure.
  773. fExtendedStatus - TRUE if the function was called from
  774. RQueryServiceStatusEx, FALSE otherwise
  775. Return Value:
  776. None.
  777. --*/
  778. {
  779. SC_ASSERT(! ScServiceRecordLock.Have());
  780. //
  781. // Sanity check that the contents of the union are stored
  782. // in the same set of 4 bytes since they're both pointers
  783. //
  784. SC_ASSERT((LPBYTE)ServiceStatus.Ex == (LPBYTE)ServiceStatus.Regular);
  785. if (fExtendedStatus) {
  786. ServiceStatus.Ex->dwProcessId = 0;
  787. ServiceStatus.Ex->dwServiceFlags = 0;
  788. }
  789. //
  790. // If this request is for a driver, call ScGetDriverStatus and return.
  791. //
  792. if (ServiceRecord->ServiceStatus.dwServiceType & SERVICE_DRIVER) {
  793. CServiceRecordExclusiveLock RLock;
  794. return ScGetDriverStatus(ServiceRecord,
  795. ServiceStatus.Regular);
  796. }
  797. else {
  798. CServiceRecordSharedLock RLock;
  799. //
  800. // Copy the latest status into the return buffer.
  801. //
  802. RtlCopyMemory(
  803. ServiceStatus.Regular,
  804. &(ServiceRecord->ServiceStatus),
  805. sizeof(SERVICE_STATUS));
  806. if (fExtendedStatus) {
  807. //
  808. // Copy the PID and flags into the structure -- if the service
  809. // hasn't started yet (i.e., there's no ImageRecord), the the PID
  810. // and the flags will be 0
  811. //
  812. if (ServiceRecord->ImageRecord) {
  813. ServiceStatus.Ex->dwProcessId = ServiceRecord->ImageRecord->Pid;
  814. if (ServiceRecord->ImageRecord->ImageFlags & IS_SYSTEM_SERVICE) {
  815. ServiceStatus.Ex->dwServiceFlags |= SERVICE_RUNS_IN_SYSTEM_PROCESS;
  816. }
  817. }
  818. }
  819. }
  820. return NO_ERROR;
  821. }
  822. DWORD
  823. REnumDependentServicesW(
  824. IN SC_RPC_HANDLE hService,
  825. IN DWORD dwServiceState,
  826. OUT LPBYTE lpServices,
  827. IN DWORD cbBufSize,
  828. OUT LPDWORD pcbBytesNeeded,
  829. OUT LPDWORD lpServicesReturned
  830. )
  831. /*++
  832. Routine Description:
  833. This function enumerates the services which are dependent on the
  834. specified service. The list returned is an ordered list of services
  835. to be stopped before the specified service can be stopped. This
  836. list has to be ordered because there may be dependencies between
  837. the services that depend on the specified service.
  838. Arguments:
  839. dwServiceState - Value so select the services to enumerate based on the
  840. running state. It must be one or the bitwise OR of the following
  841. values:
  842. SERVICE_ACTIVE - enumerate services that have started.
  843. SERVICE_INACTIVE - enumerate services that are stopped.
  844. lpServices - A pointer to a buffer to receive an array of enum status
  845. (or service) entries.
  846. cbBufSize - Size of the buffer in bytes pointed to by lpBuffer.
  847. pcbBytesNeeded - A pointer to a location where the number of bytes
  848. left (to be enumerated) is to be placed. This indicates to the
  849. caller how large the buffer must be in order to complete the
  850. enumeration with the next call.
  851. lpServicesReturned - A pointer to a variable to receive the number of
  852. of service entries returned.
  853. Return Value:
  854. NO_ERROR - The operation was successful.
  855. ERROR_MORE_DATA - Not all of the data in the active database could be
  856. returned due to the size of the user's buffer. pcbBytesNeeded
  857. contains the number of bytes required to get the remaining
  858. entries.
  859. ERROR_INVALID_PARAMETER - An illegal parameter value was passed in
  860. for the service state.
  861. ERROR_INVALID_HANDLE - The specified handle was invalid.
  862. Note:
  863. It is expected that the RPC Stub functions will find the following
  864. parameter problems:
  865. Bad pointers for lpServices, pcbServicesReturned, and
  866. pcbBytesNeeded.
  867. --*/
  868. {
  869. DWORD status;
  870. LPSERVICE_RECORD Service;
  871. LPENUM_SERVICE_STATUS_WOW64 EnumRecord = (LPENUM_SERVICE_STATUS_WOW64) lpServices;
  872. LPWSTR EndOfVariableData;
  873. cbBufSize = ROUND_DOWN_COUNT(cbBufSize, ALIGN_WCHAR);
  874. EndOfVariableData = (LPWSTR) ((DWORD_PTR) EnumRecord + cbBufSize);
  875. SC_LOG(TRACE," Inside REnumDependentServicesW\n",0);
  876. if (ScShutdownInProgress)
  877. {
  878. return(ERROR_SHUTDOWN_IN_PROGRESS);
  879. }
  880. //
  881. // Check the handle.
  882. //
  883. if (!ScIsValidServiceHandle(hService))
  884. {
  885. return ERROR_INVALID_HANDLE;
  886. }
  887. Service = ((LPSC_HANDLE_STRUCT)hService)->Type.ScServiceObject.ServiceRecord;
  888. //
  889. // Service State is invalid if neither of the bit masks is set, or if any bit
  890. // outside of the bitmask range is set.
  891. //
  892. if (ENUM_STATE_MASK_INVALID(dwServiceState)) {
  893. return ERROR_INVALID_PARAMETER;
  894. }
  895. //
  896. // Was the handle opened with SERVICE_ENUMERATE_DEPENDENTS access?
  897. //
  898. if (! RtlAreAllAccessesGranted(
  899. ((LPSC_HANDLE_STRUCT)hService)->AccessGranted,
  900. SERVICE_ENUMERATE_DEPENDENTS
  901. )) {
  902. return ERROR_ACCESS_DENIED;
  903. }
  904. //
  905. // Initialize returned values
  906. //
  907. *lpServicesReturned = 0;
  908. *pcbBytesNeeded = 0;
  909. status = NO_ERROR;
  910. //
  911. // Get a shared (read) lock on the database so that it cannot be changed
  912. // while we're gathering up data.
  913. //
  914. {
  915. CServiceRecordSharedLock RLock;
  916. ScEnumDependents(
  917. Service,
  918. EnumRecord,
  919. dwServiceState,
  920. lpServicesReturned,
  921. pcbBytesNeeded,
  922. &EnumRecord,
  923. &EndOfVariableData,
  924. &status
  925. );
  926. }
  927. if (status == NO_ERROR)
  928. {
  929. *pcbBytesNeeded = 0;
  930. }
  931. return status;
  932. }
  933. VOID
  934. ScGetBootAndSystemDriverState(
  935. VOID
  936. )
  937. /*++
  938. Routine Description:
  939. This function is called once at service controller init time to get
  940. the latest state of boot and system drivers.
  941. Arguments:
  942. None.
  943. Return Value:
  944. None.
  945. --*/
  946. {
  947. DWORD status;
  948. CServiceListSharedLock LLock; // to avoid assertions
  949. //
  950. // ScGetDriverStatus assumes that the exclusive database lock is claimed.
  951. //
  952. CServiceRecordExclusiveLock RLock;
  953. FOR_ALL_SERVICES(Service)
  954. {
  955. if ((Service->StartType == SERVICE_BOOT_START ||
  956. Service->StartType == SERVICE_SYSTEM_START)
  957. &&
  958. (Service->ServiceStatus.dwServiceType == SERVICE_KERNEL_DRIVER ||
  959. Service->ServiceStatus.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER))
  960. {
  961. status = ScGetDriverStatus(
  962. Service,
  963. NULL
  964. );
  965. if (status == NO_ERROR)
  966. {
  967. if (Service->ServiceStatus.dwCurrentState == SERVICE_STOPPED
  968. &&
  969. ScInHardwareProfile(Service->ServiceName, CM_GETIDLIST_DONOTGENERATE))
  970. {
  971. Service->ServiceStatus.dwControlsAccepted = 0;
  972. Service->ServiceStatus.dwWin32ExitCode = ERROR_GEN_FAILURE;
  973. //
  974. // For popup after user has logged on to indicate that some
  975. // service started at boot has failed.
  976. //
  977. if (Service->ErrorControl == SERVICE_ERROR_NORMAL ||
  978. Service->ErrorControl == SERVICE_ERROR_SEVERE ||
  979. Service->ErrorControl == SERVICE_ERROR_CRITICAL)
  980. {
  981. (void) ScAddFailedDriver(Service->ServiceName);
  982. ScPopupStartFail = TRUE;
  983. }
  984. }
  985. }
  986. }
  987. }
  988. }