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.

5227 lines
135 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. scwrap.c
  5. Abstract:
  6. These are the Service Controller API RPC client wrapper routines.
  7. These are the entry points that are exported by the dll.
  8. ControlService
  9. EnumServicesStatusW
  10. EnumServicesStatusA
  11. EnumServicesStatusExW
  12. EnumServicesStatusExA
  13. EnumServiceGroupW
  14. OpenServiceW
  15. CloseServiceHandle
  16. OpenSCManagerW
  17. QueryServiceStatus
  18. QueryServiceStatusEx
  19. StartServiceW
  20. SetServiceStatus
  21. I_ScSetServiceBitsW
  22. I_ScSetServiceBitsA
  23. I_ScGetCurrentGroupStateW
  24. I_ScSendTSMessage
  25. SetServiceBits
  26. OpenSCManagerA
  27. OpenServiceA
  28. StartServiceA
  29. QueryServiceObjectSecurity
  30. SetServiceObjectSecurity
  31. ScConvertOffsetsW
  32. ScConvertOffsetsA
  33. ScConvertOffsetsExW
  34. ScConvertOffsetsExA
  35. ScConvertOffsets64
  36. ChangeServiceConfigA
  37. ChangeServiceConfigW
  38. ChangeServiceConfig2A
  39. ChangeServiceConfig2W
  40. CreateServiceA
  41. CreateServiceW
  42. DeleteService
  43. EnumDependentServicesA
  44. EnumDependentServicesW
  45. GetServiceDisplayNameA
  46. GetServiceDisplayNameW
  47. GetServiceKeyNameA
  48. GetServiceKeyNameW
  49. LockServiceDatabase
  50. QueryServiceConfigA
  51. QueryServiceConfigW
  52. QueryServiceConfig2A
  53. QueryServiceConfig2W
  54. QueryServiceLockStatusA
  55. QueryServiceLockStatusW
  56. UnlockServiceDatabase
  57. NotifyBootConfigStatus
  58. Author:
  59. Dan Lafferty (danl) 03-Feb-1992
  60. Environment:
  61. User Mode - Win32
  62. Revision History:
  63. 07-May-1998 jschwart
  64. Added QueryServiceStatusEx and EnumServicesStatusEx
  65. 11-Oct-1996 AnirudhS
  66. Added ChangeServiceConfig2 and QueryServiceConfig2.
  67. 14-Feb-1996 AnirudhS
  68. Added EnumServiceGroupW.
  69. 22-Sep-1995 AnirudhS
  70. ScWaitForStart: Fixed race condition - OpenEvent needs to be tried
  71. a second time after CreateEvent.
  72. 15-Aug-1995 AnirudhS
  73. Added I_ScGetCurrentGroupStateW.
  74. 05-Nov-1992 Danl
  75. Added display name changes (CreateService, ChangeServiceConfig) and
  76. new api (GetServiceDisplayName, GetServiceKeyName).
  77. 13-Oct-1992 Danl
  78. Allow 0 length buffers to be passed into EnumServicesStatus and
  79. EnumDependentServices.
  80. 04-Aug-1992 Danl
  81. Allow 0 length buffers to be passed into QueryServiceConfig and
  82. QueryServiceLockStatus.
  83. 28-May-1992 JohnRo
  84. RAID 9829: winsvc.h and related file cleanup.
  85. 14-Apr-1992 JohnRo
  86. Enable Lock and Unlock APIs.
  87. 03-Feb-1992 Danl
  88. Created
  89. --*/
  90. //
  91. // INCLUDES
  92. //
  93. extern "C"
  94. {
  95. #include <nt.h> // DbgPrint prototype
  96. #include <ntrtl.h> // DbgPrint prototype
  97. #include <nturtl.h> // needed when we include windows.h
  98. }
  99. #include <rpc.h> // DataTypes and runtime APIs
  100. #include <windows.h> // NO_ERROR
  101. #include <svcctl.h> // generated by the MIDL compiler
  102. #include <lmcons.h> // for lmserver.h
  103. #include <srvann.h> // MS-internal functions
  104. #include <winsvcp.h> // MS-internal functions
  105. #include <rpcasync.h> // I_RpcExceptionFilter
  106. #include <string.h> // needed by strarray.h
  107. #include <scdebug.h> // SCC_LOG
  108. #include <sccrypt.h> // ScEncryptPassword
  109. #include <sclib.h> // ScConvertToUnicode
  110. #include <strarray.h> // ScWStrArraySize
  111. #include <lmerr.h> // for lmserver.h
  112. #include <lmserver.h> // SV_TYPE_WORKSTATION ...
  113. #include <scseclib.h> // ScCreateStartEventSD
  114. #include <scwow.h> // 32/64-bit interop structures
  115. //
  116. // DEFINES
  117. //
  118. #define SC_START_TIMEOUT 180000 // 3 minute timeout
  119. #define RESERVED_BITS (SV_TYPE_WORKSTATION | \
  120. SV_TYPE_SERVER | \
  121. SV_TYPE_DOMAIN_CTRL | \
  122. SV_TYPE_DOMAIN_BAKCTRL | \
  123. SV_TYPE_TIME_SOURCE | \
  124. SV_TYPE_AFP | \
  125. SV_TYPE_DOMAIN_MEMBER | \
  126. SV_TYPE_PRINTQ_SERVER | \
  127. SV_TYPE_DIALIN_SERVER | \
  128. SV_TYPE_XENIX_SERVER | \
  129. SV_TYPE_SERVER_UNIX | \
  130. SV_TYPE_NT | \
  131. SV_TYPE_WFW | \
  132. SV_TYPE_POTENTIAL_BROWSER | \
  133. SV_TYPE_BACKUP_BROWSER | \
  134. SV_TYPE_MASTER_BROWSER | \
  135. SV_TYPE_DOMAIN_MASTER | \
  136. SV_TYPE_LOCAL_LIST_ONLY | \
  137. SV_TYPE_DOMAIN_ENUM)
  138. //
  139. // LOCAL FUNCTIONS
  140. //
  141. VOID
  142. ScConvertOffsetsW(
  143. LPENUM_SERVICE_STATUSW lpServices,
  144. DWORD NumStructs
  145. );
  146. VOID
  147. ScConvertOffsetsA(
  148. LPENUM_SERVICE_STATUSA lpServices,
  149. DWORD NumStructs
  150. );
  151. VOID
  152. ScConvertOffsetsExW(
  153. LPENUM_SERVICE_STATUS_PROCESSW lpServices,
  154. DWORD NumStructs
  155. );
  156. VOID
  157. ScConvertOffsetsExA(
  158. LPENUM_SERVICE_STATUS_PROCESSA lpServices,
  159. DWORD NumStructs
  160. );
  161. #ifdef _WIN64
  162. //
  163. // API numbers for ScConvertOffsets64
  164. //
  165. typedef enum
  166. {
  167. SC_API_ENUM_W = 0,
  168. SC_API_ENUM_A,
  169. SC_API_ENUM_GROUP,
  170. SC_API_ENUM_DEPEND_W,
  171. SC_API_ENUM_DEPEND_A,
  172. SC_API_ENUM_PROCESS_W,
  173. SC_API_ENUM_PROCESS_A,
  174. SC_API_QUERY_DESCRIPTION_W,
  175. SC_API_QUERY_DESCRIPTION_A,
  176. SC_API_QUERY_FAILURE_ACTIONS_W,
  177. SC_API_QUERY_FAILURE_ACTIONS_A,
  178. SC_API_MAX
  179. }
  180. SC_API_NUMBER;
  181. BOOL
  182. ScConvertOffsets64(
  183. SC_API_NUMBER scApi,
  184. SC_HANDLE hSCManager,
  185. DWORD dwServiceType,
  186. DWORD dwServiceState,
  187. LPBYTE lpServices,
  188. DWORD cbBufSize,
  189. LPDWORD pcbBytesNeeded,
  190. LPDWORD lpServicesReturned,
  191. LPDWORD lpResumeIndex,
  192. LPVOID pszGroupName,
  193. LPDWORD lpdwError
  194. );
  195. #endif // _WIN64
  196. DWORD
  197. ScMapRpcError(
  198. IN DWORD RpcError,
  199. IN DWORD BadContextError
  200. );
  201. DWORD
  202. ScWaitForStart(
  203. VOID
  204. );
  205. DWORD
  206. ScRemoveDispatchEntry(
  207. IN SC_HANDLE hStatusHandle
  208. );
  209. //
  210. // Globals
  211. //
  212. extern "C"
  213. {
  214. void
  215. SccInit(
  216. DWORD dwReason
  217. )
  218. {
  219. return;
  220. }
  221. }
  222. BOOL
  223. WINAPI
  224. ControlService(
  225. IN SC_HANDLE hService,
  226. IN DWORD dwControl,
  227. OUT LPSERVICE_STATUS lpServiceStatus
  228. )
  229. /*++
  230. Routine Description:
  231. This is the DLL entrypoint for Control Service
  232. Arguments:
  233. Return Value:
  234. --*/
  235. {
  236. DWORD status;
  237. RpcTryExcept {
  238. status = RControlService (
  239. (SC_RPC_HANDLE)hService,
  240. dwControl,
  241. lpServiceStatus);
  242. }
  243. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  244. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  245. }
  246. RpcEndExcept
  247. if (status != NO_ERROR){
  248. SetLastError(status);
  249. return(FALSE);
  250. }
  251. return(TRUE);
  252. }
  253. BOOL
  254. WINAPI
  255. EnumServicesStatusW(
  256. IN SC_HANDLE hSCManager,
  257. IN DWORD dwServiceType,
  258. IN DWORD dwServiceState,
  259. OUT LPENUM_SERVICE_STATUSW lpServices,
  260. IN DWORD cbBufSize,
  261. OUT LPDWORD pcbBytesNeeded,
  262. OUT LPDWORD lpServicesReturned,
  263. IN OUT LPDWORD lpResumeIndex
  264. )
  265. /*++
  266. Routine Description:
  267. This is the DLL entrypoint for EnumServicesStatusW
  268. Arguments:
  269. Return Value:
  270. Note:
  271. --*/
  272. {
  273. return EnumServiceGroupW(
  274. hSCManager,
  275. dwServiceType,
  276. dwServiceState,
  277. lpServices,
  278. cbBufSize,
  279. pcbBytesNeeded,
  280. lpServicesReturned,
  281. lpResumeIndex,
  282. NULL);
  283. }
  284. BOOL
  285. WINAPI
  286. EnumServicesStatusExW(
  287. IN SC_HANDLE hSCManager,
  288. IN SC_ENUM_TYPE InfoLevel,
  289. IN DWORD dwServiceType,
  290. IN DWORD dwServiceState,
  291. OUT LPBYTE lpServices,
  292. IN DWORD cbBufSize,
  293. OUT LPDWORD pcbBytesNeeded,
  294. OUT LPDWORD lpServicesReturned,
  295. IN OUT LPDWORD lpResumeIndex,
  296. IN LPCWSTR pszGroupName
  297. )
  298. /*++
  299. Routine Description:
  300. This is the DLL entrypoint for EnumServicesStatusExW
  301. Arguments:
  302. Return Value:
  303. Note:
  304. --*/
  305. {
  306. DWORD status;
  307. LPENUM_SERVICE_STATUS_PROCESSW pEnumBuf;
  308. ENUM_SERVICE_STATUS_PROCESSW enumBuf;
  309. DWORD tempBufSize;
  310. #ifdef _WIN64
  311. DWORD dwOldResumeIndex = 0;
  312. if (lpResumeIndex != NULL)
  313. {
  314. dwOldResumeIndex = *lpResumeIndex;
  315. }
  316. #endif // _WIN64
  317. //
  318. // Make sure we were passed a valid InfoLevel
  319. //
  320. if (InfoLevel != SC_ENUM_PROCESS_INFO)
  321. {
  322. SetLastError(ERROR_INVALID_LEVEL);
  323. return FALSE;
  324. }
  325. tempBufSize = cbBufSize;
  326. //
  327. // Create a dummy buffer that is at least the size of the structure.
  328. // This way RPC should at least send the request to the server side.
  329. // The server should recognize that the buffer is to small for any
  330. // strings, and put the correct size in the BytesNeeded parameter,
  331. // and fail the call.
  332. //
  333. if (cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSW) || (lpServices == NULL)) {
  334. pEnumBuf = &enumBuf;
  335. tempBufSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW);
  336. }
  337. else {
  338. pEnumBuf = (LPENUM_SERVICE_STATUS_PROCESSW)lpServices;
  339. }
  340. RpcTryExcept {
  341. status = REnumServicesStatusExW (
  342. hSCManager,
  343. InfoLevel,
  344. dwServiceType,
  345. dwServiceState,
  346. (LPBYTE)pEnumBuf,
  347. tempBufSize,
  348. pcbBytesNeeded,
  349. lpServicesReturned,
  350. lpResumeIndex,
  351. pszGroupName);
  352. }
  353. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  354. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  355. }
  356. RpcEndExcept
  357. //
  358. // If data is returned, convert Offsets in the Enum buffer to pointers.
  359. //
  360. if ((status == NO_ERROR) || (status == ERROR_MORE_DATA))
  361. {
  362. if ((*lpServicesReturned) > 0)
  363. {
  364. #ifdef _WIN64
  365. DWORD dwError;
  366. if (!ScConvertOffsets64(SC_API_ENUM_PROCESS_W,
  367. hSCManager,
  368. dwServiceType,
  369. dwServiceState,
  370. (LPBYTE) lpServices,
  371. cbBufSize,
  372. pcbBytesNeeded,
  373. lpServicesReturned,
  374. &dwOldResumeIndex,
  375. (LPVOID) pszGroupName,
  376. &dwError))
  377. {
  378. status = dwError;
  379. if (lpResumeIndex != NULL)
  380. {
  381. *lpResumeIndex = dwOldResumeIndex;
  382. }
  383. }
  384. #else // ndef _WIN64
  385. ScConvertOffsetsExW((LPENUM_SERVICE_STATUS_PROCESSW) lpServices,
  386. *lpServicesReturned);
  387. #endif // _WIN64
  388. }
  389. #ifdef _WIN64
  390. //
  391. // The byte count returned is the size needed to hold all of
  392. // the 32-bit structures rather than the 64-bit ones. Assume
  393. // a buffer full of fixed-length structures (i.e., no variable-
  394. // length data) and scale from 32- to 64-bit sizes to get the
  395. // minimum guaranteed size for all the 64-bit structures.
  396. //
  397. *pcbBytesNeeded = *pcbBytesNeeded
  398. * sizeof(ENUM_SERVICE_STATUS_PROCESSW)
  399. / sizeof(ENUM_SERVICE_STATUS_PROCESS_WOW64);
  400. #endif // _WIN64
  401. }
  402. if (status != NO_ERROR)
  403. {
  404. SetLastError(status);
  405. return FALSE;
  406. }
  407. return TRUE;
  408. }
  409. BOOL
  410. WINAPI
  411. EnumServiceGroupW(
  412. IN SC_HANDLE hSCManager,
  413. IN DWORD dwServiceType,
  414. IN DWORD dwServiceState,
  415. OUT LPENUM_SERVICE_STATUSW lpServices,
  416. IN DWORD cbBufSize,
  417. OUT LPDWORD pcbBytesNeeded,
  418. OUT LPDWORD lpServicesReturned,
  419. IN OUT LPDWORD lpResumeIndex,
  420. IN LPCWSTR pszGroupName
  421. )
  422. /*++
  423. Routine Description:
  424. This is the DLL entrypoint for EnumServiceGroupW
  425. Arguments:
  426. Return Value:
  427. Note:
  428. --*/
  429. {
  430. DWORD status;
  431. LPENUM_SERVICE_STATUSW pEnumBuf;
  432. ENUM_SERVICE_STATUSW enumBuf;
  433. DWORD tempBufSize;
  434. #ifdef _WIN64
  435. DWORD dwOldResumeIndex = 0;
  436. if (lpResumeIndex != NULL)
  437. {
  438. dwOldResumeIndex = *lpResumeIndex;
  439. }
  440. #endif // _WIN64
  441. tempBufSize = cbBufSize;
  442. //
  443. // Create a dummy buffer that is at least the size of the structure.
  444. // This way RPC should at least send the request to the server side.
  445. // The server should recognize that the buffer is to small for any
  446. // strings, and put the correct size in the BytesNeeded parameter,
  447. // and fail the call.
  448. //
  449. if (cbBufSize < sizeof(ENUM_SERVICE_STATUSW) || (lpServices == NULL)) {
  450. pEnumBuf = &enumBuf;
  451. tempBufSize = sizeof(ENUM_SERVICE_STATUSW);
  452. }
  453. else {
  454. pEnumBuf = lpServices;
  455. }
  456. RpcTryExcept {
  457. if (pszGroupName == NULL) {
  458. //
  459. // Call the downlevel API, so that the call will work on targeted
  460. // machines running Windows NT 3.51 or earlier
  461. //
  462. status = REnumServicesStatusW (
  463. (SC_RPC_HANDLE)hSCManager,
  464. dwServiceType,
  465. dwServiceState,
  466. (LPBYTE)pEnumBuf,
  467. tempBufSize,
  468. pcbBytesNeeded,
  469. lpServicesReturned,
  470. lpResumeIndex);
  471. }
  472. else {
  473. status = REnumServiceGroupW (
  474. (SC_RPC_HANDLE)hSCManager,
  475. dwServiceType,
  476. dwServiceState,
  477. (LPBYTE)pEnumBuf,
  478. tempBufSize,
  479. pcbBytesNeeded,
  480. lpServicesReturned,
  481. lpResumeIndex,
  482. pszGroupName);
  483. }
  484. }
  485. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  486. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  487. }
  488. RpcEndExcept
  489. //
  490. // If data is returned, convert Offsets in the Enum buffer to pointers.
  491. //
  492. if ((status == NO_ERROR) || (status == ERROR_MORE_DATA))
  493. {
  494. if ((*lpServicesReturned) > 0)
  495. {
  496. #ifdef _WIN64
  497. DWORD dwError;
  498. if (!ScConvertOffsets64(pszGroupName ? SC_API_ENUM_GROUP :
  499. SC_API_ENUM_W,
  500. hSCManager,
  501. dwServiceType,
  502. dwServiceState,
  503. (LPBYTE) lpServices,
  504. cbBufSize,
  505. pcbBytesNeeded,
  506. lpServicesReturned,
  507. &dwOldResumeIndex,
  508. (LPVOID) pszGroupName,
  509. &dwError))
  510. {
  511. status = dwError;
  512. if (lpResumeIndex != NULL)
  513. {
  514. *lpResumeIndex = dwOldResumeIndex;
  515. }
  516. }
  517. #else // ndef _WIN64
  518. ScConvertOffsetsW(lpServices, *lpServicesReturned);
  519. #endif // _WIN64
  520. }
  521. #ifdef _WIN64
  522. //
  523. // The byte count returned is the size needed to hold all of
  524. // the 32-bit structures rather than the 64-bit ones. Assume
  525. // a buffer full of fixed-length structures (i.e., no variable-
  526. // length data) and scale from 32- to 64-bit sizes to get the
  527. // minimum guaranteed size for all the 64-bit structures.
  528. //
  529. *pcbBytesNeeded = *pcbBytesNeeded
  530. * sizeof(ENUM_SERVICE_STATUSW)
  531. / sizeof(ENUM_SERVICE_STATUS_WOW64);
  532. #endif // _WIN64
  533. }
  534. if (status != NO_ERROR)
  535. {
  536. SetLastError(status);
  537. return(FALSE);
  538. }
  539. return(TRUE);
  540. }
  541. SC_HANDLE
  542. WINAPI
  543. OpenServiceW(
  544. IN SC_HANDLE hSCManager,
  545. IN LPCWSTR lpServiceName,
  546. IN DWORD dwDesiredAccess
  547. )
  548. /*++
  549. Routine Description:
  550. Arguments:
  551. Return Value:
  552. --*/
  553. {
  554. DWORD status;
  555. SC_RPC_HANDLE hService=NULL;
  556. RpcTryExcept {
  557. status = ROpenServiceW (
  558. (SC_RPC_HANDLE)hSCManager,
  559. (LPWSTR) lpServiceName,
  560. dwDesiredAccess,
  561. &hService);
  562. }
  563. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  564. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  565. }
  566. RpcEndExcept
  567. if (status != NO_ERROR){
  568. SetLastError(status);
  569. return(NULL);
  570. }
  571. return (SC_HANDLE)hService;
  572. }
  573. BOOL
  574. WINAPI
  575. CloseServiceHandle(
  576. IN SC_HANDLE hSCObject
  577. )
  578. /*++
  579. Routine Description:
  580. Arguments:
  581. Return Value:
  582. --*/
  583. {
  584. DWORD status;
  585. RpcTryExcept {
  586. status = RCloseServiceHandle((LPSC_RPC_HANDLE)&hSCObject);
  587. }
  588. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  589. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  590. }
  591. RpcEndExcept
  592. if (status != NO_ERROR){
  593. SetLastError(status);
  594. return(FALSE);
  595. }
  596. return(TRUE);
  597. }
  598. SC_HANDLE
  599. WINAPI
  600. OpenSCManagerW(
  601. IN LPCWSTR lpMachineName,
  602. IN LPCWSTR lpDatabaseName OPTIONAL,
  603. IN DWORD dwDesiredAccess
  604. )
  605. /*++
  606. Routine Description:
  607. Arguments:
  608. Return Value:
  609. --*/
  610. {
  611. DWORD status;
  612. SC_RPC_HANDLE ScHandle=NULL;
  613. //
  614. // Check to see if the local Service Controller is started yet.
  615. // If not, then wait for it to start (or timeout).
  616. //
  617. status = ScWaitForStart();
  618. if (status != NO_ERROR) {
  619. SetLastError(status);
  620. return(NULL);
  621. }
  622. RpcTryExcept {
  623. status = ROpenSCManagerW (
  624. (LPWSTR) lpMachineName,
  625. (LPWSTR) lpDatabaseName,
  626. dwDesiredAccess,
  627. &ScHandle);
  628. }
  629. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  630. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  631. }
  632. RpcEndExcept
  633. if (status != NO_ERROR){
  634. SetLastError(status);
  635. return(NULL);
  636. }
  637. return (SC_HANDLE)ScHandle;
  638. }
  639. BOOL
  640. WINAPI
  641. QueryServiceStatus(
  642. IN SC_HANDLE hService,
  643. OUT LPSERVICE_STATUS lpServiceStatus
  644. )
  645. /*++
  646. Routine Description:
  647. This is the DLL entrypoint for QueryServiceStatus.
  648. Arguments:
  649. Return Value:
  650. --*/
  651. {
  652. DWORD status;
  653. RpcTryExcept {
  654. status = RQueryServiceStatus (
  655. (SC_RPC_HANDLE)hService,
  656. lpServiceStatus);
  657. }
  658. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  659. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  660. }
  661. RpcEndExcept
  662. if (status != NO_ERROR){
  663. SetLastError(status);
  664. return(FALSE);
  665. }
  666. return(TRUE);
  667. }
  668. BOOL
  669. WINAPI
  670. QueryServiceStatusEx(
  671. IN SC_HANDLE hService,
  672. IN SC_STATUS_TYPE InfoLevel,
  673. OUT LPBYTE lpBuffer,
  674. IN DWORD cbBufSize,
  675. OUT LPDWORD pcbBytesNeeded
  676. )
  677. /*++
  678. Routine Description:
  679. This is the DLL entrypoint for QueryServiceStatusEx.
  680. Arguments:
  681. Return Value:
  682. Note:
  683. --*/
  684. {
  685. DWORD status;
  686. switch (InfoLevel) {
  687. case SC_STATUS_PROCESS_INFO:
  688. if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS)) {
  689. //
  690. // The buffer is too small -- since the structure is a fixed
  691. // size, we can handle this error on the client side
  692. //
  693. *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
  694. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  695. return FALSE;
  696. }
  697. break;
  698. default:
  699. SetLastError(ERROR_INVALID_LEVEL);
  700. return FALSE;
  701. }
  702. RpcTryExcept {
  703. status = RQueryServiceStatusEx (
  704. (SC_RPC_HANDLE)hService,
  705. InfoLevel,
  706. lpBuffer,
  707. cbBufSize,
  708. pcbBytesNeeded);
  709. }
  710. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  711. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  712. }
  713. RpcEndExcept
  714. if (status != NO_ERROR) {
  715. SetLastError(status);
  716. return FALSE;
  717. }
  718. return TRUE;
  719. }
  720. BOOL
  721. WINAPI
  722. StartServiceW(
  723. IN SC_HANDLE hService,
  724. IN DWORD dwNumServiceArgs,
  725. IN LPCWSTR *lpServiceArgVectors
  726. )
  727. /*++
  728. Routine Description:
  729. This is the DLL entrypoint for StartServiceW
  730. Arguments:
  731. servername - Points to a string containing the name of the computer
  732. that is to execute the API function.
  733. service- Points to a string containing the name of the service
  734. that is to be started.
  735. argc - Indicates the number or argument vectors in argv.
  736. argv - A pointer to an array of pointers to strings. These
  737. are command line arguments that are to be passed to the service.
  738. bufptr - This is the address where a pointer to the service's
  739. information buffer (SERVICE_INFO_2) is to be placed.
  740. Return Value:
  741. --*/
  742. {
  743. DWORD status;
  744. RpcTryExcept {
  745. status = RStartServiceW (
  746. (SC_RPC_HANDLE)hService,
  747. dwNumServiceArgs,
  748. (LPSTRING_PTRSW)lpServiceArgVectors);
  749. }
  750. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  751. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  752. }
  753. RpcEndExcept
  754. if (status != NO_ERROR){
  755. SetLastError(status);
  756. return(FALSE);
  757. }
  758. return(TRUE);
  759. }
  760. BOOL
  761. WINAPI
  762. SetServiceStatus(
  763. IN SERVICE_STATUS_HANDLE hServiceStatus,
  764. IN LPSERVICE_STATUS lpServiceStatus
  765. )
  766. /*++
  767. Routine Description:
  768. This is the DLL entrypoint for SetServiceStatus. It is called from
  769. a service when that service changes its state or receives a control.
  770. The status is maintained by the service controller.
  771. Arguments:
  772. hServiceStatus - This is a handle that was obtained from calling
  773. the RegisterControlHandler function.
  774. lpServiceStatus - This is a pointer to a service status structure.
  775. Return Value:
  776. --*/
  777. {
  778. DWORD status;
  779. //
  780. // Do the RPC call with an exception handler since RPC will raise an
  781. // exception if anything fails. It is up to us to figure out what
  782. // to do once the exception is raised.
  783. //
  784. RpcTryExcept {
  785. status = RSetServiceStatus (
  786. (SC_HANDLE)hServiceStatus,
  787. lpServiceStatus);
  788. }
  789. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  790. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  791. }
  792. RpcEndExcept
  793. if (status != NO_ERROR){
  794. SetLastError(status);
  795. return(FALSE);
  796. }
  797. if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED) {
  798. //
  799. // Service is stopping -- close the handle we opened
  800. // in StartServiceCtrlDispatcher when the service started
  801. //
  802. ScRemoveDispatchEntry((SC_HANDLE) hServiceStatus);
  803. CloseServiceHandle((SC_HANDLE) hServiceStatus);
  804. }
  805. return(TRUE);
  806. }
  807. BOOL
  808. I_ScSetServiceBitsA(
  809. IN SERVICE_STATUS_HANDLE hServiceStatus,
  810. IN DWORD dwServiceBits,
  811. IN BOOL bSetBitsOn,
  812. IN BOOL bUpdateImmediately,
  813. IN LPSTR pszTransportName
  814. )
  815. /*++
  816. Routine Description:
  817. This is an internal routine that sets the Server Announcement bits
  818. in the service controller.
  819. Arguments:
  820. hServiceStatus -
  821. dwServiceBits -
  822. Return Value:
  823. Note:
  824. --*/
  825. {
  826. SetLastError(ERROR_NOT_SUPPORTED);
  827. return FALSE;
  828. }
  829. BOOL
  830. I_ScSetServiceBitsW(
  831. IN SERVICE_STATUS_HANDLE hServiceStatus,
  832. IN DWORD dwServiceBits,
  833. IN BOOL bSetBitsOn,
  834. IN BOOL bUpdateImmediately,
  835. IN LPWSTR pszTransportName
  836. )
  837. /*++
  838. Routine Description:
  839. This is an internal routine that sets the Server Announcement bits
  840. in the service controller.
  841. Arguments:
  842. hServiceStatus -
  843. dwServiceBits -
  844. Return Value:
  845. Note:
  846. --*/
  847. {
  848. DWORD status;
  849. DWORD setBitsOnFlag=0;
  850. DWORD updateImmediatelyFlag=0;
  851. if(bSetBitsOn) {
  852. setBitsOnFlag = 1;
  853. }
  854. if(bUpdateImmediately) {
  855. updateImmediatelyFlag = 1;
  856. }
  857. //
  858. // Do the RPC call with an exception handler since RPC will raise an
  859. // exception if anything fails. It is up to us to figure out what
  860. // to do once the exception is raised.
  861. //
  862. RpcTryExcept {
  863. status = RI_ScSetServiceBitsW (
  864. (SC_HANDLE)hServiceStatus,
  865. dwServiceBits,
  866. setBitsOnFlag,
  867. updateImmediatelyFlag,
  868. pszTransportName);
  869. }
  870. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  871. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  872. }
  873. RpcEndExcept
  874. if (status != NO_ERROR){
  875. SetLastError(status);
  876. return(FALSE);
  877. }
  878. return(TRUE);
  879. }
  880. DWORD
  881. I_ScGetCurrentGroupStateW(
  882. IN SC_HANDLE hSCManager,
  883. IN LPWSTR pszGroupName,
  884. OUT LPDWORD pdwCurrentState
  885. )
  886. /*++
  887. Routine Description:
  888. This is obsolete but some (MS) apps still statically link to it.
  889. --*/
  890. {
  891. return ERROR_NOT_SUPPORTED;
  892. }
  893. extern "C" {
  894. DWORD
  895. I_ScSendTSMessage(
  896. DWORD OpCode,
  897. DWORD dwEvent,
  898. DWORD cbData,
  899. LPBYTE lpData
  900. )
  901. /*++
  902. Routine Description:
  903. Private entrypoint for Terminal Server to tell the SCM to send
  904. console switch notification to services that are interested.
  905. --*/
  906. {
  907. DWORD status;
  908. SC_HANDLE hSCManager;
  909. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  910. if (hSCManager == NULL)
  911. {
  912. return GetLastError();
  913. }
  914. //
  915. // Do the RPC call with an exception handler since RPC will raise an
  916. // exception if anything fails. It is up to us to figure out what
  917. // to do once the exception is raised.
  918. //
  919. RpcTryExcept
  920. {
  921. status = RI_ScSendTSMessage(hSCManager,
  922. OpCode,
  923. dwEvent,
  924. cbData,
  925. lpData);
  926. }
  927. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  928. {
  929. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  930. }
  931. RpcEndExcept
  932. CloseServiceHandle(hSCManager);
  933. return status;
  934. }
  935. } // extern "C"
  936. BOOL
  937. NET_API_FUNCTION
  938. SetServiceBits(
  939. IN SERVICE_STATUS_HANDLE hServiceStatus,
  940. IN DWORD dwServiceBits,
  941. IN BOOL bSetBitsOn,
  942. IN BOOL bUpdateImmediately
  943. )
  944. /*++
  945. Routine Description:
  946. This is an internal routine that sets the Server Announcement bits
  947. in the service controller.
  948. Arguments:
  949. hServiceStatus -
  950. dwServiceBits -
  951. Return Value:
  952. Note:
  953. --*/
  954. {
  955. if (dwServiceBits & RESERVED_BITS) {
  956. SetLastError(ERROR_INVALID_DATA);
  957. return(FALSE);
  958. }
  959. return(I_ScSetServiceBitsW(
  960. hServiceStatus,
  961. dwServiceBits,
  962. bSetBitsOn,
  963. bUpdateImmediately,
  964. (LPWSTR)NULL));
  965. }
  966. SC_HANDLE
  967. WINAPI
  968. OpenSCManagerA(
  969. IN LPCSTR lpMachineName,
  970. IN LPCSTR lpDatabaseName OPTIONAL,
  971. IN DWORD dwDesiredAccess
  972. )
  973. /*++
  974. Routine Description:
  975. Arguments:
  976. Return Value:
  977. --*/
  978. {
  979. DWORD status;
  980. SC_RPC_HANDLE ScHandle=NULL;
  981. //
  982. // Check to see if the local Service Controller is started yet.
  983. // If not, then wait for it to start (or timeout).
  984. //
  985. status = ScWaitForStart();
  986. if (status != NO_ERROR) {
  987. SetLastError(status);
  988. return(NULL);
  989. };
  990. RpcTryExcept {
  991. status = ROpenSCManagerA (
  992. (LPSTR) lpMachineName,
  993. (LPSTR) lpDatabaseName,
  994. dwDesiredAccess,
  995. &ScHandle);
  996. }
  997. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  998. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  999. }
  1000. RpcEndExcept
  1001. if (status != NO_ERROR){
  1002. SetLastError(status);
  1003. return(NULL);
  1004. }
  1005. return (SC_HANDLE)ScHandle;
  1006. }
  1007. SC_HANDLE
  1008. WINAPI
  1009. OpenServiceA(
  1010. IN SC_HANDLE hSCManager,
  1011. IN LPCSTR lpServiceName,
  1012. IN DWORD dwDesiredAccess
  1013. )
  1014. /*++
  1015. Routine Description:
  1016. Arguments:
  1017. Return Value:
  1018. --*/
  1019. {
  1020. DWORD status;
  1021. SC_RPC_HANDLE hService=NULL;
  1022. RpcTryExcept {
  1023. status = ROpenServiceA (
  1024. (SC_RPC_HANDLE)hSCManager,
  1025. (LPSTR) lpServiceName,
  1026. dwDesiredAccess,
  1027. &hService);
  1028. }
  1029. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1030. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  1031. }
  1032. RpcEndExcept
  1033. if (status != NO_ERROR){
  1034. SetLastError(status);
  1035. return(NULL);
  1036. }
  1037. return (SC_HANDLE)hService;
  1038. }
  1039. BOOL
  1040. WINAPI
  1041. StartServiceA(
  1042. IN SC_HANDLE hService,
  1043. IN DWORD dwNumServiceArgs,
  1044. IN LPCSTR *lpServiceArgVectors
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. Arguments:
  1049. servername - Points to a string containing the name of the computer
  1050. that is to execute the API function.
  1051. service- Points to a string containing the name of the service
  1052. that is to be started.
  1053. argc - Indicates the number or argument vectors in argv.
  1054. argv - A pointer to an array of pointers to strings. These
  1055. are command line arguments that are to be passed to the service.
  1056. bufptr - This is the address where a pointer to the service's
  1057. information buffer (SERVICE_INFO_2) is to be placed.
  1058. Return Value:
  1059. --*/
  1060. {
  1061. DWORD status;
  1062. RpcTryExcept {
  1063. status = RStartServiceA (
  1064. (SC_RPC_HANDLE)hService,
  1065. dwNumServiceArgs,
  1066. (LPSTRING_PTRSA)lpServiceArgVectors);
  1067. }
  1068. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1069. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  1070. }
  1071. RpcEndExcept
  1072. if (status != NO_ERROR){
  1073. SetLastError(status);
  1074. return(FALSE);
  1075. }
  1076. return(TRUE);
  1077. }
  1078. BOOL
  1079. WINAPI
  1080. EnumServicesStatusA(
  1081. IN SC_HANDLE hSCManager,
  1082. IN DWORD dwServiceType,
  1083. IN DWORD dwServiceState,
  1084. OUT LPENUM_SERVICE_STATUSA lpServices,
  1085. IN DWORD cbBufSize,
  1086. OUT LPDWORD pcbBytesNeeded,
  1087. OUT LPDWORD lpServicesReturned,
  1088. IN OUT LPDWORD lpResumeIndex
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. Arguments:
  1093. Return Value:
  1094. --*/
  1095. {
  1096. DWORD status;
  1097. LPENUM_SERVICE_STATUSA pEnumBuf;
  1098. ENUM_SERVICE_STATUSA enumBuf;
  1099. DWORD tempBufSize;
  1100. #ifdef _WIN64
  1101. DWORD dwOldResumeIndex = 0;
  1102. if (lpResumeIndex != NULL)
  1103. {
  1104. dwOldResumeIndex = *lpResumeIndex;
  1105. }
  1106. #endif // _WIN64
  1107. tempBufSize = cbBufSize;
  1108. //
  1109. // Create a dummy buffer that is at least the size of the structure.
  1110. // This way RPC should at least send the request to the server side.
  1111. // The server should recognize that the buffer is to small for any
  1112. // strings, and put the correct size in the BytesNeeded parameter,
  1113. // and fail the call.
  1114. //
  1115. if (cbBufSize < sizeof(ENUM_SERVICE_STATUSA) || (lpServices == NULL)) {
  1116. pEnumBuf = &enumBuf;
  1117. tempBufSize = sizeof(ENUM_SERVICE_STATUSA);
  1118. }
  1119. else {
  1120. pEnumBuf = lpServices;
  1121. }
  1122. RpcTryExcept {
  1123. status = REnumServicesStatusA (
  1124. (SC_RPC_HANDLE)hSCManager,
  1125. dwServiceType,
  1126. dwServiceState,
  1127. (LPBYTE)pEnumBuf,
  1128. tempBufSize,
  1129. pcbBytesNeeded,
  1130. lpServicesReturned,
  1131. lpResumeIndex);
  1132. }
  1133. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1134. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  1135. }
  1136. RpcEndExcept
  1137. //
  1138. // If data is returned, convert Offsets in the Enum buffer to pointers.
  1139. //
  1140. if ((status == NO_ERROR) || (status == ERROR_MORE_DATA))
  1141. {
  1142. if ((*lpServicesReturned) > 0)
  1143. {
  1144. #ifdef _WIN64
  1145. DWORD dwError;
  1146. if (!ScConvertOffsets64(SC_API_ENUM_A,
  1147. hSCManager,
  1148. dwServiceType,
  1149. dwServiceState,
  1150. (LPBYTE) lpServices,
  1151. cbBufSize,
  1152. pcbBytesNeeded,
  1153. lpServicesReturned,
  1154. &dwOldResumeIndex,
  1155. NULL,
  1156. &dwError))
  1157. {
  1158. status = dwError;
  1159. if (lpResumeIndex != NULL)
  1160. {
  1161. *lpResumeIndex = dwOldResumeIndex;
  1162. }
  1163. }
  1164. #else // ndef _WIN64
  1165. ScConvertOffsetsA(lpServices, *lpServicesReturned);
  1166. #endif // _WIN64
  1167. }
  1168. #ifdef _WIN64
  1169. //
  1170. // The byte count returned is the size needed to hold all of
  1171. // the 32-bit structures rather than the 64-bit ones. Assume
  1172. // a buffer full of fixed-length structures (i.e., no variable-
  1173. // length data) and scale from 32- to 64-bit sizes to get the
  1174. // minimum guaranteed size for all the 64-bit structures.
  1175. //
  1176. *pcbBytesNeeded = *pcbBytesNeeded
  1177. * sizeof(ENUM_SERVICE_STATUSA)
  1178. / sizeof(ENUM_SERVICE_STATUS_WOW64);
  1179. #endif // _WIN64
  1180. }
  1181. if (status != NO_ERROR)
  1182. {
  1183. SetLastError(status);
  1184. return(FALSE);
  1185. }
  1186. return(TRUE);
  1187. }
  1188. BOOL
  1189. WINAPI
  1190. EnumServicesStatusExA(
  1191. IN SC_HANDLE hSCManager,
  1192. IN SC_ENUM_TYPE InfoLevel,
  1193. IN DWORD dwServiceType,
  1194. IN DWORD dwServiceState,
  1195. OUT LPBYTE lpServices,
  1196. IN DWORD cbBufSize,
  1197. OUT LPDWORD pcbBytesNeeded,
  1198. OUT LPDWORD lpServicesReturned,
  1199. IN OUT LPDWORD lpResumeIndex,
  1200. IN LPCTSTR pszGroupName
  1201. )
  1202. /*++
  1203. Routine Description:
  1204. Arguments:
  1205. Return Value:
  1206. --*/
  1207. {
  1208. DWORD status;
  1209. LPENUM_SERVICE_STATUS_PROCESSA pEnumBuf;
  1210. ENUM_SERVICE_STATUS_PROCESSA enumBuf;
  1211. DWORD tempBufSize;
  1212. #ifdef _WIN64
  1213. DWORD dwOldResumeIndex = 0;
  1214. if (lpResumeIndex != NULL)
  1215. {
  1216. dwOldResumeIndex = *lpResumeIndex;
  1217. }
  1218. #endif // _WIN64
  1219. //
  1220. // Make sure we were passed a valid InfoLevel
  1221. //
  1222. if (InfoLevel != SC_ENUM_PROCESS_INFO)
  1223. {
  1224. SetLastError(ERROR_INVALID_LEVEL);
  1225. return FALSE;
  1226. }
  1227. tempBufSize = cbBufSize;
  1228. //
  1229. // Create a dummy buffer that is at least the size of the structure.
  1230. // This way RPC should at least send the request to the server side.
  1231. // The server should recognize that the buffer is to small for any
  1232. // strings, and put the correct size in the BytesNeeded parameter,
  1233. // and fail the call.
  1234. //
  1235. if (cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSA) || (lpServices == NULL)) {
  1236. pEnumBuf = &enumBuf;
  1237. tempBufSize = sizeof(ENUM_SERVICE_STATUS_PROCESSA);
  1238. }
  1239. else {
  1240. pEnumBuf = (LPENUM_SERVICE_STATUS_PROCESSA) lpServices;
  1241. }
  1242. RpcTryExcept {
  1243. status = REnumServicesStatusExA (
  1244. (SC_RPC_HANDLE)hSCManager,
  1245. InfoLevel,
  1246. dwServiceType,
  1247. dwServiceState,
  1248. (LPBYTE)pEnumBuf,
  1249. tempBufSize,
  1250. pcbBytesNeeded,
  1251. lpServicesReturned,
  1252. lpResumeIndex,
  1253. pszGroupName);
  1254. }
  1255. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1256. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  1257. }
  1258. RpcEndExcept
  1259. //
  1260. // If data is returned, convert Offsets in the Enum buffer to pointers.
  1261. //
  1262. if ((status == NO_ERROR) || (status == ERROR_MORE_DATA))
  1263. {
  1264. if ((*lpServicesReturned) > 0)
  1265. {
  1266. #ifdef _WIN64
  1267. DWORD dwError;
  1268. if (!ScConvertOffsets64(SC_API_ENUM_PROCESS_A,
  1269. hSCManager,
  1270. dwServiceType,
  1271. dwServiceState,
  1272. (LPBYTE) lpServices,
  1273. cbBufSize,
  1274. pcbBytesNeeded,
  1275. lpServicesReturned,
  1276. &dwOldResumeIndex,
  1277. (LPVOID) pszGroupName,
  1278. &dwError))
  1279. {
  1280. status = dwError;
  1281. if (lpResumeIndex != NULL)
  1282. {
  1283. *lpResumeIndex = dwOldResumeIndex;
  1284. }
  1285. }
  1286. #else // ndef _WIN64
  1287. ScConvertOffsetsExA((LPENUM_SERVICE_STATUS_PROCESSA) lpServices,
  1288. *lpServicesReturned);
  1289. #endif // _WIN64
  1290. }
  1291. #ifdef _WIN64
  1292. //
  1293. // The byte count returned is the size needed to hold all of
  1294. // the 32-bit structures rather than the 64-bit ones. Assume
  1295. // a buffer full of fixed-length structures (i.e., no variable-
  1296. // length data) and scale from 32- to 64-bit sizes to get the
  1297. // minimum guaranteed size for all the 64-bit structures.
  1298. //
  1299. *pcbBytesNeeded = *pcbBytesNeeded
  1300. * sizeof(ENUM_SERVICE_STATUS_PROCESSA)
  1301. / sizeof(ENUM_SERVICE_STATUS_PROCESS_WOW64);
  1302. #endif // _WIN64
  1303. }
  1304. if (status != NO_ERROR)
  1305. {
  1306. SetLastError(status);
  1307. return FALSE;
  1308. }
  1309. return TRUE;
  1310. }
  1311. BOOL
  1312. WINAPI
  1313. QueryServiceObjectSecurity(
  1314. IN SC_HANDLE hService,
  1315. IN SECURITY_INFORMATION dwSecurityInformation,
  1316. OUT PSECURITY_DESCRIPTOR lpSecurityDescriptor,
  1317. IN DWORD cbBufSize,
  1318. OUT LPDWORD pcbBytesNeeded
  1319. )
  1320. /*++
  1321. Routine Description:
  1322. This is the DLL entrypoint for the QueryServiceObjectSecurity API.
  1323. This function returns to the caller requested security information
  1324. currently assigned to an object.
  1325. Based on the caller's access rights this procedure
  1326. will return a security descriptor containing any or all of the
  1327. object's owner ID, group ID, discretionary ACL or system ACL. To
  1328. read the owner ID, group ID, or the discretionary ACL the caller
  1329. must be granted READ_CONTROL access to the object. To read the
  1330. system ACL the caller must be granted ACCESS_SYSTEM_SECURITY
  1331. access.
  1332. Arguments:
  1333. hService - Supplies a handle to an existing service object.
  1334. dwSecurityInformation - Supplies a value describing which pieces of
  1335. security information are being queried.
  1336. lpSecurityInformation - Supplies the output buffer from the user
  1337. which security descriptor information will be written to on
  1338. return.
  1339. cbBufSize - Supplies the size of lpSecurityInformation buffer.
  1340. pcbBytesNeeded - Returns the number of bytes needed of the
  1341. lpSecurityInformation buffer to get all the requested
  1342. information.
  1343. Return Value:
  1344. NO_ERROR - The operation was successful.
  1345. ERROR_INVALID_HANDLE - The specified handle was invalid.
  1346. ERROR_ACCESS_DENIED - The specified handle was not opened for
  1347. either READ_CONTROL or ACCESS_SYSTEM_SECURITY
  1348. access.
  1349. ERROR_INVALID_PARAMETER - The dwSecurityInformation parameter is
  1350. invalid.
  1351. ERROR_INSUFFICIENT_BUFFER - The specified output buffer is smaller
  1352. than the required size returned in pcbBytesNeeded. None of
  1353. the security descriptor is returned.
  1354. --*/
  1355. {
  1356. DWORD status;
  1357. RpcTryExcept {
  1358. status = RQueryServiceObjectSecurity(
  1359. (SC_RPC_HANDLE) hService,
  1360. (DWORD) dwSecurityInformation,
  1361. (LPBYTE) lpSecurityDescriptor,
  1362. cbBufSize,
  1363. pcbBytesNeeded
  1364. );
  1365. }
  1366. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1367. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  1368. }
  1369. RpcEndExcept
  1370. if (status != NO_ERROR){
  1371. SetLastError(status);
  1372. return(FALSE);
  1373. }
  1374. return(TRUE);
  1375. }
  1376. BOOL
  1377. WINAPI
  1378. SetServiceObjectSecurity(
  1379. IN SC_HANDLE hService,
  1380. IN SECURITY_INFORMATION dwSecurityInformation,
  1381. IN PSECURITY_DESCRIPTOR lpSecurityDescriptor
  1382. )
  1383. /*++
  1384. Routine Description:
  1385. This is the DLL entrypoint for the SetServiceObjectSecurity API.
  1386. This function takes a well-formed Security Descriptor provided by the
  1387. caller and assigns specified portions of it to an existing service
  1388. object. Based on the flags set in the SecurityInformation
  1389. parameter and the caller's access rights, this procedure will
  1390. replace any or all of the security information associated with an
  1391. object.
  1392. This is the only function available to users and applications for
  1393. changing security information, including the owner ID, group ID, and
  1394. the discretionary and system ACLs of an object. The caller must
  1395. have WRITE_OWNER access to the object to change the owner or primary
  1396. group of the object. The caller must have WRITE_DAC access to the
  1397. object to change the discretionary ACL. The caller must have
  1398. ACCESS_SYSTEM_SECURITY access to an object to assign a system ACL
  1399. to the object.
  1400. Parameters:
  1401. hService - Supplies a handle to an existing service object.
  1402. dwSecurityInformation - Supplies a value describing which pieces of
  1403. security information are being set.
  1404. lpSecurityInformation - Supplies a pointer to a well-formed security
  1405. descriptor.
  1406. Return Values:
  1407. NO_ERROR - The operation was successful.
  1408. ERROR_INVALID_HANDLE - The specified handle was invalid.
  1409. ERROR_ACCESS_DENIED - The specified handle was not opened for
  1410. either WRITE_OWNER, WRITE_DAC, or ACCESS_SYSTEM_SECURITY
  1411. access.
  1412. ERROR_INVALID_PARAMETER - The lpSecurityDescriptor or dwSecurityInformation
  1413. parameter is invalid.
  1414. ERROR_NOT_ENOUGH_MEMORY - Not enough memory to complete the API call.
  1415. --*/
  1416. {
  1417. DWORD status;
  1418. NTSTATUS ntstatus;
  1419. DWORD UserSdSize = 0;
  1420. PSECURITY_DESCRIPTOR SelfRelativeSd;
  1421. //
  1422. // Find out the length of the user supplied security descriptor
  1423. //
  1424. ntstatus = RtlMakeSelfRelativeSD(
  1425. lpSecurityDescriptor,
  1426. NULL,
  1427. &UserSdSize
  1428. );
  1429. if (ntstatus != STATUS_BUFFER_TOO_SMALL) {
  1430. //
  1431. // lpSecurityDescriptor is invalid
  1432. //
  1433. SetLastError(ERROR_INVALID_PARAMETER);
  1434. return(FALSE);
  1435. }
  1436. SelfRelativeSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_ZEROINIT, (UINT) UserSdSize);
  1437. if (SelfRelativeSd == NULL) {
  1438. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1439. return(FALSE);
  1440. }
  1441. //
  1442. // Make a self-relative security descriptor for the RPC call
  1443. //
  1444. ntstatus = RtlMakeSelfRelativeSD(
  1445. lpSecurityDescriptor,
  1446. SelfRelativeSd,
  1447. &UserSdSize
  1448. );
  1449. if (! NT_SUCCESS(ntstatus)) {
  1450. LocalFree(SelfRelativeSd);
  1451. SetLastError(RtlNtStatusToDosError(ntstatus));
  1452. return(FALSE);
  1453. }
  1454. //
  1455. // Call the server
  1456. //
  1457. RpcTryExcept {
  1458. status = RSetServiceObjectSecurity(
  1459. (SC_RPC_HANDLE) hService,
  1460. (DWORD) dwSecurityInformation,
  1461. (LPBYTE) SelfRelativeSd,
  1462. UserSdSize
  1463. );
  1464. }
  1465. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  1466. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  1467. }
  1468. RpcEndExcept
  1469. (void) LocalFree(SelfRelativeSd);
  1470. if (status != NO_ERROR){
  1471. SetLastError(status);
  1472. return(FALSE);
  1473. }
  1474. return(TRUE);
  1475. }
  1476. VOID
  1477. ScConvertOffsetsW(
  1478. LPENUM_SERVICE_STATUSW lpServices,
  1479. DWORD NumStructs
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. Arguments:
  1484. Return Value:
  1485. --*/
  1486. {
  1487. LPBYTE pBuffer;
  1488. DWORD i;
  1489. pBuffer = (LPBYTE)lpServices;
  1490. for (i=0; i<NumStructs; i++ ) {
  1491. lpServices[i].lpServiceName = (LPWSTR)(pBuffer +
  1492. (DWORD)(ULONG_PTR)(lpServices[i].lpServiceName));
  1493. lpServices[i].lpDisplayName = (LPWSTR)(pBuffer +
  1494. (DWORD)(ULONG_PTR)(lpServices[i].lpDisplayName));
  1495. }
  1496. }
  1497. VOID
  1498. ScConvertOffsetsA(
  1499. LPENUM_SERVICE_STATUSA lpServices,
  1500. DWORD NumStructs
  1501. )
  1502. /*++
  1503. Routine Description:
  1504. Arguments:
  1505. Return Value:
  1506. --*/
  1507. {
  1508. LPBYTE pBuffer;
  1509. DWORD i;
  1510. pBuffer = (LPBYTE)lpServices;
  1511. for (i=0; i<NumStructs; i++ ) {
  1512. lpServices[i].lpServiceName = (LPSTR)(pBuffer +
  1513. (DWORD)(ULONG_PTR)(lpServices[i].lpServiceName));
  1514. lpServices[i].lpDisplayName = (LPSTR)(pBuffer +
  1515. (DWORD)(ULONG_PTR)(lpServices[i].lpDisplayName));
  1516. }
  1517. }
  1518. VOID
  1519. ScConvertOffsetsExW(
  1520. LPENUM_SERVICE_STATUS_PROCESSW lpServices,
  1521. DWORD NumStructs
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. Arguments:
  1526. Return Value:
  1527. --*/
  1528. {
  1529. LPBYTE pBuffer;
  1530. DWORD i;
  1531. pBuffer = (LPBYTE)lpServices;
  1532. for (i=0; i<NumStructs; i++ ) {
  1533. lpServices[i].lpServiceName = (LPWSTR)(pBuffer +
  1534. (DWORD)(ULONG_PTR)(lpServices[i].lpServiceName));
  1535. lpServices[i].lpDisplayName = (LPWSTR)(pBuffer +
  1536. (DWORD)(ULONG_PTR)(lpServices[i].lpDisplayName));
  1537. }
  1538. }
  1539. VOID
  1540. ScConvertOffsetsExA(
  1541. LPENUM_SERVICE_STATUS_PROCESSA lpServices,
  1542. DWORD NumStructs
  1543. )
  1544. /*++
  1545. Routine Description:
  1546. Arguments:
  1547. Return Value:
  1548. --*/
  1549. {
  1550. LPBYTE pBuffer;
  1551. DWORD i;
  1552. pBuffer = (LPBYTE)lpServices;
  1553. for (i=0; i<NumStructs; i++ ) {
  1554. lpServices[i].lpServiceName = (LPSTR)(pBuffer +
  1555. (DWORD)(ULONG_PTR)(lpServices[i].lpServiceName));
  1556. lpServices[i].lpDisplayName = (LPSTR)(pBuffer +
  1557. (DWORD)(ULONG_PTR)(lpServices[i].lpDisplayName));
  1558. }
  1559. }
  1560. #ifdef _WIN64
  1561. BOOL
  1562. ScConvertOffsets64(
  1563. SC_API_NUMBER scApi,
  1564. SC_HANDLE hSCManager,
  1565. DWORD dwServiceType,
  1566. DWORD dwServiceState,
  1567. LPBYTE lpServices,
  1568. DWORD cbBufSize,
  1569. LPDWORD pcbBytesNeeded,
  1570. LPDWORD lpServicesReturned,
  1571. LPDWORD lpResumeIndex,
  1572. LPVOID pszGroupName,
  1573. LPDWORD lpdwError
  1574. )
  1575. /*++
  1576. Routine Description:
  1577. Perform API-specific offset-to-pointer conversions for the
  1578. client side of the SCM APIs on 64-bit clients.
  1579. Arguments:
  1580. Return Value:
  1581. TRUE if the conversion succeeded, FALSE otherwise (with lpdwError
  1582. holding the true error).
  1583. --*/
  1584. {
  1585. switch (scApi)
  1586. {
  1587. case SC_API_ENUM_W:
  1588. case SC_API_ENUM_A:
  1589. case SC_API_ENUM_GROUP:
  1590. case SC_API_ENUM_PROCESS_W:
  1591. case SC_API_ENUM_PROCESS_A:
  1592. case SC_API_ENUM_DEPEND_W:
  1593. case SC_API_ENUM_DEPEND_A:
  1594. {
  1595. //
  1596. // Convert buffer returned by EnumServicesStatusW
  1597. //
  1598. LPBYTE lpIter = lpServices;
  1599. LPBYTE lpConverted;
  1600. DWORD dwCount64;
  1601. DWORD dwTotalVarData = 0;
  1602. DWORD dwSize64 = 0;
  1603. DWORD dwStatusSize;
  1604. DWORD dwStrucSize64;
  1605. DWORD dwStrucSizeWOW;
  1606. if (scApi == SC_API_ENUM_PROCESS_W || scApi == SC_API_ENUM_PROCESS_A)
  1607. {
  1608. dwStrucSize64 = sizeof(ENUM_SERVICE_STATUS_PROCESSW);
  1609. dwStrucSizeWOW = sizeof(ENUM_SERVICE_STATUS_PROCESS_WOW64);
  1610. dwStatusSize = sizeof(SERVICE_STATUS_PROCESS);
  1611. }
  1612. else
  1613. {
  1614. dwStrucSize64 = sizeof(ENUM_SERVICE_STATUSW);
  1615. dwStrucSizeWOW = sizeof(ENUM_SERVICE_STATUS_WOW64);
  1616. dwStatusSize = sizeof(SERVICE_STATUS);
  1617. }
  1618. for (dwCount64 = 0;
  1619. dwCount64 < *lpServicesReturned;
  1620. dwCount64++, lpIter += dwStrucSizeWOW)
  1621. {
  1622. DWORD dwCurrentVarData;
  1623. DWORD dwOffset;
  1624. //
  1625. // Compute size of this record's variable-length data
  1626. //
  1627. dwOffset = ((LPENUM_SERVICE_STATUS_WOW64) lpIter)->dwDisplayNameOffset;
  1628. dwCurrentVarData = cbBufSize - dwOffset - dwTotalVarData;
  1629. //
  1630. // Is there room to expand the current record to 64-bit pointers?
  1631. //
  1632. if (dwSize64 + dwStrucSize64 + dwCurrentVarData > cbBufSize)
  1633. {
  1634. //
  1635. // Nope.
  1636. //
  1637. break;
  1638. }
  1639. //
  1640. // Update the total number of variable-length data bytes
  1641. // in the post-conversion buffer
  1642. //
  1643. dwTotalVarData += dwCurrentVarData;
  1644. dwSize64 += dwStrucSize64 + dwCurrentVarData;
  1645. }
  1646. //
  1647. // Set up the pointer to the last soon-to-be-converted structure.
  1648. // Cast to INT to sign-extend the offset to 64 bits (required
  1649. // when (dwCount64 == 0) or else the sum gets bizarre).
  1650. //
  1651. lpIter = lpServices + (INT) (dwStrucSizeWOW * (dwCount64 - 1));
  1652. lpConverted = lpServices + (INT) (dwStrucSize64 * (dwCount64 - 1));
  1653. for ( ;
  1654. lpIter >= lpServices;
  1655. lpIter -= dwStrucSizeWOW, lpConverted -= dwStrucSize64)
  1656. {
  1657. LPENUM_SERVICE_STATUSW lpEnum = (LPENUM_SERVICE_STATUSW) lpConverted;
  1658. LPENUM_SERVICE_STATUS_WOW64 lpEnumWOW = (LPENUM_SERVICE_STATUS_WOW64) lpIter;
  1659. //
  1660. // Copy fields individually in reverse order in case there's overlap
  1661. //
  1662. RtlMoveMemory(&lpEnum->ServiceStatus,
  1663. &lpEnumWOW->ServiceStatus,
  1664. dwStatusSize);
  1665. //
  1666. // Do the offset-to-pointer conversion. Can do straight addition
  1667. // since we didn't move the variable length data.
  1668. //
  1669. lpEnum->lpDisplayName = (LPWSTR) (lpServices + lpEnumWOW->dwDisplayNameOffset);
  1670. lpEnum->lpServiceName = (LPWSTR) (lpServices + lpEnumWOW->dwServiceNameOffset);
  1671. }
  1672. ASSERT(lpIter < lpServices && lpConverted < lpServices);
  1673. if (*lpServicesReturned != dwCount64)
  1674. {
  1675. //
  1676. // Not enough room to fit all the records returned. Update
  1677. // all the OUT parameters. Add on the size of the overwritten
  1678. // records' variable-length data first.
  1679. //
  1680. *pcbBytesNeeded += (cbBufSize
  1681. - dwTotalVarData
  1682. - *lpServicesReturned * dwStrucSizeWOW);
  1683. //
  1684. // And now do the fixed-length data. Use the 32-bit structures
  1685. // and the caller will multiply it up to 64-bit lengths.
  1686. //
  1687. *pcbBytesNeeded += (*lpServicesReturned - dwCount64)
  1688. * dwStrucSizeWOW;
  1689. //
  1690. // Update the count of services returned
  1691. //
  1692. *lpServicesReturned = dwCount64;
  1693. if (scApi == SC_API_ENUM_DEPEND_W || scApi == SC_API_ENUM_DEPEND_A)
  1694. {
  1695. *lpdwError = ERROR_MORE_DATA;
  1696. return FALSE;
  1697. }
  1698. //
  1699. // And now things get ugly. We need to update the resume index
  1700. // since we removed some services from the buffer. However,
  1701. // there's no easy way to get the resume index of a particular
  1702. // service from the server side. So we have to build up an
  1703. // enum buffer that's just small enough to hold only the records
  1704. // we're going to return and enum again just to get the RI.
  1705. //
  1706. LPBYTE lpTemp;
  1707. DWORD status;
  1708. DWORD dwTempBytes;
  1709. DWORD dwTempCount;
  1710. DWORD dwTempSize = dwCount64 * dwStrucSizeWOW + dwTotalVarData;
  1711. lpTemp = (LPBYTE) LocalAlloc(LMEM_FIXED, dwTempSize);
  1712. if (lpTemp == NULL)
  1713. {
  1714. *lpdwError = ERROR_NOT_ENOUGH_MEMORY;
  1715. return FALSE;
  1716. }
  1717. RpcTryExcept
  1718. {
  1719. switch (scApi)
  1720. {
  1721. case SC_API_ENUM_W:
  1722. status = REnumServicesStatusW (
  1723. (SC_RPC_HANDLE) hSCManager,
  1724. dwServiceType,
  1725. dwServiceState,
  1726. (LPBYTE) lpTemp,
  1727. dwTempSize,
  1728. &dwTempBytes,
  1729. &dwTempCount,
  1730. lpResumeIndex);
  1731. break;
  1732. case SC_API_ENUM_A:
  1733. status = REnumServicesStatusA (
  1734. (SC_RPC_HANDLE) hSCManager,
  1735. dwServiceType,
  1736. dwServiceState,
  1737. (LPBYTE) lpTemp,
  1738. dwTempSize,
  1739. &dwTempBytes,
  1740. &dwTempCount,
  1741. lpResumeIndex);
  1742. break;
  1743. case SC_API_ENUM_GROUP:
  1744. status = REnumServiceGroupW (
  1745. (SC_RPC_HANDLE) hSCManager,
  1746. dwServiceType,
  1747. dwServiceState,
  1748. (LPBYTE) lpTemp,
  1749. dwTempSize,
  1750. &dwTempBytes,
  1751. &dwTempCount,
  1752. lpResumeIndex,
  1753. (LPCWSTR) pszGroupName);
  1754. break;
  1755. case SC_API_ENUM_PROCESS_W:
  1756. status = REnumServicesStatusExW (
  1757. hSCManager,
  1758. SC_ENUM_PROCESS_INFO,
  1759. dwServiceType,
  1760. dwServiceState,
  1761. (LPBYTE) lpTemp,
  1762. dwTempSize,
  1763. &dwTempBytes,
  1764. &dwTempCount,
  1765. lpResumeIndex,
  1766. (LPCWSTR) pszGroupName);
  1767. break;
  1768. case SC_API_ENUM_PROCESS_A:
  1769. status = REnumServicesStatusExA (
  1770. hSCManager,
  1771. SC_ENUM_PROCESS_INFO,
  1772. dwServiceType,
  1773. dwServiceState,
  1774. (LPBYTE) lpTemp,
  1775. dwTempSize,
  1776. &dwTempBytes,
  1777. &dwTempCount,
  1778. lpResumeIndex,
  1779. (LPCSTR) pszGroupName);
  1780. break;
  1781. default:
  1782. ASSERT(FALSE && "Unsupported API in ScConvertOffsets64 enum path");
  1783. status = ERROR_NOT_SUPPORTED;
  1784. }
  1785. }
  1786. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  1787. {
  1788. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  1789. }
  1790. RpcEndExcept
  1791. LocalFree(lpTemp);
  1792. //
  1793. // We had to overwrite at least one structure so we need
  1794. // to return some form of error, even if it's ERROR_MORE_DATA.
  1795. //
  1796. *lpdwError = status;
  1797. return FALSE;
  1798. }
  1799. return TRUE;
  1800. break;
  1801. }
  1802. case SC_API_QUERY_DESCRIPTION_W:
  1803. case SC_API_QUERY_DESCRIPTION_A:
  1804. {
  1805. DWORD dwBytesNeeded = *pcbBytesNeeded;
  1806. DWORD dwSizeDiff = sizeof(SERVICE_DESCRIPTIONW) - sizeof(SERVICE_DESCRIPTION_WOW64);
  1807. LPSERVICE_DESCRIPTION_WOW64 psdWOW = (LPSERVICE_DESCRIPTION_WOW64) lpServices;
  1808. LPSERVICE_DESCRIPTIONW psd = (LPSERVICE_DESCRIPTIONW) lpServices;
  1809. //
  1810. // *pcbBytesNeeded is filled in on success or "buffer too small"
  1811. // failure, so update it with the 64-bit size.
  1812. //
  1813. *pcbBytesNeeded += dwSizeDiff;
  1814. if (*pcbBytesNeeded > cbBufSize)
  1815. {
  1816. return FALSE;
  1817. }
  1818. //
  1819. // We have room -- move the variable-length data
  1820. //
  1821. RtlMoveMemory(psd + 1,
  1822. psdWOW + 1,
  1823. dwBytesNeeded - sizeof(SERVICE_DESCRIPTION_WOW64));
  1824. //
  1825. // Resize the offset from 4 to 8 bytes.
  1826. //
  1827. if (psdWOW->dwDescriptionOffset == 0)
  1828. {
  1829. psd->lpDescription = NULL;
  1830. }
  1831. else
  1832. {
  1833. psd->lpDescription = (LPWSTR) UlongToPtr(psdWOW->dwDescriptionOffset + dwSizeDiff);
  1834. }
  1835. return TRUE;
  1836. }
  1837. case SC_API_QUERY_FAILURE_ACTIONS_W:
  1838. case SC_API_QUERY_FAILURE_ACTIONS_A:
  1839. {
  1840. DWORD dwBytesNeeded = *pcbBytesNeeded;
  1841. DWORD dwSizeDiff = sizeof(SERVICE_FAILURE_ACTIONSW) - sizeof(SERVICE_FAILURE_ACTIONS_WOW64);
  1842. LPSERVICE_FAILURE_ACTIONS_WOW64 psfaWOW = (LPSERVICE_FAILURE_ACTIONS_WOW64) lpServices;
  1843. LPSERVICE_FAILURE_ACTIONSW psfa = (LPSERVICE_FAILURE_ACTIONSW) lpServices;
  1844. //
  1845. // *pcbBytesNeeded is filled in on success or "buffer too small"
  1846. // failure, so update it with the 64-bit size.
  1847. //
  1848. *pcbBytesNeeded += dwSizeDiff;
  1849. if (*pcbBytesNeeded > cbBufSize)
  1850. {
  1851. return FALSE;
  1852. }
  1853. //
  1854. // We have room -- move the variable-length data
  1855. //
  1856. RtlMoveMemory(psfa + 1,
  1857. psfaWOW + 1,
  1858. dwBytesNeeded - sizeof(SERVICE_FAILURE_ACTIONS_WOW64));
  1859. //
  1860. // Resize the offsets from 4 to 8 bytes. Do this in reverse field order
  1861. // to avoid trampling over any still-to-be-converted offsets.
  1862. //
  1863. if (psfaWOW->dwsaActionsOffset == 0)
  1864. {
  1865. psfa->lpsaActions = NULL;
  1866. }
  1867. else
  1868. {
  1869. psfa->lpsaActions = (SC_ACTION *) UlongToPtr(psfaWOW->dwsaActionsOffset + dwSizeDiff);
  1870. }
  1871. psfa->cActions = psfaWOW->cActions;
  1872. if (psfaWOW->dwCommandOffset == 0)
  1873. {
  1874. psfa->lpCommand = NULL;
  1875. }
  1876. else
  1877. {
  1878. psfa->lpCommand = (LPWSTR) UlongToPtr(psfaWOW->dwCommandOffset + dwSizeDiff);
  1879. }
  1880. if (psfaWOW->dwRebootMsgOffset == 0)
  1881. {
  1882. psfa->lpRebootMsg = NULL;
  1883. }
  1884. else
  1885. {
  1886. psfa->lpRebootMsg = (LPWSTR) UlongToPtr(psfaWOW->dwRebootMsgOffset + dwSizeDiff);
  1887. }
  1888. psfa->dwResetPeriod = psfaWOW->dwResetPeriod;
  1889. return TRUE;
  1890. }
  1891. default:
  1892. ASSERT(FALSE && "Unsupported API passed to ScConvertOffsets64");
  1893. *lpdwError = ERROR_NOT_SUPPORTED;
  1894. return FALSE;
  1895. }
  1896. }
  1897. #endif // _WIN64
  1898. BOOL
  1899. WINAPI
  1900. ChangeServiceConfigA(
  1901. IN SC_HANDLE hService,
  1902. IN DWORD dwServiceType,
  1903. IN DWORD dwStartType,
  1904. IN DWORD dwErrorControl,
  1905. IN LPCSTR lpBinaryPathName,
  1906. IN LPCSTR lpLoadOrderGroup,
  1907. OUT LPDWORD lpdwTagId,
  1908. IN LPCSTR lpDependencies,
  1909. IN LPCSTR lpServiceStartName,
  1910. IN LPCSTR lpPassword,
  1911. IN LPCSTR lpDisplayName
  1912. )
  1913. /*++
  1914. Routine Description:
  1915. This is the DLL entry point for the ChangeServiceConfig function.
  1916. ChangeServiceConfig changes the service configuration kept in the
  1917. Service Control Manager database. This configuration information
  1918. was first set in the database via the CreateService API, and can
  1919. be queried (exept for the password parameter) using the
  1920. QueryServiceConfig API.
  1921. Arguments:
  1922. hService - Handle obtained from a previous OpenService call.
  1923. dwServiceType - Value to indicate the type of service this is.
  1924. dwStartType - Value to specify when to start the service.
  1925. dwErrorControl - Value to specify the severity of the error if this
  1926. service fails to start during boot so that the appropriate action
  1927. can be taken.
  1928. lpBinaryPathName - Fully-qualified path name to the service binary file.
  1929. lpLoadOrderGroup - Name of the load ordering group which this service
  1930. is a member of. Groups of services are started based on the group
  1931. order list specified in the registry at
  1932. HKEY_LOCAL_SYSTEM\Control\Service_Group_Order.
  1933. lpdwTagId - On output this pointer receives a unique tag identification
  1934. number within the group. If this parameter is specified (non-NULL)
  1935. but lpLoadOrderGroup is not specified, ERROR_INVALID_PARAMETER
  1936. will be returned.
  1937. lpDependencies - NULL-separated names of services which must be
  1938. running before this service can run. An empty string means that
  1939. this service has no dependencies.
  1940. lpServiceStartName - If service type is SERVICE_WIN32, this name is
  1941. the account name in the form of "DomainName\Username" which the
  1942. service process will be logged on as when it runs. If service
  1943. type is SERVICE_DRIVER, this name must be the NT driver object
  1944. name (e.g. \FileSystem\LanManRedirector or \Driver\Xns) which
  1945. the I/O system uses to load the device driver.
  1946. lpPassword - Password to the account name specified by
  1947. lpServiceStartName if service type is SERVICE_WIN32. This
  1948. password will be changed periodically by the Service Control
  1949. Manager so that it will not expire. If service type is
  1950. SERVICE_DRIVER, this parameter is ignored.
  1951. lpDisplayName - This is the internationalized name that is used for
  1952. display purposes only.
  1953. Return Value:
  1954. Note:
  1955. --*/
  1956. {
  1957. DWORD status;
  1958. LPWSTR lpPasswordW;
  1959. LPBYTE EncryptedPassword = NULL;
  1960. DWORD PasswordSize = 0;
  1961. LPSTR Ptr;
  1962. LPWSTR DependBuffer = NULL;
  1963. DWORD DependSize = 0;
  1964. RpcTryExcept {
  1965. //
  1966. // Create a unicode version of lpPassword, and then encrypt it.
  1967. //
  1968. if (ARGUMENT_PRESENT(lpPassword)) {
  1969. if (! ScConvertToUnicode(&lpPasswordW, lpPassword)) {
  1970. SCC_LOG0(ERROR,"ChangeServiceConfigA: convert password to Unicode failed\n");
  1971. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1972. return(FALSE);
  1973. }
  1974. status = ScEncryptPassword(
  1975. (SC_RPC_HANDLE)hService,
  1976. lpPasswordW,
  1977. &EncryptedPassword,
  1978. &PasswordSize
  1979. );
  1980. (void) LocalFree(lpPasswordW);
  1981. if (status != NO_ERROR) {
  1982. SCC_LOG0(ERROR,"ChangeServiceConfigA: ScEncryptPassword failed\n");
  1983. SetLastError(status);
  1984. return(FALSE);
  1985. }
  1986. }
  1987. if (ARGUMENT_PRESENT(lpDependencies)) {
  1988. DependSize = ScAStrArraySize((LPSTR) lpDependencies) / sizeof(CHAR) * sizeof(WCHAR);
  1989. if ((DependBuffer = (LPWSTR)LocalAlloc(
  1990. LMEM_ZEROINIT,
  1991. (UINT) DependSize)) == NULL) {
  1992. SCC_LOG1(ERROR,
  1993. "ChangeServiceConfigA: LocalAlloc of DependBuffer failed "
  1994. FORMAT_DWORD "\n", GetLastError());
  1995. status = ERROR_NOT_ENOUGH_MEMORY;
  1996. }
  1997. if (DependSize > sizeof(WCHAR)) {
  1998. //
  1999. // There is at least one dependency entry.
  2000. //
  2001. Ptr = (LPSTR) lpDependencies;
  2002. //
  2003. // Convert each dependency into Unicode, and append it to the
  2004. // DependBuffer.
  2005. //
  2006. while (*Ptr != 0) {
  2007. LPWSTR ConvertedDependency = NULL;
  2008. if (! ScConvertToUnicode(&ConvertedDependency, Ptr)) {
  2009. SCC_LOG0(ERROR,
  2010. "ChangeServiceConfigA: convert dependency to Unicode failed\n");
  2011. status = ERROR_NOT_ENOUGH_MEMORY;
  2012. goto CleanExit;
  2013. }
  2014. ScAddWStrToWStrArray(DependBuffer, ConvertedDependency);
  2015. (void) LocalFree(ConvertedDependency);
  2016. Ptr = ScNextAStrArrayEntry(Ptr);
  2017. }
  2018. }
  2019. }
  2020. status = RChangeServiceConfigA(
  2021. (SC_RPC_HANDLE)hService,
  2022. dwServiceType,
  2023. dwStartType,
  2024. dwErrorControl,
  2025. (LPSTR) lpBinaryPathName,
  2026. (LPSTR) lpLoadOrderGroup,
  2027. lpdwTagId,
  2028. (LPBYTE) DependBuffer,
  2029. DependSize,
  2030. (LPSTR) lpServiceStartName,
  2031. EncryptedPassword,
  2032. PasswordSize,
  2033. (LPSTR)lpDisplayName);
  2034. }
  2035. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2036. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2037. }
  2038. RpcEndExcept
  2039. CleanExit:
  2040. if (EncryptedPassword != NULL) {
  2041. (void) LocalFree(EncryptedPassword);
  2042. }
  2043. if (DependBuffer != NULL) {
  2044. (void) LocalFree(DependBuffer);
  2045. }
  2046. if (status != NO_ERROR){
  2047. SetLastError(status);
  2048. return(FALSE);
  2049. }
  2050. return(TRUE);
  2051. }
  2052. BOOL
  2053. WINAPI
  2054. ChangeServiceConfigW(
  2055. IN SC_HANDLE hService,
  2056. IN DWORD dwServiceType,
  2057. IN DWORD dwStartType,
  2058. IN DWORD dwErrorControl,
  2059. IN LPCWSTR lpBinaryPathName,
  2060. IN LPCWSTR lpLoadOrderGroup,
  2061. OUT LPDWORD lpdwTagId,
  2062. IN LPCWSTR lpDependencies,
  2063. IN LPCWSTR lpServiceStartName,
  2064. IN LPCWSTR lpPassword,
  2065. IN LPCWSTR lpDisplayName
  2066. )
  2067. /*++
  2068. Routine Description:
  2069. see ChangeServiceConfigA
  2070. Arguments:
  2071. Return Value:
  2072. Note:
  2073. --*/
  2074. {
  2075. DWORD status;
  2076. LPBYTE EncryptedPassword = NULL;
  2077. DWORD PasswordSize = 0;
  2078. DWORD DependSize = 0;
  2079. RpcTryExcept {
  2080. //
  2081. // Create a unicode version of lpPassword, and then encrypt it.
  2082. //
  2083. if (ARGUMENT_PRESENT(lpPassword)) {
  2084. status = ScEncryptPassword(
  2085. (SC_RPC_HANDLE)hService,
  2086. (LPWSTR) lpPassword,
  2087. &EncryptedPassword,
  2088. &PasswordSize
  2089. );
  2090. if (status != NO_ERROR) {
  2091. SCC_LOG0(ERROR,"ChangeServiceConfigW: ScEncryptPassword failed\n");
  2092. SetLastError(status);
  2093. return(FALSE);
  2094. }
  2095. }
  2096. if (ARGUMENT_PRESENT(lpDependencies)) {
  2097. DependSize = ScWStrArraySize((LPWSTR) lpDependencies);
  2098. }
  2099. status = RChangeServiceConfigW(
  2100. (SC_RPC_HANDLE)hService,
  2101. dwServiceType,
  2102. dwStartType,
  2103. dwErrorControl,
  2104. (LPWSTR) lpBinaryPathName,
  2105. (LPWSTR) lpLoadOrderGroup,
  2106. lpdwTagId,
  2107. (LPBYTE) lpDependencies,
  2108. DependSize,
  2109. (LPWSTR) lpServiceStartName,
  2110. EncryptedPassword,
  2111. PasswordSize,
  2112. (LPWSTR)lpDisplayName);
  2113. }
  2114. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2115. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2116. }
  2117. RpcEndExcept
  2118. if (EncryptedPassword != NULL) {
  2119. (void) LocalFree(EncryptedPassword);
  2120. }
  2121. if (status != NO_ERROR){
  2122. SetLastError(status);
  2123. return(FALSE);
  2124. }
  2125. return(TRUE);
  2126. }
  2127. BOOL
  2128. WINAPI
  2129. ChangeServiceConfig2A(
  2130. IN SC_HANDLE hService,
  2131. IN DWORD dwInfoLevel,
  2132. IN LPVOID lpInfo
  2133. )
  2134. /*++
  2135. Routine Description:
  2136. Arguments:
  2137. Return Value:
  2138. Note:
  2139. --*/
  2140. {
  2141. DWORD status;
  2142. // Transform the parameters into a union that RPC likes
  2143. SC_RPC_CONFIG_INFOA RpcInfo = { dwInfoLevel,
  2144. (LPSERVICE_DESCRIPTIONA) lpInfo };
  2145. RpcTryExcept
  2146. {
  2147. status = RChangeServiceConfig2A(
  2148. (SC_RPC_HANDLE) hService,
  2149. RpcInfo
  2150. );
  2151. }
  2152. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  2153. {
  2154. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2155. }
  2156. RpcEndExcept
  2157. if (status == RPC_S_INVALID_TAG)
  2158. {
  2159. status = ERROR_INVALID_LEVEL;
  2160. }
  2161. if (status != NO_ERROR)
  2162. {
  2163. SetLastError(status);
  2164. return FALSE;
  2165. }
  2166. return TRUE;
  2167. }
  2168. BOOL
  2169. WINAPI
  2170. ChangeServiceConfig2W(
  2171. IN SC_HANDLE hService,
  2172. IN DWORD dwInfoLevel,
  2173. IN LPVOID lpInfo
  2174. )
  2175. /*++
  2176. Routine Description:
  2177. Arguments:
  2178. Return Value:
  2179. Note:
  2180. --*/
  2181. {
  2182. DWORD status;
  2183. // Transform the parameters into a union that RPC likes
  2184. SC_RPC_CONFIG_INFOW RpcInfo = { dwInfoLevel,
  2185. (LPSERVICE_DESCRIPTIONW) lpInfo };
  2186. RpcTryExcept
  2187. {
  2188. status = RChangeServiceConfig2W(
  2189. (SC_RPC_HANDLE) hService,
  2190. RpcInfo
  2191. );
  2192. }
  2193. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  2194. {
  2195. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2196. }
  2197. RpcEndExcept
  2198. if (status == RPC_S_INVALID_TAG)
  2199. {
  2200. status = ERROR_INVALID_LEVEL;
  2201. }
  2202. if (status != NO_ERROR)
  2203. {
  2204. SetLastError(status);
  2205. return FALSE;
  2206. }
  2207. return TRUE;
  2208. }
  2209. SC_HANDLE
  2210. WINAPI
  2211. CreateServiceA(
  2212. IN SC_HANDLE hSCManager,
  2213. IN LPCSTR lpServiceName,
  2214. IN LPCSTR lpDisplayName,
  2215. IN DWORD dwDesiredAccess,
  2216. IN DWORD dwServiceType,
  2217. IN DWORD dwStartType,
  2218. IN DWORD dwErrorControl,
  2219. IN LPCSTR lpBinaryPathName,
  2220. IN LPCSTR lpLoadOrderGroup,
  2221. OUT LPDWORD lpdwTagId,
  2222. IN LPCSTR lpDependencies,
  2223. IN LPCSTR lpServiceStartName,
  2224. IN LPCSTR lpPassword
  2225. )
  2226. /*++
  2227. Routine Description:
  2228. This function is the DLL entry point for the ansi version
  2229. of CreateService. On the server side, this function will create
  2230. a service object and add it to the Service Control Manager database.
  2231. Arguments:
  2232. hSCManager - Handle obtained from a previous OpenSCManager call.
  2233. lpServiceName - Name of the service to install.
  2234. lpDisplayName - This is the internationalized name that is used for
  2235. display purposes only.
  2236. dwDesiredAccess - Access types desired to access the service.
  2237. dwServiceType - Value to indicate the type of service this is.
  2238. dwStartType - Value to specify when to start the service.
  2239. dwErrorControl - Value to specify the severity of the error if this
  2240. service fails to start during boot so that the appropriate action
  2241. can be taken.
  2242. lpBinaryPathName - Fully-qualified path name to the service binary file.
  2243. lpLoadOrderGroup - Name of the load ordering group which this service
  2244. is a member of. Groups of services are started based on the group
  2245. order list specified in the registry at
  2246. HKEY_LOCAL_SYSTEM\Control\Service_Group_Order.
  2247. lpdwTagId - On output this pointer receives a unique tag identification
  2248. number within the group. If this parameter is specified (non-NULL)
  2249. but lpLoadOrderGroup is not specified, ERROR_INVALID_PARAMETER
  2250. will be returned.
  2251. lpDependencies - Space-separated names of services which must be
  2252. running before this service can run. An empty string means that
  2253. this service has no dependencies.
  2254. lpServiceStartName - If service type is SERVICE_WIN32, this name is
  2255. the account name in the form of "DomainName\Username" which the
  2256. service process will be logged on as when it runs. If service
  2257. type is SERVICE_DRIVER, this name must be the NT driver object
  2258. name (e.g. \FileSystem\LanManRedirector or \Driver\Xns) which
  2259. the I/O system uses to load the device driver.
  2260. lpPassword - Password to the account name specified by
  2261. lpServiceStartName if service type is SERVICE_WIN32. This
  2262. password will be changed periodically by the Service Control
  2263. Manager so that it will not expire. If service type is
  2264. SERVICE_DRIVER, this parameter is ignored.
  2265. Return Value:
  2266. Note:
  2267. --*/
  2268. {
  2269. DWORD status;
  2270. SC_RPC_HANDLE hService=NULL;
  2271. LPWSTR lpPasswordW;
  2272. LPBYTE EncryptedPassword = NULL;
  2273. DWORD PasswordSize = 0;
  2274. LPSTR Ptr;
  2275. LPWSTR DependBuffer = NULL;
  2276. DWORD DependSize = 0;
  2277. RpcTryExcept {
  2278. //
  2279. // Create a unicode version of lpPassword, and then encrypt it.
  2280. //
  2281. if (ARGUMENT_PRESENT(lpPassword)) {
  2282. if (! ScConvertToUnicode(&lpPasswordW, lpPassword)) {
  2283. SCC_LOG0(ERROR,"CreateServiceA: convert password to Unicode failed\n");
  2284. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2285. return(NULL);
  2286. }
  2287. status = ScEncryptPassword(
  2288. (SC_RPC_HANDLE)hSCManager,
  2289. lpPasswordW,
  2290. &EncryptedPassword,
  2291. &PasswordSize
  2292. );
  2293. (void) LocalFree(lpPasswordW);
  2294. if (status != NO_ERROR) {
  2295. SCC_LOG0(ERROR,"CreateServiceA: ScEncryptPassword failed\n");
  2296. SetLastError(status);
  2297. return(NULL);
  2298. }
  2299. }
  2300. if (ARGUMENT_PRESENT(lpDependencies)) {
  2301. DependSize = ScAStrArraySize((LPSTR) lpDependencies) / sizeof(CHAR) * sizeof(WCHAR);
  2302. if ((DependBuffer = (LPWSTR)LocalAlloc(
  2303. LMEM_ZEROINIT,
  2304. (UINT) DependSize)) == NULL) {
  2305. SCC_LOG1(ERROR,
  2306. "CreateServiceA: LocalAlloc of DependBuffer failed "
  2307. FORMAT_DWORD "\n", GetLastError());
  2308. status = ERROR_NOT_ENOUGH_MEMORY;
  2309. goto CleanExit;
  2310. }
  2311. if (DependSize > sizeof(WCHAR)) {
  2312. //
  2313. // There is at least one dependency entry.
  2314. //
  2315. Ptr = (LPSTR) lpDependencies;
  2316. //
  2317. // Convert each dependency into Unicode, and append it to the
  2318. // DependBuffer.
  2319. //
  2320. while (*Ptr != 0) {
  2321. LPWSTR ConvertedDependency = NULL;
  2322. if (! ScConvertToUnicode(&ConvertedDependency, Ptr)) {
  2323. SCC_LOG0(ERROR,
  2324. "CreateServiceA: convert dependency to Unicode failed\n");
  2325. status = ERROR_NOT_ENOUGH_MEMORY;
  2326. goto CleanExit;
  2327. }
  2328. ScAddWStrToWStrArray(DependBuffer, ConvertedDependency);
  2329. (void) LocalFree(ConvertedDependency);
  2330. Ptr = ScNextAStrArrayEntry(Ptr);
  2331. }
  2332. }
  2333. }
  2334. status = RCreateServiceA (
  2335. (SC_RPC_HANDLE)hSCManager,
  2336. (LPSTR) lpServiceName,
  2337. (LPSTR) lpDisplayName,
  2338. dwDesiredAccess,
  2339. dwServiceType,
  2340. dwStartType,
  2341. dwErrorControl,
  2342. (LPSTR) lpBinaryPathName,
  2343. (LPSTR) lpLoadOrderGroup,
  2344. lpdwTagId,
  2345. (LPBYTE) DependBuffer,
  2346. DependSize,
  2347. (LPSTR) lpServiceStartName,
  2348. EncryptedPassword,
  2349. PasswordSize,
  2350. &hService);
  2351. }
  2352. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2353. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2354. }
  2355. RpcEndExcept
  2356. CleanExit:
  2357. if (DependBuffer != NULL) {
  2358. (void) LocalFree(DependBuffer);
  2359. }
  2360. if (EncryptedPassword != NULL) {
  2361. (void) LocalFree(EncryptedPassword);
  2362. }
  2363. if (status != NO_ERROR){
  2364. SetLastError(status);
  2365. return(NULL);
  2366. }
  2367. return (SC_HANDLE)hService;
  2368. }
  2369. SC_HANDLE
  2370. WINAPI
  2371. CreateServiceW(
  2372. IN SC_HANDLE hSCManager,
  2373. IN LPCWSTR lpServiceName,
  2374. IN LPCWSTR lpDisplayName,
  2375. IN DWORD dwDesiredAccess,
  2376. IN DWORD dwServiceType,
  2377. IN DWORD dwStartType,
  2378. IN DWORD dwErrorControl,
  2379. IN LPCWSTR lpBinaryPathName,
  2380. IN LPCWSTR lpLoadOrderGroup,
  2381. OUT LPDWORD lpdwTagId,
  2382. IN LPCWSTR lpDependencies,
  2383. IN LPCWSTR lpServiceStartName,
  2384. IN LPCWSTR lpPassword
  2385. )
  2386. /*++
  2387. Routine Description:
  2388. see CreateServiceA
  2389. Arguments:
  2390. Return Value:
  2391. Note:
  2392. --*/
  2393. {
  2394. DWORD status;
  2395. SC_RPC_HANDLE hService = NULL;
  2396. LPBYTE EncryptedPassword = NULL;
  2397. DWORD PasswordSize = 0;
  2398. DWORD DependSize = 0;
  2399. RpcTryExcept {
  2400. if (ARGUMENT_PRESENT(lpPassword)) {
  2401. status = ScEncryptPassword(
  2402. (SC_RPC_HANDLE)hSCManager,
  2403. (LPWSTR) lpPassword,
  2404. &EncryptedPassword,
  2405. &PasswordSize
  2406. );
  2407. if (status != NO_ERROR) {
  2408. SCC_LOG0(ERROR,"CreateServiceW: ScEncryptPassword failed\n");
  2409. SetLastError(status);
  2410. return NULL;
  2411. }
  2412. }
  2413. if (ARGUMENT_PRESENT(lpDependencies)) {
  2414. DependSize = ScWStrArraySize((LPWSTR) lpDependencies);
  2415. }
  2416. status = RCreateServiceW (
  2417. (SC_RPC_HANDLE)hSCManager,
  2418. (LPWSTR) lpServiceName,
  2419. (LPWSTR) lpDisplayName,
  2420. dwDesiredAccess,
  2421. dwServiceType,
  2422. dwStartType,
  2423. dwErrorControl,
  2424. (LPWSTR) lpBinaryPathName,
  2425. (LPWSTR) lpLoadOrderGroup,
  2426. lpdwTagId,
  2427. (LPBYTE) lpDependencies,
  2428. DependSize,
  2429. (LPWSTR) lpServiceStartName,
  2430. EncryptedPassword,
  2431. PasswordSize,
  2432. &hService);
  2433. }
  2434. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2435. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2436. }
  2437. RpcEndExcept
  2438. if (EncryptedPassword != NULL) {
  2439. LocalFree(EncryptedPassword);
  2440. }
  2441. if (status != NO_ERROR){
  2442. SetLastError(status);
  2443. return NULL;
  2444. }
  2445. return (SC_HANDLE)hService;
  2446. }
  2447. BOOL
  2448. WINAPI
  2449. DeleteService(
  2450. IN SC_HANDLE hService
  2451. )
  2452. /*++
  2453. Routine Description:
  2454. This is the DLL entry point for the DeleteService function.
  2455. DeleteService removes the service from the Service Control
  2456. Manager's database.
  2457. Arguments:
  2458. hService - Handle obtained from a previous CreateService or
  2459. OpenService call.
  2460. Return Value:
  2461. Note:
  2462. --*/
  2463. {
  2464. DWORD status;
  2465. SCC_LOG1(TRACE,
  2466. "---------DeleteService called (%ws)\n",
  2467. GetCommandLineW());
  2468. RpcTryExcept {
  2469. status = RDeleteService ((SC_RPC_HANDLE)hService);
  2470. }
  2471. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2472. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2473. }
  2474. RpcEndExcept
  2475. if (status != NO_ERROR){
  2476. SCC_LOG2(TRACE,
  2477. "---------DeleteService FAILED, %ld (%ws)\n",
  2478. status,
  2479. GetCommandLineW());
  2480. SetLastError(status);
  2481. return(FALSE);
  2482. }
  2483. SCC_LOG1(TRACE,
  2484. "---------DeleteService SUCCESS (%ws)\n",
  2485. GetCommandLineW());
  2486. return TRUE;
  2487. }
  2488. BOOL
  2489. WINAPI
  2490. EnumDependentServicesA(
  2491. IN SC_HANDLE hService,
  2492. IN DWORD dwServiceState,
  2493. OUT LPENUM_SERVICE_STATUSA lpServices,
  2494. IN DWORD cbBufSize,
  2495. OUT LPDWORD pcbBytesNeeded,
  2496. OUT LPDWORD lpServicesReturned
  2497. )
  2498. /*++
  2499. Routine Description:
  2500. This function lists the services which depend on the specified
  2501. service to be running before they can run. The returned
  2502. services entries are ordered in the reverse order of start
  2503. dependencies with group order taken into account. Services can
  2504. be stopped in the proper order based on the order of entries
  2505. written to the output buffer.
  2506. Arguments:
  2507. hService - Handle obtained from a previous OpenService call.
  2508. dwServiceState - Value to select the services to enumerate based on
  2509. the running state.
  2510. lpServices - A pointer to a buffer to receive an array of service
  2511. entries; each entry is the ENUM_SERVICE_STATUS information
  2512. structure. The services returned in the buffer is ordered by
  2513. the reverse dependency order.
  2514. cbBufSize - Size of the buffer in bytes pointed to by lpServices.
  2515. pcbBytesNeeded - A pointer to a variable to receive the number of
  2516. bytes needed to fit the remaining service entries.
  2517. lpServicesReturned - A pointer to a variable to receive the number
  2518. of service entries returned.
  2519. Return Value:
  2520. TRUE - if all Services are successfully written into the supplied
  2521. output buffer.
  2522. FALSE - If an error has occured - Use GetLastError to determine the
  2523. cause of the failure.
  2524. --*/
  2525. {
  2526. DWORD status;
  2527. LPENUM_SERVICE_STATUSA pEnumBuf;
  2528. ENUM_SERVICE_STATUSA enumBuf;
  2529. DWORD tempBufSize;
  2530. tempBufSize = cbBufSize;
  2531. //
  2532. // Create a dummy buffer that is at least the size of the structure.
  2533. // This way RPC should at least send the request to the server side.
  2534. // The server should recognize that the buffer is to small for any
  2535. // strings, and put the correct size in the BytesNeeded parameter,
  2536. // and fail the call.
  2537. //
  2538. if (cbBufSize < sizeof(ENUM_SERVICE_STATUSA) || (lpServices == NULL)) {
  2539. pEnumBuf = &enumBuf;
  2540. tempBufSize = sizeof(ENUM_SERVICE_STATUSA);
  2541. }
  2542. else {
  2543. pEnumBuf = lpServices;
  2544. }
  2545. RpcTryExcept {
  2546. status = REnumDependentServicesA(
  2547. (SC_RPC_HANDLE)hService,
  2548. dwServiceState,
  2549. (LPBYTE)pEnumBuf,
  2550. tempBufSize,
  2551. pcbBytesNeeded,
  2552. lpServicesReturned);
  2553. }
  2554. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2555. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2556. }
  2557. RpcEndExcept
  2558. //
  2559. // If data is returned, convert Offsets in the Enum buffer to pointers.
  2560. //
  2561. if ((status == NO_ERROR) || (status == ERROR_MORE_DATA))
  2562. {
  2563. if ((*lpServicesReturned) > 0)
  2564. {
  2565. #ifdef _WIN64
  2566. DWORD dwError;
  2567. if (!ScConvertOffsets64(SC_API_ENUM_DEPEND_A,
  2568. NULL, // no hSCManager
  2569. 0, // no service type
  2570. 0, // no service state
  2571. (LPBYTE) lpServices,
  2572. cbBufSize,
  2573. pcbBytesNeeded,
  2574. lpServicesReturned,
  2575. NULL, // no old resume index
  2576. NULL, // no group name
  2577. &dwError))
  2578. {
  2579. status = dwError;
  2580. }
  2581. }
  2582. //
  2583. // Scale required size up to the minimum size guaranteed to
  2584. // succeed with 64-bit structures.
  2585. //
  2586. *pcbBytesNeeded = *pcbBytesNeeded
  2587. * sizeof(ENUM_SERVICE_STATUSA)
  2588. / sizeof(ENUM_SERVICE_STATUS_WOW64);
  2589. #else // ndef _WIN64
  2590. ScConvertOffsetsA(lpServices, *lpServicesReturned);
  2591. }
  2592. #endif // _WIN64
  2593. }
  2594. if (status != NO_ERROR)
  2595. {
  2596. SetLastError(status);
  2597. return(FALSE);
  2598. }
  2599. return(TRUE);
  2600. }
  2601. BOOL
  2602. WINAPI
  2603. EnumDependentServicesW(
  2604. IN SC_HANDLE hService,
  2605. IN DWORD dwServiceState,
  2606. OUT LPENUM_SERVICE_STATUSW lpServices,
  2607. IN DWORD cbBufSize,
  2608. OUT LPDWORD pcbBytesNeeded,
  2609. OUT LPDWORD lpServicesReturned
  2610. )
  2611. /*++
  2612. Routine Description:
  2613. This function lists the services which depend on the specified
  2614. service to be running before they can run. The returned
  2615. services entries are ordered in the reverse order of start
  2616. dependencies with group order taken into account. Services can
  2617. be stopped in the proper order based on the order of entries
  2618. written to the output buffer.
  2619. Arguments:
  2620. hService - Handle obtained from a previous OpenService call.
  2621. dwServiceState - Value to select the services to enumerate based on
  2622. the running state.
  2623. lpServices - A pointer to a buffer to receive an array of service
  2624. entries; each entry is the ENUM_SERVICE_STATUS information
  2625. structure. The services returned in the buffer is ordered by
  2626. the reverse dependency order.
  2627. cbBufSize - Size of the buffer in bytes pointed to by lpServices.
  2628. pcbBytesNeeded - A pointer to a variable to receive the number of
  2629. bytes needed to fit the remaining service entries.
  2630. lpServicesReturned - A pointer to a variable to receive the number
  2631. of service entries returned.
  2632. Return Value:
  2633. TRUE - if all Services are successfully written into the supplied
  2634. output buffer.
  2635. FALSE - If an error has occured - Use GetLastError to determine the
  2636. cause of the failure.
  2637. --*/
  2638. {
  2639. DWORD status;
  2640. LPENUM_SERVICE_STATUSW pEnumBuf;
  2641. ENUM_SERVICE_STATUSW enumBuf;
  2642. DWORD tempBufSize;
  2643. tempBufSize = cbBufSize;
  2644. //
  2645. // Create a dummy buffer that is at least the size of the structure.
  2646. // This way RPC should at least send the request to the server side.
  2647. // The server should recognize that the buffer is to small for any
  2648. // strings, and put the correct size in the BytesNeeded parameter,
  2649. // and fail the call.
  2650. //
  2651. if (cbBufSize < sizeof(ENUM_SERVICE_STATUSW) || (lpServices == NULL)) {
  2652. pEnumBuf = &enumBuf;
  2653. tempBufSize = sizeof(ENUM_SERVICE_STATUSW);
  2654. }
  2655. else {
  2656. pEnumBuf = lpServices;
  2657. }
  2658. RpcTryExcept {
  2659. status = REnumDependentServicesW(
  2660. (SC_RPC_HANDLE)hService,
  2661. dwServiceState,
  2662. (LPBYTE)pEnumBuf,
  2663. tempBufSize,
  2664. pcbBytesNeeded,
  2665. lpServicesReturned);
  2666. }
  2667. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2668. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2669. }
  2670. RpcEndExcept
  2671. //
  2672. // If data is returned, convert Offsets in the Enum buffer to pointers.
  2673. //
  2674. if ((status == NO_ERROR) || (status == ERROR_MORE_DATA))
  2675. {
  2676. if ((*lpServicesReturned) > 0)
  2677. {
  2678. #ifdef _WIN64
  2679. DWORD dwError;
  2680. if (!ScConvertOffsets64(SC_API_ENUM_DEPEND_W,
  2681. NULL, // no hSCManager
  2682. 0, // no service type
  2683. 0, // no service state
  2684. (LPBYTE) lpServices,
  2685. cbBufSize,
  2686. pcbBytesNeeded,
  2687. lpServicesReturned,
  2688. NULL, // no old resume index
  2689. NULL, // no group name
  2690. &dwError))
  2691. {
  2692. status = dwError;
  2693. }
  2694. }
  2695. //
  2696. // Scale required size up to the minimum size guaranteed to
  2697. // succeed with 64-bit structures.
  2698. //
  2699. *pcbBytesNeeded = *pcbBytesNeeded
  2700. * sizeof(ENUM_SERVICE_STATUSA)
  2701. / sizeof(ENUM_SERVICE_STATUS_WOW64);
  2702. #else // ndef _WIN64
  2703. ScConvertOffsetsW(lpServices, *lpServicesReturned);
  2704. }
  2705. #endif // _WIN64
  2706. }
  2707. if (status != NO_ERROR)
  2708. {
  2709. SetLastError(status);
  2710. return(FALSE);
  2711. }
  2712. return(TRUE);
  2713. }
  2714. BOOL
  2715. WINAPI
  2716. GetServiceDisplayNameA(
  2717. SC_HANDLE hSCManager,
  2718. LPCSTR lpServiceName,
  2719. LPSTR lpDisplayName,
  2720. LPDWORD lpcchBuffer
  2721. )
  2722. /*++
  2723. Routine Description:
  2724. This function returns the display name for a service that is identified
  2725. by its key name (ServiceName).
  2726. Arguments:
  2727. hSCManager - This is the handle to the Service Controller Manager that
  2728. is expected to return the display name.
  2729. lpServiceName - This is the ServiceName (which is actually a key
  2730. name) that identifies the service.
  2731. lpDisplayName - This is a pointer to a buffer that is to receive the
  2732. DisplayName string.
  2733. lpcchBuffer - This is a pointer to the size (in characters) of the
  2734. buffer that is to receive the DisplayName string. If the buffer
  2735. is not large enough to receive the entire string, then the required
  2736. buffer size is returned in this location. (NOTE: Ansi Characters,
  2737. including DBCS, are assumed to be 8 bits).
  2738. Return Value:
  2739. --*/
  2740. {
  2741. DWORD status;
  2742. LPSTR bufPtr;
  2743. CHAR tempString[] = "";
  2744. //
  2745. // Create a dummy buffer that is at least the size of a CHAR.
  2746. // This way RPC should at least send the request to the server side.
  2747. // The server should recognize that the buffer is to small for any
  2748. // strings, and put the correct size in the BytesNeeded parameter,
  2749. // and fail the call.
  2750. //
  2751. RpcTryExcept {
  2752. if ((*lpcchBuffer < sizeof(CHAR)) || (lpDisplayName == NULL)){
  2753. bufPtr = tempString;
  2754. *lpcchBuffer = sizeof(CHAR);
  2755. }
  2756. else {
  2757. bufPtr = (LPSTR)lpDisplayName;
  2758. }
  2759. status = RGetServiceDisplayNameA(
  2760. (SC_RPC_HANDLE)hSCManager,
  2761. (LPSTR)lpServiceName,
  2762. bufPtr,
  2763. lpcchBuffer);
  2764. }
  2765. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2766. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2767. }
  2768. RpcEndExcept
  2769. if (status != NO_ERROR) {
  2770. SetLastError(status);
  2771. return(FALSE);
  2772. }
  2773. return(TRUE);
  2774. }
  2775. BOOL
  2776. WINAPI
  2777. GetServiceDisplayNameW(
  2778. SC_HANDLE hSCManager,
  2779. LPCWSTR lpServiceName,
  2780. LPWSTR lpDisplayName,
  2781. LPDWORD lpcchBuffer
  2782. )
  2783. /*++
  2784. Routine Description:
  2785. Arguments:
  2786. Return Value:
  2787. --*/
  2788. {
  2789. DWORD status;
  2790. LPWSTR bufPtr;
  2791. WCHAR tempString[]=L"";
  2792. //
  2793. // Create a dummy buffer that is at least the size of a WCHAR.
  2794. // This way RPC should at least send the request to the server side.
  2795. // The server should recognize that the buffer is to small for any
  2796. // strings, and put the correct size in the BytesNeeded parameter,
  2797. // and fail the call.
  2798. //
  2799. RpcTryExcept {
  2800. if ((*lpcchBuffer < sizeof(WCHAR)) || (lpDisplayName == NULL)) {
  2801. bufPtr = tempString;
  2802. *lpcchBuffer = sizeof(WCHAR);
  2803. }
  2804. else {
  2805. bufPtr = (LPWSTR)lpDisplayName;
  2806. }
  2807. status = RGetServiceDisplayNameW(
  2808. (SC_RPC_HANDLE)hSCManager,
  2809. (LPWSTR)lpServiceName,
  2810. bufPtr,
  2811. lpcchBuffer);
  2812. }
  2813. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2814. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2815. }
  2816. RpcEndExcept
  2817. if (status != NO_ERROR) {
  2818. SetLastError(status);
  2819. return(FALSE);
  2820. }
  2821. return(TRUE);
  2822. }
  2823. BOOL
  2824. WINAPI
  2825. GetServiceKeyNameA(
  2826. SC_HANDLE hSCManager,
  2827. LPCSTR lpDisplayName,
  2828. LPSTR lpServiceName,
  2829. LPDWORD lpcchBuffer
  2830. )
  2831. /*++
  2832. Routine Description:
  2833. Arguments:
  2834. hSCManager - This is the handle to the Service Controller Manager that
  2835. is expected to return the service name (key name).
  2836. lpServiceName - This is the Service Display Name that identifies
  2837. the service.
  2838. lpServiceName - This is a pointer to a buffer that is to receive the
  2839. Service Key Name string.
  2840. lpcchBuffer - This is a pointer to the size of the buffer that is
  2841. to receive the Service Key Name string. If the buffer is not large
  2842. enough to receive the entire string, then the required buffer size
  2843. is returned in this location.
  2844. Return Value:
  2845. --*/
  2846. {
  2847. DWORD status;
  2848. LPSTR bufPtr;
  2849. CHAR tempString[]="";
  2850. //
  2851. // Create a dummy buffer that is at least the size of a CHAR.
  2852. // This way RPC should at least send the request to the server side.
  2853. // The server should recognize that the buffer is to small for any
  2854. // strings, and put the correct size in the BytesNeeded parameter,
  2855. // and fail the call.
  2856. //
  2857. RpcTryExcept {
  2858. if ((*lpcchBuffer < sizeof(CHAR)) || (lpServiceName == NULL)) {
  2859. bufPtr = tempString;
  2860. *lpcchBuffer = sizeof(CHAR);
  2861. }
  2862. else {
  2863. bufPtr = (LPSTR)lpServiceName;
  2864. }
  2865. status = RGetServiceKeyNameA(
  2866. (SC_RPC_HANDLE)hSCManager,
  2867. (LPSTR)lpDisplayName,
  2868. bufPtr,
  2869. lpcchBuffer);
  2870. }
  2871. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2872. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2873. }
  2874. RpcEndExcept
  2875. if (status != NO_ERROR) {
  2876. SetLastError(status);
  2877. return(FALSE);
  2878. }
  2879. return(TRUE);
  2880. }
  2881. BOOL
  2882. WINAPI
  2883. GetServiceKeyNameW(
  2884. SC_HANDLE hSCManager,
  2885. LPCWSTR lpDisplayName,
  2886. LPWSTR lpServiceName,
  2887. LPDWORD lpcchBuffer
  2888. )
  2889. /*++
  2890. Routine Description:
  2891. Arguments:
  2892. Return Value:
  2893. --*/
  2894. {
  2895. DWORD status = NO_ERROR;
  2896. LPWSTR bufPtr;
  2897. WCHAR tempString[]=L"";
  2898. //
  2899. // Create a dummy buffer that is at least the size of a WCHAR.
  2900. // This way RPC should at least send the request to the server side.
  2901. // The server should recognize that the buffer is to small for any
  2902. // strings, and put the correct size in the BytesNeeded parameter,
  2903. // and fail the call.
  2904. //
  2905. RpcTryExcept {
  2906. if ((*lpcchBuffer < sizeof(WCHAR)) || (lpServiceName == NULL)) {
  2907. bufPtr = tempString;
  2908. *lpcchBuffer = sizeof(WCHAR);
  2909. }
  2910. else {
  2911. bufPtr = (LPWSTR)lpServiceName;
  2912. }
  2913. status = RGetServiceKeyNameW(
  2914. (SC_RPC_HANDLE)hSCManager,
  2915. (LPWSTR)lpDisplayName,
  2916. bufPtr,
  2917. lpcchBuffer);
  2918. }
  2919. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2920. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2921. }
  2922. RpcEndExcept
  2923. if (status != NO_ERROR) {
  2924. SetLastError(status);
  2925. return(FALSE);
  2926. }
  2927. return(TRUE);
  2928. }
  2929. SC_LOCK
  2930. WINAPI
  2931. LockServiceDatabase(
  2932. IN SC_HANDLE hSCManager
  2933. )
  2934. /*++
  2935. Routine Description:
  2936. This is the DLL entry point for the LockServiceDatabase function.
  2937. This function acquires a lock on the database that was opened from
  2938. a previous OpenSCManager call. There can only be one lock
  2939. outstanding on a database for a given time.
  2940. Arguments:
  2941. hSCManager - Handle obtained from a previous OpenSCManager call
  2942. which specifies the database to lock.
  2943. Return Value:
  2944. --*/
  2945. {
  2946. DWORD status;
  2947. SC_RPC_LOCK lock = NULL;
  2948. RpcTryExcept {
  2949. status = RLockServiceDatabase(
  2950. (SC_RPC_HANDLE)hSCManager,
  2951. &lock);
  2952. }
  2953. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  2954. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  2955. }
  2956. RpcEndExcept
  2957. if (status != NO_ERROR){
  2958. SetLastError(status);
  2959. return(NULL);
  2960. }
  2961. return((SC_LOCK)lock);
  2962. }
  2963. BOOL
  2964. WINAPI
  2965. QueryServiceConfigA(
  2966. IN SC_HANDLE hService,
  2967. OUT LPQUERY_SERVICE_CONFIGA lpServiceConfig,
  2968. IN DWORD cbBufSize,
  2969. OUT LPDWORD pcbBytesNeeded
  2970. )
  2971. /*++
  2972. Routine Description:
  2973. This is the DLL entry point for the QueryServiceConfig function.
  2974. QueryServiceConfig obtains the service configuration information
  2975. stored in the Service Control Manager database. This configuration
  2976. information was first set in the database via the CreateService API,
  2977. and may have been updated via the ChangeServiceConfig API.
  2978. Arguments:
  2979. hService - Handle obtained from a previous CreateService or
  2980. OpenService call.
  2981. lpServiceConfig - A pointer to a buffer to receive a
  2982. QUERY_SERVICE_CONFIG information structure.
  2983. cbBufSize - Size of the buffer in bytes pointed to by lpServiceConfig.
  2984. pcbBytesNeeded - A pointer to a variable to receive the number of
  2985. bytes needed to fit the entire QUERY_SERVICE_CONFIG information
  2986. structure.
  2987. Return Value:
  2988. Note:
  2989. --*/
  2990. {
  2991. DWORD status;
  2992. LPSTR pDepend;
  2993. LPQUERY_SERVICE_CONFIGA pConfigBuf;
  2994. QUERY_SERVICE_CONFIGA configBuf;
  2995. DWORD tempBufSize;
  2996. tempBufSize = cbBufSize;
  2997. //
  2998. // Create a dummy buffer that is at least the size of the structure.
  2999. // This way RPC should at least send the request to the server side.
  3000. // The server should recognize that the buffer is to small for any
  3001. // strings, and put the correct size in the BytesNeeded parameter,
  3002. // and fail the call.
  3003. //
  3004. if (cbBufSize < sizeof(QUERY_SERVICE_CONFIGA))
  3005. {
  3006. pConfigBuf = &configBuf;
  3007. tempBufSize = sizeof(QUERY_SERVICE_CONFIGA);
  3008. }
  3009. else
  3010. {
  3011. pConfigBuf = lpServiceConfig;
  3012. }
  3013. RpcTryExcept
  3014. {
  3015. status = RQueryServiceConfigA(
  3016. (SC_RPC_HANDLE)hService,
  3017. pConfigBuf,
  3018. tempBufSize,
  3019. pcbBytesNeeded);
  3020. }
  3021. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3022. {
  3023. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3024. }
  3025. RpcEndExcept
  3026. if (status != NO_ERROR)
  3027. {
  3028. #ifdef _WIN64
  3029. //
  3030. // pcbBytesNeeded isn't filled in if the byte count is too
  3031. // small (returned when the buffer size is large enough to
  3032. // hold the 32-bit structure but too small to hold the
  3033. // 64-bit structure. Get the necessary (32-bit) size.
  3034. //
  3035. if (status == RPC_X_BYTE_COUNT_TOO_SMALL)
  3036. {
  3037. RpcTryExcept
  3038. {
  3039. status = RQueryServiceConfigA(
  3040. (SC_RPC_HANDLE)hService,
  3041. pConfigBuf,
  3042. sizeof(QUERY_SERVICE_CONFIGA),
  3043. pcbBytesNeeded);
  3044. }
  3045. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3046. {
  3047. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3048. }
  3049. RpcEndExcept
  3050. }
  3051. //
  3052. // Since the ACF file specifies byte_count for this API, we're
  3053. // responsible for managing the count of bytes needed by the
  3054. // caller. For 64-bit clients calling 32-bit servers, the
  3055. // returned buffer size is too small because of differing
  3056. // pointer sizes. Add on the minimum number of bytes that
  3057. // will guarantee enough space in the buffer for the next
  3058. // call.
  3059. //
  3060. if (status == ERROR_INSUFFICIENT_BUFFER)
  3061. {
  3062. //
  3063. // 5 embedded pointers in the structure and max
  3064. // space required for alignment.
  3065. //
  3066. *pcbBytesNeeded += 5 * (sizeof(PVOID) - sizeof(ULONG) + sizeof(PVOID));
  3067. }
  3068. #endif // _WIN64
  3069. SetLastError(status);
  3070. return(FALSE);
  3071. }
  3072. else
  3073. {
  3074. //
  3075. // Replace the '/' separator characters by NULLs. We used
  3076. // separator characters in the double NULL terminated set of
  3077. // strings so that RPC could treat it as a single string.
  3078. //
  3079. if ((pDepend = lpServiceConfig->lpDependencies) != NULL) {
  3080. while (*pDepend != '\0') {
  3081. if (*pDepend == '/') {
  3082. *pDepend = '\0';
  3083. }
  3084. pDepend++;
  3085. }
  3086. }
  3087. }
  3088. return(TRUE);
  3089. }
  3090. BOOL
  3091. WINAPI
  3092. QueryServiceConfigW(
  3093. IN SC_HANDLE hService,
  3094. OUT LPQUERY_SERVICE_CONFIGW lpServiceConfig,
  3095. IN DWORD cbBufSize,
  3096. OUT LPDWORD pcbBytesNeeded
  3097. )
  3098. /*++
  3099. Routine Description:
  3100. see QueryServiceConfigA
  3101. Arguments:
  3102. Return Value:
  3103. Note:
  3104. --*/
  3105. {
  3106. DWORD status;
  3107. LPWSTR pDepend;
  3108. LPQUERY_SERVICE_CONFIGW pConfigBuf;
  3109. QUERY_SERVICE_CONFIGW configBuf;
  3110. DWORD tempBufSize;
  3111. tempBufSize = cbBufSize;
  3112. //
  3113. // Create a dummy buffer that is at least the size of the structure.
  3114. // This way RPC should at least send the request to the server side.
  3115. // The server should recognize that the buffer is to small for any
  3116. // strings, and put the correct size in the BytesNeeded parameter,
  3117. // and fail the call.
  3118. //
  3119. if (cbBufSize < sizeof(QUERY_SERVICE_CONFIGW))
  3120. {
  3121. pConfigBuf = &configBuf;
  3122. tempBufSize = sizeof(QUERY_SERVICE_CONFIGW);
  3123. }
  3124. else
  3125. {
  3126. pConfigBuf = lpServiceConfig;
  3127. }
  3128. RpcTryExcept
  3129. {
  3130. status = RQueryServiceConfigW(
  3131. (SC_RPC_HANDLE)hService,
  3132. pConfigBuf,
  3133. tempBufSize,
  3134. pcbBytesNeeded);
  3135. }
  3136. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3137. {
  3138. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3139. }
  3140. RpcEndExcept
  3141. if (status != NO_ERROR)
  3142. {
  3143. #ifdef _WIN64
  3144. //
  3145. // pcbBytesNeeded isn't filled in if the byte count is too
  3146. // small (returned when the buffer size is large enough to
  3147. // hold the 32-bit structure but too small to hold the
  3148. // 64-bit structure. Get the necessary (32-bit) size.
  3149. //
  3150. if (status == RPC_X_BYTE_COUNT_TOO_SMALL)
  3151. {
  3152. RpcTryExcept
  3153. {
  3154. status = RQueryServiceConfigW(
  3155. (SC_RPC_HANDLE)hService,
  3156. pConfigBuf,
  3157. sizeof(QUERY_SERVICE_CONFIGW),
  3158. pcbBytesNeeded);
  3159. }
  3160. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3161. {
  3162. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3163. }
  3164. RpcEndExcept
  3165. }
  3166. //
  3167. // Since the ACF file specifies byte_count for this API, we're
  3168. // responsible for managing the count of bytes needed by the
  3169. // caller. For 64-bit clients calling 32-bit servers, the
  3170. // returned buffer size is too small because of differing
  3171. // pointer sizes. Add on the minimum number of bytes that
  3172. // will guarantee enough space in the buffer for the next
  3173. // call.
  3174. //
  3175. if (status == ERROR_INSUFFICIENT_BUFFER)
  3176. {
  3177. //
  3178. // 5 embedded pointers in the structure and max
  3179. // space required for alignment.
  3180. //
  3181. *pcbBytesNeeded += 5 * (sizeof(PVOID) - sizeof(ULONG) + sizeof(PVOID));
  3182. }
  3183. #endif // _WIN64
  3184. SetLastError(status);
  3185. return(FALSE);
  3186. }
  3187. else
  3188. {
  3189. //
  3190. // Replace the '/' separator characters by NULLs. We used
  3191. // separator characters in the double NULL terminated set of
  3192. // strings so that RPC could treat it as a single string.
  3193. //
  3194. if ((pDepend = lpServiceConfig->lpDependencies) != NULL) {
  3195. while (*pDepend != L'\0') {
  3196. if (*pDepend == L'/') {
  3197. *pDepend = L'\0';
  3198. }
  3199. pDepend++;
  3200. }
  3201. }
  3202. }
  3203. return(TRUE);
  3204. }
  3205. BOOL
  3206. WINAPI
  3207. QueryServiceConfig2A(
  3208. IN SC_HANDLE hService,
  3209. IN DWORD dwInfoLevel,
  3210. OUT LPBYTE lpBuffer,
  3211. IN DWORD cbBufSize,
  3212. OUT LPDWORD pcbBytesNeeded
  3213. )
  3214. /*++
  3215. Routine Description:
  3216. Arguments:
  3217. Return Value:
  3218. Note:
  3219. --*/
  3220. {
  3221. DWORD status;
  3222. LPBYTE lpTempBuffer;
  3223. SERVICE_DESCRIPTIONA sdDescription;
  3224. SERVICE_FAILURE_ACTIONSA sfaActions;
  3225. DWORD tempBufSize;
  3226. BOOL fDummyBuffer = FALSE;
  3227. tempBufSize = cbBufSize;
  3228. lpTempBuffer = lpBuffer;
  3229. //
  3230. // Create a dummy buffer that is at least the size of the structure.
  3231. // This way RPC should at least send the request to the server side.
  3232. // The server should recognize that the buffer is to small for any
  3233. // strings, put the correct size in the BytesNeeded parameter, and
  3234. // fail the call.
  3235. //
  3236. switch(dwInfoLevel) {
  3237. case SERVICE_CONFIG_DESCRIPTION:
  3238. if (cbBufSize < sizeof(SERVICE_DESCRIPTION_WOW64)) {
  3239. lpTempBuffer = (LPBYTE) &sdDescription;
  3240. tempBufSize = sizeof(SERVICE_DESCRIPTION_WOW64);
  3241. fDummyBuffer = TRUE;
  3242. }
  3243. break;
  3244. case SERVICE_CONFIG_FAILURE_ACTIONS:
  3245. if (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONS_WOW64)) {
  3246. lpTempBuffer = (LPBYTE) &sfaActions;
  3247. tempBufSize = sizeof(SERVICE_FAILURE_ACTIONS_WOW64);
  3248. fDummyBuffer = TRUE;
  3249. }
  3250. break;
  3251. default:
  3252. SetLastError(ERROR_INVALID_LEVEL);
  3253. return FALSE;
  3254. }
  3255. RpcTryExcept
  3256. {
  3257. status = RQueryServiceConfig2A(
  3258. (SC_RPC_HANDLE) hService,
  3259. dwInfoLevel,
  3260. lpTempBuffer,
  3261. tempBufSize,
  3262. pcbBytesNeeded);
  3263. }
  3264. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3265. {
  3266. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3267. }
  3268. RpcEndExcept
  3269. #ifdef _WIN64
  3270. //
  3271. // 64-bit needs more space than the 32-bit-oriented structure
  3272. // coming from the server. Make sure we have it. Do this
  3273. // even if fDummyBuffer is TRUE since ScConvertOffsets64 will
  3274. // update *pcbBytesNeeded appropriately.
  3275. //
  3276. if (status == NO_ERROR || status == ERROR_INSUFFICIENT_BUFFER)
  3277. {
  3278. if (!ScConvertOffsets64(dwInfoLevel == SERVICE_CONFIG_DESCRIPTION ?
  3279. SC_API_QUERY_DESCRIPTION_A :
  3280. SC_API_QUERY_FAILURE_ACTIONS_A,
  3281. NULL,
  3282. 0,
  3283. 0,
  3284. lpTempBuffer,
  3285. tempBufSize,
  3286. pcbBytesNeeded,
  3287. NULL,
  3288. NULL,
  3289. NULL,
  3290. NULL))
  3291. {
  3292. status = ERROR_INSUFFICIENT_BUFFER;
  3293. }
  3294. }
  3295. #endif // _WIN64
  3296. if (status != NO_ERROR)
  3297. {
  3298. SetLastError(status);
  3299. return FALSE;
  3300. }
  3301. //
  3302. // Catch the case where the RPC call succeeded even though we used
  3303. // a dummy buffer (e.g., SERVICE_FAILURE_ACTIONS on a service with
  3304. // no command line or reboot message). Note that the server side
  3305. // of this API fills in pcbBytesNeeded even on success
  3306. //
  3307. if (fDummyBuffer)
  3308. {
  3309. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  3310. return FALSE;
  3311. }
  3312. //
  3313. // Convert offsets to pointers in the returned structure
  3314. //
  3315. switch (dwInfoLevel)
  3316. {
  3317. case SERVICE_CONFIG_DESCRIPTION:
  3318. {
  3319. LPSERVICE_DESCRIPTIONA psd =
  3320. (LPSERVICE_DESCRIPTIONA) lpBuffer;
  3321. if (psd->lpDescription != NULL)
  3322. {
  3323. psd->lpDescription = (LPSTR)
  3324. (lpBuffer + (DWORD)(ULONG_PTR)psd->lpDescription);
  3325. }
  3326. }
  3327. break;
  3328. case SERVICE_CONFIG_FAILURE_ACTIONS:
  3329. {
  3330. LPSERVICE_FAILURE_ACTIONSA psfa =
  3331. (LPSERVICE_FAILURE_ACTIONSA) lpBuffer;
  3332. if (psfa->lpRebootMsg != NULL)
  3333. {
  3334. psfa->lpRebootMsg = (LPSTR)
  3335. (lpBuffer + (DWORD)(ULONG_PTR)psfa->lpRebootMsg);
  3336. }
  3337. if (psfa->lpCommand != NULL)
  3338. {
  3339. psfa->lpCommand = (LPSTR)
  3340. (lpBuffer + (DWORD)(ULONG_PTR)psfa->lpCommand);
  3341. }
  3342. if (psfa->lpsaActions != NULL)
  3343. {
  3344. psfa->lpsaActions = (SC_ACTION *)
  3345. (lpBuffer + (DWORD)(ULONG_PTR)psfa->lpsaActions);
  3346. }
  3347. }
  3348. break;
  3349. }
  3350. return TRUE;
  3351. }
  3352. BOOL
  3353. WINAPI
  3354. QueryServiceConfig2W(
  3355. IN SC_HANDLE hService,
  3356. IN DWORD dwInfoLevel,
  3357. OUT LPBYTE lpBuffer,
  3358. IN DWORD cbBufSize,
  3359. OUT LPDWORD pcbBytesNeeded
  3360. )
  3361. /*++
  3362. Routine Description:
  3363. Arguments:
  3364. Return Value:
  3365. Note:
  3366. --*/
  3367. {
  3368. DWORD status;
  3369. LPBYTE lpTempBuffer;
  3370. SERVICE_DESCRIPTIONW sdDescription;
  3371. SERVICE_FAILURE_ACTIONSW sfaActions;
  3372. DWORD tempBufSize;
  3373. BOOL fDummyBuffer = FALSE;
  3374. tempBufSize = cbBufSize;
  3375. lpTempBuffer = lpBuffer;
  3376. //
  3377. // Create a dummy buffer that is at least the size of the structure.
  3378. // This way RPC should at least send the request to the server side.
  3379. // The server should recognize that the buffer is to small for any
  3380. // strings, put the correct size in the BytesNeeded parameter, and
  3381. // fail the call.
  3382. //
  3383. switch(dwInfoLevel) {
  3384. case SERVICE_CONFIG_DESCRIPTION:
  3385. if (cbBufSize < sizeof(SERVICE_DESCRIPTIONW)) {
  3386. lpTempBuffer = (LPBYTE) &sdDescription;
  3387. tempBufSize = sizeof(SERVICE_DESCRIPTIONW);
  3388. fDummyBuffer = TRUE;
  3389. }
  3390. break;
  3391. case SERVICE_CONFIG_FAILURE_ACTIONS:
  3392. if (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONSW)) {
  3393. lpTempBuffer = (LPBYTE) &sfaActions;
  3394. tempBufSize = sizeof(SERVICE_FAILURE_ACTIONSW);
  3395. fDummyBuffer = TRUE;
  3396. }
  3397. break;
  3398. default:
  3399. SetLastError(ERROR_INVALID_LEVEL);
  3400. return FALSE;
  3401. }
  3402. RpcTryExcept
  3403. {
  3404. status = RQueryServiceConfig2W(
  3405. (SC_RPC_HANDLE) hService,
  3406. dwInfoLevel,
  3407. lpTempBuffer,
  3408. tempBufSize,
  3409. pcbBytesNeeded);
  3410. }
  3411. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3412. {
  3413. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3414. }
  3415. RpcEndExcept
  3416. #ifdef _WIN64
  3417. //
  3418. // 64-bit needs more space than the 32-bit-oriented structure
  3419. // coming from the server. Make sure we have it. Do this
  3420. // even if fDummyBuffer is TRUE since ScConvertOffsets64 will
  3421. // update *pcbBytesNeeded appropriately.
  3422. //
  3423. if (status == NO_ERROR || status == ERROR_INSUFFICIENT_BUFFER)
  3424. {
  3425. if (!ScConvertOffsets64(dwInfoLevel == SERVICE_CONFIG_DESCRIPTION ?
  3426. SC_API_QUERY_DESCRIPTION_W :
  3427. SC_API_QUERY_FAILURE_ACTIONS_W,
  3428. NULL,
  3429. 0,
  3430. 0,
  3431. lpTempBuffer,
  3432. tempBufSize,
  3433. pcbBytesNeeded,
  3434. NULL,
  3435. NULL,
  3436. NULL,
  3437. NULL))
  3438. {
  3439. status = ERROR_INSUFFICIENT_BUFFER;
  3440. }
  3441. }
  3442. #endif // _WIN64
  3443. if (status != NO_ERROR)
  3444. {
  3445. SetLastError(status);
  3446. return FALSE;
  3447. }
  3448. //
  3449. // Catch the case where the RPC call succeeded even though we used
  3450. // a dummy buffer (e.g., SERVICE_FAILURE_ACTIONS on a service with
  3451. // no command line or reboot message). Note that the server side
  3452. // of this API fills in pcbBytesNeeded even on success
  3453. //
  3454. if (fDummyBuffer)
  3455. {
  3456. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  3457. return FALSE;
  3458. }
  3459. //
  3460. // Convert offsets to pointers in the returned structure
  3461. //
  3462. switch (dwInfoLevel)
  3463. {
  3464. case SERVICE_CONFIG_DESCRIPTION:
  3465. {
  3466. LPSERVICE_DESCRIPTIONW psd =
  3467. (LPSERVICE_DESCRIPTIONW) lpBuffer;
  3468. if (psd->lpDescription != NULL)
  3469. {
  3470. psd->lpDescription = (LPWSTR)
  3471. (lpBuffer + (DWORD)(ULONG_PTR) psd->lpDescription);
  3472. }
  3473. }
  3474. break;
  3475. case SERVICE_CONFIG_FAILURE_ACTIONS:
  3476. {
  3477. LPSERVICE_FAILURE_ACTIONSW psfa =
  3478. (LPSERVICE_FAILURE_ACTIONSW) lpBuffer;
  3479. if (psfa->lpRebootMsg != NULL)
  3480. {
  3481. psfa->lpRebootMsg = (LPWSTR)
  3482. (lpBuffer + (DWORD)(ULONG_PTR) psfa->lpRebootMsg);
  3483. }
  3484. if (psfa->lpCommand != NULL)
  3485. {
  3486. psfa->lpCommand = (LPWSTR)
  3487. (lpBuffer + (DWORD)(ULONG_PTR) psfa->lpCommand);
  3488. }
  3489. if (psfa->lpsaActions != NULL)
  3490. {
  3491. psfa->lpsaActions = (SC_ACTION *)
  3492. (lpBuffer + (DWORD)(ULONG_PTR) psfa->lpsaActions);
  3493. }
  3494. }
  3495. break;
  3496. }
  3497. return TRUE;
  3498. }
  3499. BOOL
  3500. WINAPI
  3501. QueryServiceLockStatusA(
  3502. SC_HANDLE hSCManager,
  3503. LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
  3504. DWORD cbBufSize,
  3505. LPDWORD pcbBytesNeeded
  3506. )
  3507. /*++
  3508. Routine Description:
  3509. This is the DLL entry point for the QueryServiceLockStatus function.
  3510. This function returns lock status information on a Service Control
  3511. Manager database.
  3512. Arguments:
  3513. hSCManager - Handled obtained from a previous call to OpenSCManager
  3514. call.
  3515. lpLockStatus - A pointer to a buffer to receive a
  3516. QUERY_SERVICE_LOCK_STATUS information structure.
  3517. Return Value:
  3518. Note:
  3519. --*/
  3520. {
  3521. DWORD status;
  3522. LPQUERY_SERVICE_LOCK_STATUSA pStatusBuf;
  3523. QUERY_SERVICE_LOCK_STATUSA statusBuf;
  3524. DWORD tempBufSize;
  3525. tempBufSize = cbBufSize;
  3526. //
  3527. // Create a dummy buffer that is at least the size of the structure.
  3528. // This way RPC should at least send the request to the server side.
  3529. // The server should recognize that the buffer is to small for any
  3530. // strings, and put the correct size in the BytesNeeded parameter,
  3531. // and fail the call.
  3532. //
  3533. if (cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSA))
  3534. {
  3535. pStatusBuf = &statusBuf;
  3536. tempBufSize = sizeof(QUERY_SERVICE_LOCK_STATUSA);
  3537. }
  3538. else
  3539. {
  3540. pStatusBuf = lpLockStatus;
  3541. }
  3542. RpcTryExcept
  3543. {
  3544. status = RQueryServiceLockStatusA(
  3545. (SC_RPC_HANDLE)hSCManager,
  3546. pStatusBuf,
  3547. tempBufSize,
  3548. pcbBytesNeeded);
  3549. }
  3550. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3551. {
  3552. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3553. }
  3554. RpcEndExcept
  3555. if (status != NO_ERROR)
  3556. {
  3557. #ifdef _WIN64
  3558. //
  3559. // pcbBytesNeeded isn't filled in if the byte count is too
  3560. // small (returned when the buffer size is large enough to
  3561. // hold the 32-bit structure but too small to hold the
  3562. // 64-bit structure. Get the necessary (32-bit) size.
  3563. //
  3564. if (status == RPC_X_BYTE_COUNT_TOO_SMALL)
  3565. {
  3566. RpcTryExcept
  3567. {
  3568. status = RQueryServiceLockStatusA(
  3569. (SC_RPC_HANDLE)hSCManager,
  3570. pStatusBuf,
  3571. sizeof(QUERY_SERVICE_LOCK_STATUSA),
  3572. pcbBytesNeeded);
  3573. }
  3574. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3575. {
  3576. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3577. }
  3578. RpcEndExcept
  3579. }
  3580. //
  3581. // Since the ACF file specifies byte_count for this API, we're
  3582. // responsible for managing the count of bytes needed by the
  3583. // caller. For 64-bit clients calling 32-bit servers, the
  3584. // returned buffer size is too small because of differing
  3585. // pointer sizes. Add on the minimum number of bytes that
  3586. // will guarantee enough space in the buffer for the next
  3587. // call.
  3588. //
  3589. if (status == ERROR_INSUFFICIENT_BUFFER)
  3590. {
  3591. //
  3592. // 1 embedded pointer in the structure and max
  3593. // space required for alignment.
  3594. //
  3595. *pcbBytesNeeded += (sizeof(PVOID) - sizeof(ULONG) + sizeof(PVOID));
  3596. }
  3597. else if (status == RPC_X_BYTE_COUNT_TOO_SMALL)
  3598. {
  3599. //
  3600. // We get here if we called a 32-bit server where the lock
  3601. // was unowned and we used a buffer size smaller than
  3602. // sizeof(QUERY_SERVICE_LOCK_STATUSA).
  3603. //
  3604. *pcbBytesNeeded = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(WCHAR);
  3605. status = ERROR_INSUFFICIENT_BUFFER;
  3606. }
  3607. #endif // _WIN64
  3608. SetLastError(status);
  3609. return(FALSE);
  3610. }
  3611. return(TRUE);
  3612. }
  3613. BOOL
  3614. WINAPI
  3615. QueryServiceLockStatusW(
  3616. SC_HANDLE hSCManager,
  3617. LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
  3618. DWORD cbBufSize,
  3619. LPDWORD pcbBytesNeeded
  3620. )
  3621. /*++
  3622. Routine Description:
  3623. see QueryServiceLockStatusA
  3624. Arguments:
  3625. Return Value:
  3626. Note:
  3627. --*/
  3628. {
  3629. DWORD status;
  3630. LPQUERY_SERVICE_LOCK_STATUSW pStatusBuf;
  3631. QUERY_SERVICE_LOCK_STATUSW statusBuf;
  3632. DWORD tempBufSize;
  3633. tempBufSize = cbBufSize;
  3634. //
  3635. // Create a dummy buffer that is at least the size of the structure.
  3636. // This way RPC should at least send the request to the server side.
  3637. // The server should recognize that the buffer is to small for any
  3638. // strings, and put the correct size in the BytesNeeded parameter,
  3639. // and fail the call.
  3640. //
  3641. if (cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSW))
  3642. {
  3643. pStatusBuf = &statusBuf;
  3644. tempBufSize = sizeof(QUERY_SERVICE_LOCK_STATUSW);
  3645. }
  3646. else
  3647. {
  3648. pStatusBuf = lpLockStatus;
  3649. }
  3650. RpcTryExcept
  3651. {
  3652. status = RQueryServiceLockStatusW(
  3653. (SC_RPC_HANDLE)hSCManager,
  3654. pStatusBuf,
  3655. tempBufSize,
  3656. pcbBytesNeeded);
  3657. }
  3658. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3659. {
  3660. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3661. }
  3662. RpcEndExcept
  3663. if (status != NO_ERROR)
  3664. {
  3665. #ifdef _WIN64
  3666. //
  3667. // pcbBytesNeeded isn't filled in if the byte count is too
  3668. // small (returned when the buffer size is large enough to
  3669. // hold the 32-bit structure but too small to hold the
  3670. // 64-bit structure. Get the necessary (32-bit) size.
  3671. //
  3672. if (status == RPC_X_BYTE_COUNT_TOO_SMALL)
  3673. {
  3674. RpcTryExcept
  3675. {
  3676. status = RQueryServiceLockStatusW(
  3677. (SC_RPC_HANDLE)hSCManager,
  3678. pStatusBuf,
  3679. sizeof(QUERY_SERVICE_LOCK_STATUSW),
  3680. pcbBytesNeeded);
  3681. }
  3682. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  3683. {
  3684. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3685. }
  3686. RpcEndExcept
  3687. }
  3688. //
  3689. // Since the ACF file specifies byte_count for this API, we're
  3690. // responsible for managing the count of bytes needed by the
  3691. // caller. For 64-bit clients calling 32-bit servers, the
  3692. // returned buffer size is too small because of differing
  3693. // pointer sizes. Add on the minimum number of bytes that
  3694. // will guarantee enough space in the buffer for the next
  3695. // call.
  3696. //
  3697. if (status == ERROR_INSUFFICIENT_BUFFER)
  3698. {
  3699. //
  3700. // 1 embedded pointer in the structure and max
  3701. // space required for alignment.
  3702. //
  3703. *pcbBytesNeeded += (sizeof(PVOID) - sizeof(ULONG) + sizeof(PVOID));
  3704. }
  3705. else if (status == RPC_X_BYTE_COUNT_TOO_SMALL)
  3706. {
  3707. //
  3708. // We get here if we called a 32-bit server where the lock
  3709. // was unowned and we used a buffer size smaller than
  3710. // sizeof(QUERY_SERVICE_LOCK_STATUSW).
  3711. //
  3712. *pcbBytesNeeded = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
  3713. status = ERROR_INSUFFICIENT_BUFFER;
  3714. }
  3715. #endif // _WIN64
  3716. SetLastError(status);
  3717. return(FALSE);
  3718. }
  3719. return(TRUE);
  3720. }
  3721. BOOL
  3722. WINAPI
  3723. UnlockServiceDatabase(
  3724. IN SC_LOCK ScLock
  3725. )
  3726. /*++
  3727. Routine Description:
  3728. This is the DLL entry point for the UnlockServiceDatabase function.
  3729. This function releases a lock on a Service Control Manager database.
  3730. Arguments:
  3731. ScLock - Lock obtained from a previous LockServiceDatabase call.
  3732. Return Value:
  3733. --*/
  3734. {
  3735. DWORD status;
  3736. UNREFERENCED_PARAMETER(ScLock);
  3737. RpcTryExcept {
  3738. status = RUnlockServiceDatabase((LPSC_RPC_LOCK)&ScLock);
  3739. }
  3740. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3741. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_SERVICE_LOCK);
  3742. }
  3743. RpcEndExcept
  3744. if (status != NO_ERROR){
  3745. SetLastError(status);
  3746. return(FALSE);
  3747. }
  3748. return(TRUE);
  3749. }
  3750. BOOL
  3751. WINAPI
  3752. NotifyBootConfigStatus(
  3753. IN BOOL BootAcceptable
  3754. )
  3755. /*++
  3756. Routine Description:
  3757. If we are not currently booted with Last Known Good, this function
  3758. will revert to Last Known Good if the boot is not acceptable. Or it
  3759. will save the boot configuration that we last booted from as the
  3760. Last Known Good. This is the configuration that we will fall back
  3761. to if a future boot fails.
  3762. Arguments:
  3763. BootAcceptable - This indicates whether or not the boot was acceptable.
  3764. Return Value:
  3765. TRUE - This is only returned if the boot is acceptable, and we
  3766. successfully replaced Last Known Good with the current boot
  3767. configuration.
  3768. FALSE - This is returned if an error occured when attempting to replace
  3769. Last Known Good or if the system is currently booted from Last
  3770. Known Good.
  3771. --*/
  3772. {
  3773. DWORD status;
  3774. RpcTryExcept {
  3775. status = RNotifyBootConfigStatus(
  3776. NULL, // A Local Call Only.
  3777. (DWORD)BootAcceptable);
  3778. }
  3779. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  3780. status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
  3781. }
  3782. RpcEndExcept
  3783. if (status != NO_ERROR){
  3784. SetLastError(status);
  3785. return(FALSE);
  3786. }
  3787. return(TRUE);
  3788. }
  3789. DWORD
  3790. ScWaitForStart(
  3791. VOID
  3792. )
  3793. /*++
  3794. Routine Description:
  3795. This routine waits until the SC_INTERNAL_START_EVENT is set or until
  3796. a timeout occurs. Then it returns.
  3797. Arguments:
  3798. none
  3799. Return Value:
  3800. none
  3801. --*/
  3802. {
  3803. DWORD status;
  3804. HANDLE ScStartEvent = NULL;
  3805. //
  3806. // Try opening the event first because it will work most of the
  3807. // time.
  3808. //
  3809. ScStartEvent = OpenEventW(
  3810. SYNCHRONIZE,
  3811. FALSE,
  3812. SC_INTERNAL_START_EVENT );
  3813. if (ScStartEvent == NULL) {
  3814. status = GetLastError();
  3815. if (status == ERROR_FILE_NOT_FOUND) {
  3816. //
  3817. // Only if we can't find the event do we attempt to create
  3818. // it here.
  3819. //
  3820. SCC_LOG0(ERROR,
  3821. "ScWaitForStart: Event does not exist -- attempting to create it\n");
  3822. //
  3823. // Create the event that the OpenSCManager will use to wait on the
  3824. // service controller with.
  3825. //
  3826. SECURITY_ATTRIBUTES SecurityAttributes;
  3827. PSECURITY_DESCRIPTOR SecurityDescriptor=NULL;
  3828. status = ScCreateStartEventSD(&SecurityDescriptor);
  3829. if (status != NO_ERROR) {
  3830. SCC_LOG0(ERROR,"ScGetStartEvent: Couldn't allocate for SecurityDesc\n");
  3831. return status;
  3832. }
  3833. SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  3834. SecurityAttributes.bInheritHandle = FALSE;
  3835. SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
  3836. ScStartEvent = CreateEventW(
  3837. &SecurityAttributes,
  3838. TRUE, // Must be manually reset
  3839. FALSE, // The event is initially not signalled
  3840. SC_INTERNAL_START_EVENT );
  3841. status = GetLastError(); // must do this before LocalFree
  3842. LocalFree(SecurityDescriptor);
  3843. if (ScStartEvent == NULL) {
  3844. //
  3845. // Failed to create StartEvent.
  3846. //
  3847. // If we failed to create it because someone else created
  3848. // it between our calls to OpenEvent and CreateEvent, try
  3849. // to open it once more.
  3850. //
  3851. if (status == ERROR_ALREADY_EXISTS) {
  3852. ScStartEvent = OpenEventW(
  3853. SYNCHRONIZE,
  3854. FALSE,
  3855. SC_INTERNAL_START_EVENT );
  3856. if (ScStartEvent == NULL) {
  3857. status = GetLastError();
  3858. SCC_LOG1(ERROR,"ScWaitForStart: OpenEvent (StartEvent) failed "
  3859. FORMAT_DWORD " on second attempt\n", status);
  3860. return status;
  3861. }
  3862. }
  3863. else {
  3864. SCC_LOG1(ERROR,"ScWaitForStart: CreateEvent (StartEvent) Failed "
  3865. FORMAT_DWORD "\n", status);
  3866. return status;
  3867. }
  3868. }
  3869. }
  3870. else {
  3871. //
  3872. // Could not open the event for some unknown reason. Give up.
  3873. //
  3874. SCC_LOG1(ERROR,"ScWaitForStart: OpenEvent (StartEvent) Failed "
  3875. FORMAT_DWORD "\n", status);
  3876. return status;
  3877. }
  3878. }
  3879. SCC_LOG0(TRACE,"Beginning wait for ScStartEvent\n");
  3880. status = WaitForSingleObject(ScStartEvent, SC_START_TIMEOUT);
  3881. CloseHandle(ScStartEvent);
  3882. if (status == WAIT_TIMEOUT) {
  3883. SCC_LOG0(ERROR,"ScWaitForStart: TIMEOUT waiting for StartEvent\n");
  3884. return ERROR_TIMEOUT;
  3885. }
  3886. return NO_ERROR;
  3887. }
  3888. DWORD
  3889. ScMapRpcError(
  3890. IN DWORD RpcError,
  3891. IN DWORD BadContextError
  3892. )
  3893. /*++
  3894. Routine Description:
  3895. This routine maps the RPC error into a more meaningful error
  3896. for the caller.
  3897. Arguments:
  3898. RpcError - Supplies the exception error raised by RPC
  3899. BadContextError - Supplies the error code to return whenever an error
  3900. which indicates invalid context is received. In some cases, this
  3901. value is ERROR_INVALID_HANDLE; in others, it is ERROR_INVALID_SERVICE_LOCK.
  3902. Return Value:
  3903. Returns the mapped error.
  3904. --*/
  3905. {
  3906. switch (RpcError)
  3907. {
  3908. case RPC_S_INVALID_BINDING:
  3909. case RPC_X_SS_IN_NULL_CONTEXT:
  3910. case RPC_X_SS_CONTEXT_DAMAGED:
  3911. case RPC_X_SS_HANDLES_MISMATCH:
  3912. case ERROR_INVALID_HANDLE:
  3913. return BadContextError;
  3914. case RPC_X_NULL_REF_POINTER:
  3915. case EXCEPTION_ACCESS_VIOLATION:
  3916. return ERROR_INVALID_ADDRESS;
  3917. case RPC_S_INVALID_TAG:
  3918. return ERROR_INVALID_LEVEL;
  3919. case RPC_S_PROCNUM_OUT_OF_RANGE:
  3920. return ERROR_CALL_NOT_IMPLEMENTED;
  3921. default:
  3922. return RpcError;
  3923. }
  3924. }