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.

1208 lines
33 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. SvcMap.c (was DanL's OldWrap.c)
  5. Abstract:
  6. These are the API entry points for the NetService API.
  7. These mapping routines implement old-style APIs on new (NT/RPC) machines.
  8. The following functions are in this file:
  9. Exported:
  10. MapServiceControl
  11. MapServiceEnum
  12. MapServiceGetInfo
  13. MapServiceInstall
  14. Local:
  15. TranslateStatus
  16. MakeStatus
  17. MakeCode
  18. Author:
  19. Dan Lafferty (danl) 05-Feb-1992
  20. Environment:
  21. User Mode - Win32
  22. Revision History:
  23. 05-Feb-1992 Danl
  24. Created
  25. 30-Mar-1992 JohnRo
  26. Extracted DanL's code from /nt/private project back to NET project.
  27. 30-Apr-1992 JohnRo
  28. Use FORMAT_ equates where possible.
  29. 14-May-1992 JohnRo
  30. winsvc.h and related file cleanup.
  31. 22-May-1992 JohnRo
  32. RAID 9829: winsvc.h and related file cleanup.
  33. 02-Jun-1992 JohnRo
  34. RAID 9829: Avoid winsvc.h compiler warnings.
  35. 05-Aug-1992 JohnRo
  36. RAID 3021: NetService APIs don't always translate svc names.
  37. (Actually just avoid compiler warnings.)
  38. 14-OCt-1992 Danl
  39. Close handles that were left open by using CleanExit.
  40. 05-Nov-1992 JohnRo
  41. RAID 7780: netcmd: assertion 'net start' w/ only 2 present services.
  42. Corrected error code for invalid level.
  43. --*/
  44. //
  45. // INCLUDES
  46. //
  47. // These must be included first:
  48. #include <windows.h> // IN, DWORD, LocalFree(), SERVICE_ equates, etc.
  49. #include <lmcons.h> // NET_API_STATUS
  50. // These may be included in any order:
  51. #include <lmerr.h> // NetError codes
  52. #include <lmsvc.h> // LM20_SERVICE_ equates.
  53. #include <netdebug.h> // NetpAssert(), DBGSTATIC, FORMAT_ equates.
  54. #include <prefix.h> // PREFIX_ equates.
  55. #include <svcmap.h> // MapService() routines.
  56. #include <rpcutil.h> // MIDL_user_allocate(), etc.
  57. #include <svcdebug.h> // IF_DEBUG(), SCC_LOG, etc.
  58. #include <tstr.h> // STRCPY(), TCHAR_EOS.
  59. //
  60. // Range for OEM defined control opcodes
  61. //
  62. #define SVC_FUDGE_FACTOR 1024
  63. #define OEM_LOWER_LIMIT 128
  64. #define OEM_UPPER_LIMIT 255
  65. #ifndef LEVEL_2
  66. #define LEVEL_0 0L
  67. #define LEVEL_1 1L
  68. #define LEVEL_2 2L
  69. #endif
  70. //
  71. // Globals
  72. //
  73. //
  74. // LOCAL FUNCTIONS
  75. //
  76. DBGSTATIC DWORD
  77. TranslateStatus(
  78. OUT LPBYTE BufPtr,
  79. IN LPSERVICE_STATUS ServiceStatus,
  80. IN LPTSTR ServiceName,
  81. IN DWORD Level,
  82. IN LPTSTR DisplayName,
  83. OUT LPTSTR DestString
  84. );
  85. DBGSTATIC DWORD
  86. MakeStatus(
  87. IN DWORD CurrentState,
  88. IN DWORD ControlsAccepted
  89. );
  90. DBGSTATIC DWORD
  91. MakeCode(
  92. IN DWORD ExitCode,
  93. IN DWORD CheckPoint,
  94. IN DWORD WaitHint
  95. );
  96. DBGSTATIC NET_API_STATUS
  97. MapError(
  98. DWORD WinSvcError
  99. );
  100. NET_API_STATUS
  101. MapServiceControl (
  102. IN LPTSTR servername OPTIONAL,
  103. IN LPTSTR service,
  104. IN DWORD opcode,
  105. IN DWORD arg,
  106. OUT LPBYTE *bufptr
  107. )
  108. /*++
  109. Routine Description:
  110. This is the DLL entrypoint for NetServiceControl.
  111. Arguments:
  112. servername - Pointer to a string containing the name of the computer
  113. that is to execute the API function.
  114. service - Pointer to a string containing the name of the service
  115. that is to receive the control request.
  116. opcode - The control request code.
  117. arg - An additional (user defined) code that will be passed to the
  118. service.
  119. bufptr - pointer to a location where the service status is to
  120. be returned. If this pointer is invalid, it will be set to NULL
  121. upon return.
  122. Return Value:
  123. The returned InfoStruct2 structure is valid as long as the returned
  124. error is NOT NERR_ServiceNotInstalled or NERR_ServiceBadServiceName.
  125. NERR_Success - The operation was successful.
  126. NERR_InternalError - LocalAlloc or TransactNamedPipe failed, or
  127. TransactNamedPipe returned fewer bytes than expected.
  128. NERR_ServiceNotInstalled - The service record was not found in the
  129. installed list.
  130. NERR_BadServiceName - The service name pointer was NULL.
  131. NERR_ServiceCtlTimeout - The service did not respond with a status
  132. message within the fixed timeout limit (RESPONSE_WAIT_TIMEOUT).
  133. NERR_ServiceKillProcess - The service process had to be killed because
  134. it wouldn't terminate when requested.
  135. NERR_ServiceNotCtrl - The service cannot accept control messages.
  136. The install state indicates that start-up or shut-down is pending.
  137. NERR_ServiceCtlNotValid - The request is not valid for this service.
  138. For instance, a PAUSE request is not valid for a service that
  139. lists itself as NOT_PAUSABLE.
  140. ERROR_ACCESS_DENIED - This is a status response from the service
  141. security check.
  142. --*/
  143. {
  144. NET_API_STATUS status = NERR_Success;
  145. SC_HANDLE hServiceController = NULL;
  146. SC_HANDLE hService = NULL;
  147. DWORD control;
  148. DWORD desiredAccess = 0;
  149. SERVICE_STATUS serviceStatus;
  150. LPTSTR stringPtr;
  151. UNREFERENCED_PARAMETER( arg );
  152. *bufptr = NULL; // Null output so error cases are easy to handle.
  153. //
  154. // Get a handle to the service controller.
  155. //
  156. hServiceController = OpenSCManager(
  157. servername,
  158. NULL,
  159. SC_MANAGER_CONNECT);
  160. if (hServiceController == NULL) {
  161. status = MapError(GetLastError());
  162. SCC_LOG(ERROR,"NetServiceControl:OpenSCManager failed "
  163. FORMAT_API_STATUS "\n",status);
  164. return(status);
  165. }
  166. //
  167. // Translate the control opcode from the ancient variety to the
  168. // new and improved NT variety.
  169. //
  170. switch(opcode) {
  171. case SERVICE_CTRL_INTERROGATE:
  172. control = SERVICE_CONTROL_INTERROGATE;
  173. desiredAccess = SERVICE_INTERROGATE | SERVICE_QUERY_STATUS;
  174. break;
  175. case SERVICE_CTRL_PAUSE:
  176. control = SERVICE_CONTROL_PAUSE;
  177. desiredAccess = SERVICE_PAUSE_CONTINUE;
  178. break;
  179. case SERVICE_CTRL_CONTINUE:
  180. control = SERVICE_CONTROL_CONTINUE;
  181. desiredAccess = SERVICE_PAUSE_CONTINUE;
  182. break;
  183. case SERVICE_CTRL_UNINSTALL:
  184. control = SERVICE_CONTROL_STOP;
  185. desiredAccess = SERVICE_STOP;
  186. break;
  187. default:
  188. if ((opcode >= OEM_LOWER_LIMIT) &&
  189. (opcode <= OEM_UPPER_LIMIT))
  190. {
  191. control = opcode;
  192. desiredAccess = SERVICE_USER_DEFINED_CONTROL;
  193. }
  194. else
  195. {
  196. status = NERR_ServiceCtlNotValid;
  197. goto CleanExit;
  198. }
  199. }
  200. //
  201. // Get a handle to the service
  202. //
  203. hService = OpenService(
  204. hServiceController,
  205. service,
  206. desiredAccess);
  207. if (hService == NULL) {
  208. status = MapError(GetLastError());
  209. SCC_LOG(ERROR,"NetServiceControl:OpenService failed "
  210. FORMAT_API_STATUS "\n",status);
  211. goto CleanExit;
  212. }
  213. //
  214. // Send the control
  215. //
  216. if (!ControlService(hService,control,&serviceStatus)) {
  217. status = MapError(GetLastError());
  218. //
  219. // Convert an interrogate control to query service status
  220. // if the service happens to be in an uncontrollable state.
  221. //
  222. if ((status == NERR_ServiceNotCtrl || status == NERR_ServiceNotInstalled) &&
  223. (opcode == SERVICE_CTRL_INTERROGATE)) {
  224. if (!QueryServiceStatus(hService,&serviceStatus)) {
  225. status = MapError(GetLastError());
  226. }
  227. else {
  228. status = NERR_Success;
  229. }
  230. }
  231. if (status != NERR_Success) {
  232. SCC_LOG(ERROR,"NetServiceControl:ControlService failed "
  233. FORMAT_API_STATUS "\n",status);
  234. goto CleanExit;
  235. }
  236. }
  237. //
  238. // Translate the status from the old - ancient variety to the new
  239. // and improved NT variety.
  240. //
  241. *bufptr = MIDL_user_allocate(
  242. sizeof(SERVICE_INFO_2) + STRSIZE(service));
  243. if (*bufptr == NULL) {
  244. SCC_LOG(ERROR,"NetServiceControl:Allocation Failure\n",0);
  245. status = ERROR_NOT_ENOUGH_MEMORY;
  246. goto CleanExit;
  247. }
  248. stringPtr = (LPTSTR)((*bufptr) + sizeof(SERVICE_INFO_2));
  249. status = TranslateStatus(
  250. *bufptr,
  251. &serviceStatus,
  252. service,
  253. LEVEL_2,
  254. NULL, // DisplayName
  255. stringPtr); // dest for name string
  256. CleanExit:
  257. if(hServiceController != NULL) {
  258. (VOID) CloseServiceHandle(hServiceController);
  259. }
  260. if(hService != NULL) {
  261. (VOID) CloseServiceHandle(hService);
  262. }
  263. return(status);
  264. }
  265. NET_API_STATUS
  266. MapServiceEnum (
  267. IN LPTSTR servername OPTIONAL,
  268. IN DWORD level,
  269. OUT LPBYTE *bufptr,
  270. IN DWORD prefmaxlen,
  271. OUT LPDWORD entriesread,
  272. OUT LPDWORD totalentries,
  273. IN OUT LPDWORD resume_handle OPTIONAL
  274. )
  275. /*++
  276. Routine Description:
  277. This is the DLL entrypoint for NetSeviceEnum.
  278. Arguments:
  279. servername - Pointer to a string containing the name of the computer
  280. that is to execute the API function.
  281. level - This indicates the level of information that is desired.
  282. bufptr - A pointer to the location where the pointer to the returned
  283. array of info structures is to be placed.
  284. prefmaxlen - Indicates a maximum size limit that the caller will allow
  285. for the return buffer.
  286. entriesread - A pointer to the location where the number of entries
  287. (data structures)read is to be returned.
  288. totalentries - A pointer to the location which upon return indicates
  289. the total number of entries in the "active" database.
  290. resumehandle - Pointer to a value that indicates where to resume
  291. enumerating data.
  292. Return Value:
  293. Nerr_Success - The operation was successful.
  294. ERROR_MORE_DATA - Not all of the data in the active database could be
  295. returned.
  296. ERROR_INVALID_LEVEL - An illegal info Level was passed in.
  297. Note:
  298. --*/
  299. {
  300. NET_API_STATUS status = NERR_Success;
  301. SC_HANDLE hServiceController = NULL;
  302. LPENUM_SERVICE_STATUS enumStatus;
  303. ENUM_SERVICE_STATUS dummybuf;
  304. DWORD bufSize;
  305. DWORD structSize;
  306. LPBYTE buffer = NULL;
  307. LPBYTE tempPtr;
  308. DWORD bytesNeeded;
  309. DWORD i;
  310. *bufptr = NULL; // Null output so error cases are easy to handle.
  311. //
  312. // Get a handle to the service controller.
  313. //
  314. hServiceController = OpenSCManager(
  315. servername,
  316. NULL,
  317. SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
  318. if (hServiceController == NULL) {
  319. status = MapError(GetLastError());
  320. SCC_LOG(ERROR,"NetServiceEnum:OpenSCManager failed (dec) "
  321. FORMAT_API_STATUS "\n", status);
  322. SCC_LOG(ERROR,"NetServiceEnum:OpenSCManager failed (hex) "
  323. FORMAT_HEX_DWORD "\n", (DWORD) status);
  324. return(status);
  325. }
  326. if (!EnumServicesStatus(
  327. hServiceController,
  328. SERVICE_WIN32,
  329. SERVICE_ACTIVE,
  330. (LPENUM_SERVICE_STATUS) &dummybuf,
  331. sizeof(dummybuf),
  332. &bytesNeeded,
  333. entriesread,
  334. NULL)) {
  335. status = MapError(GetLastError());
  336. if (status != ERROR_MORE_DATA) {
  337. (VOID) CloseServiceHandle(hServiceController);
  338. SCC_LOG(ERROR,"NetServiceEnum:EnumServiceStatus failed "
  339. FORMAT_API_STATUS "\n",status);
  340. return status;
  341. }
  342. }
  343. else {
  344. //
  345. // No entries to enumerate.
  346. //
  347. *totalentries = *entriesread = 0;
  348. *bufptr = NULL;
  349. if (resume_handle != NULL) {
  350. *resume_handle = 0;
  351. }
  352. (VOID) CloseServiceHandle(hServiceController);
  353. return NERR_Success;
  354. }
  355. //
  356. // Initialize entriesread so that we can free the output buffer
  357. // based on this value.
  358. //
  359. *entriesread = 0;
  360. //
  361. // In order to get the totalentries value, we have to allocate a
  362. // buffer large enough to hold all entries. Since we are getting
  363. // all entries anyway, we ignore the prefmaxlen input parameter
  364. // and return everything. Add fudge factor in case other services
  365. // got started in between our two EnumServicesStatus calls.
  366. //
  367. bufSize = bytesNeeded + SVC_FUDGE_FACTOR;
  368. buffer = MIDL_user_allocate(bufSize);
  369. if (buffer == NULL) {
  370. SCC_LOG(ERROR,"NetServiceEnum: Allocation Failure "
  371. FORMAT_API_STATUS "\n", (NET_API_STATUS) GetLastError());
  372. status = ERROR_NOT_ENOUGH_MEMORY;
  373. goto CleanExit;
  374. }
  375. //
  376. // Enumerate the status
  377. //
  378. if (!EnumServicesStatus(
  379. hServiceController,
  380. SERVICE_WIN32,
  381. SERVICE_ACTIVE,
  382. (LPENUM_SERVICE_STATUS)buffer,
  383. bufSize,
  384. &bytesNeeded,
  385. entriesread,
  386. resume_handle)) {
  387. status = MapError(GetLastError());
  388. if (status == ERROR_MORE_DATA) {
  389. //
  390. // If output buffer allocated is still too small we give
  391. // up and return nothing.
  392. //
  393. *entriesread = 0;
  394. status = ERROR_NOT_ENOUGH_MEMORY;
  395. }
  396. SCC_LOG(ERROR,"NetServiceEnum:EnumServiceStatus failed "
  397. FORMAT_API_STATUS "\n",status);
  398. goto CleanExit;
  399. }
  400. //
  401. // Translate the status from the old - ancient (lanman) variety to the
  402. // new and improved NT variety.
  403. //
  404. switch(level) {
  405. case LEVEL_0:
  406. structSize = sizeof(SERVICE_INFO_0);
  407. break;
  408. case LEVEL_1:
  409. structSize = sizeof(SERVICE_INFO_1);
  410. break;
  411. case LEVEL_2:
  412. structSize = sizeof(SERVICE_INFO_2);
  413. break;
  414. default:
  415. status = ERROR_INVALID_LEVEL;
  416. goto CleanExit;
  417. }
  418. //
  419. // CHANGE FORMAT OF RETURN BUFFER TO LANMAN-STYLE.
  420. //
  421. // It should be noted that the new ENUM_SERVICE_STATUS structure
  422. // is larger than any of the old lanman structures. We can count
  423. // on the fact that the strings are in the later portion of the
  424. // buffer. Therefore, we can write over the old structures - one
  425. // by one.
  426. //
  427. tempPtr = buffer;
  428. enumStatus = (LPENUM_SERVICE_STATUS)buffer;
  429. for (i=0; i < *entriesread; i++) {
  430. status = TranslateStatus (
  431. tempPtr, // dest fixed structure
  432. &(enumStatus->ServiceStatus),
  433. enumStatus->lpServiceName,
  434. level,
  435. enumStatus->lpDisplayName, // pointer to display name
  436. enumStatus->lpServiceName); // dest for name string
  437. if (status != NERR_Success) {
  438. (VOID) LocalFree(buffer);
  439. goto CleanExit;
  440. }
  441. tempPtr += structSize;
  442. enumStatus++;
  443. }
  444. //
  445. // We've read all entries.
  446. //
  447. *totalentries = *entriesread;
  448. *bufptr = buffer;
  449. CleanExit:
  450. if(hServiceController != NULL) {
  451. (VOID) CloseServiceHandle(hServiceController);
  452. }
  453. if (*entriesread == 0) {
  454. if (buffer != NULL) {
  455. MIDL_user_free(buffer);
  456. }
  457. *bufptr = NULL;
  458. }
  459. return(status);
  460. }
  461. NET_API_STATUS
  462. MapServiceGetInfo (
  463. IN LPTSTR servername OPTIONAL,
  464. IN LPTSTR service,
  465. IN DWORD level,
  466. OUT LPBYTE *bufptr
  467. )
  468. /*++
  469. Routine Description:
  470. This is the DLL entrypoint for NetServiceGetInfo.
  471. Arguments:
  472. servername - Pointer to a string containing the name of the computer
  473. that is to execute the API function. Since this function is
  474. executing on that computer, this information is not useful
  475. by the time it gets here. It is really only useful on the RPC
  476. client side.
  477. service - Pointer to a string containing the name of the service
  478. for which information is desired.
  479. level - This indicates the level of information that is desired.
  480. bufptr - Pointer to a Location where the pointer to the returned
  481. information structure is to be placed.
  482. Return Value:
  483. NERR_Success - The operation was successful.
  484. NERR_ServiceNotInstalled - if the service record was not found in
  485. either the installed or uninstalled lists.
  486. NERR_BadServiceName - The service name pointer was NULL.
  487. ERROR_INVALID_LEVEL - An illegal info level was passed in.
  488. ERROR_NOT_ENOUGH_MEMORY - The memory allocation for the returned
  489. Info Record failed.
  490. other - Any error returned by the following base API:
  491. RPC Runtime API
  492. --*/
  493. {
  494. NET_API_STATUS status = NERR_Success;
  495. SC_HANDLE hServiceController = NULL;
  496. SC_HANDLE hService = NULL;
  497. SERVICE_STATUS serviceStatus;
  498. LPTSTR stringPtr;
  499. DWORD bufSize;
  500. DWORD structSize;
  501. *bufptr = NULL; // Null output so error cases are easy to handle.
  502. //
  503. // Get a handle to the service controller.
  504. //
  505. hServiceController = OpenSCManager(
  506. servername,
  507. NULL,
  508. SC_MANAGER_CONNECT);
  509. if (hServiceController == NULL) {
  510. status = MapError(GetLastError());
  511. SCC_LOG(ERROR,"NetServiceGetInfo:OpenSCManager failed "
  512. FORMAT_API_STATUS "\n",status);
  513. return(status);
  514. }
  515. //
  516. // Get a handle to the service
  517. //
  518. hService = OpenService(
  519. hServiceController,
  520. service,
  521. SERVICE_QUERY_STATUS);
  522. if (hService == NULL) {
  523. status = MapError(GetLastError());
  524. SCC_LOG(ERROR,"NetServiceGetInfo:OpenService failed "
  525. FORMAT_API_STATUS "\n",status);
  526. goto CleanExit;
  527. }
  528. //
  529. // Query the status
  530. //
  531. if (!QueryServiceStatus(hService,&serviceStatus)) {
  532. status = MapError(GetLastError());
  533. SCC_LOG(ERROR,"NetServiceGetInfo:QueryServiceStatus failed "
  534. FORMAT_API_STATUS "\n",status);
  535. goto CleanExit;
  536. }
  537. //
  538. // Translate the status from the old - ancient variety to the new
  539. // and improved NT variety.
  540. //
  541. switch(level) {
  542. case LEVEL_0:
  543. structSize = sizeof(SERVICE_INFO_0);
  544. break;
  545. case LEVEL_1:
  546. structSize = sizeof(SERVICE_INFO_1);
  547. break;
  548. case LEVEL_2:
  549. structSize = sizeof(SERVICE_INFO_2);
  550. break;
  551. default:
  552. status = ERROR_INVALID_LEVEL;
  553. goto CleanExit;
  554. }
  555. bufSize = structSize + STRSIZE(service);
  556. *bufptr = MIDL_user_allocate(bufSize);
  557. if (*bufptr == NULL) {
  558. SCC_LOG(ERROR,"NetServiceGetInfo:Allocation Failure\n",0);
  559. status = ERROR_NOT_ENOUGH_MEMORY;
  560. goto CleanExit;
  561. }
  562. stringPtr = (LPTSTR)(*bufptr + structSize);
  563. status = TranslateStatus(
  564. *bufptr,
  565. &serviceStatus,
  566. service,
  567. level,
  568. NULL, // DisplayName
  569. stringPtr); // dest for name string
  570. CleanExit:
  571. if(hServiceController != NULL) {
  572. (VOID) CloseServiceHandle(hServiceController);
  573. }
  574. if(hService != NULL) {
  575. (VOID) CloseServiceHandle(hService);
  576. }
  577. return(status);
  578. }
  579. NET_API_STATUS
  580. MapServiceInstall (
  581. IN LPTSTR servername OPTIONAL,
  582. IN LPTSTR service,
  583. IN DWORD argc,
  584. IN LPTSTR argv[],
  585. OUT LPBYTE *bufptr
  586. )
  587. /*++
  588. Routine Description:
  589. This is the DLL entrypoint for NetServiceInstall.
  590. Arguments:
  591. servername - Points to a string containing the name of the computer
  592. that is to execute the API function.
  593. service- Points to a string containing the name of the service
  594. that is to be started.
  595. argc - Indicates the number or argument vectors in argv.
  596. argv - A pointer to an array of pointers to strings. These
  597. are command line arguments that are to be passed to the service.
  598. bufptr - This is the address where a pointer to the service's
  599. information buffer (SERVICE_INFO_2) is to be placed.
  600. Return Value:
  601. NERR_Success - The operation was successful
  602. NERR_InternalError - There is a bug in this program somewhere.
  603. NERR_ServiceInstalled - The service is already running - we do not
  604. yet allow multiple instances of the same service.
  605. NERR_CfgCompNotFound - The configuration component could not be found.
  606. The Image File could not be found for this service.
  607. NERR_ServiceTableFull - The maximum number of running services has
  608. already been reached.
  609. NERR_ServiceCtlTimeout - The service program did not respond to the
  610. start-up request within the timeout period. If this was the
  611. only service in the service process, the service process was
  612. killed.
  613. ERROR_NOT_ENOUGH_MEMORY - If this error occurs early in the
  614. start-up procedure, the start-up will fail. If it occurs at the
  615. end (allocating the return status buffer), the service will still
  616. be started and allowed to run.
  617. other - Any error returned by the following base API:
  618. CreateNamedPipe
  619. ConnectNamedPipe
  620. CreateProcess
  621. TransactNamedPipe
  622. RPC Runtime API
  623. --*/
  624. {
  625. NET_API_STATUS status = NERR_Success;
  626. SC_HANDLE hServiceController = NULL;
  627. SC_HANDLE hService = NULL;
  628. SERVICE_STATUS serviceStatus;
  629. LPTSTR stringPtr;
  630. *bufptr = NULL; // Null output so error cases are easy to handle.
  631. //
  632. // Get a handle to the service controller.
  633. //
  634. hServiceController = OpenSCManager(
  635. servername,
  636. NULL,
  637. SC_MANAGER_CONNECT);
  638. if (hServiceController == NULL) {
  639. status = MapError(GetLastError());
  640. SCC_LOG(ERROR,"NetServiceInstall:OpenSCManager failed "
  641. FORMAT_API_STATUS "\n",status);
  642. return(status);
  643. }
  644. //
  645. // Get a handle to the service
  646. //
  647. hService = OpenService(
  648. hServiceController,
  649. service,
  650. SERVICE_QUERY_STATUS | SERVICE_START);
  651. if (hService == NULL) {
  652. status = MapError(GetLastError());
  653. SCC_LOG(ERROR,"NetServiceInstall:OpenService failed "
  654. FORMAT_API_STATUS "\n",status);
  655. goto CleanExit;
  656. }
  657. //
  658. // Call StartService
  659. //
  660. if (!StartService(hService,argc,(LPCTSTR *)argv)) {
  661. status = MapError(GetLastError());
  662. SCC_LOG(ERROR,"NetServiceInstall:StartService failed "
  663. FORMAT_API_STATUS "\n",status);
  664. goto CleanExit;
  665. }
  666. //
  667. // Get the service status since StartService does not return it
  668. //
  669. if (!QueryServiceStatus(hService,&serviceStatus)) {
  670. status = MapError(GetLastError());
  671. SCC_LOG(ERROR,"NetServiceInstall:QueryServiceStatus failed "
  672. FORMAT_API_STATUS "\n",status);
  673. goto CleanExit;
  674. }
  675. //
  676. // Translate the status from the old - ancient variety to the new
  677. // and improved NT variety.
  678. //
  679. *bufptr = MIDL_user_allocate(
  680. sizeof(SERVICE_INFO_2) + STRSIZE(service));
  681. if (*bufptr == NULL) {
  682. SCC_LOG(ERROR,"NetServiceInstall:Allocation Failure\n",0);
  683. status = ERROR_NOT_ENOUGH_MEMORY;
  684. goto CleanExit;
  685. }
  686. stringPtr = (LPTSTR)((*bufptr) + sizeof(SERVICE_INFO_2));
  687. status = TranslateStatus(
  688. *bufptr,
  689. &serviceStatus,
  690. service,
  691. LEVEL_2,
  692. NULL, // DisplayName
  693. stringPtr); // dest for name string
  694. CleanExit:
  695. if(hServiceController != NULL) {
  696. (VOID) CloseServiceHandle(hServiceController);
  697. }
  698. if(hService != NULL) {
  699. (VOID) CloseServiceHandle(hService);
  700. }
  701. return(status);
  702. }
  703. DBGSTATIC DWORD
  704. TranslateStatus(
  705. OUT LPBYTE BufPtr,
  706. IN LPSERVICE_STATUS ServiceStatus,
  707. IN LPTSTR ServiceName,
  708. IN DWORD Level,
  709. IN LPTSTR DisplayName,
  710. OUT LPTSTR DestString
  711. )
  712. /*++
  713. Routine Description:
  714. This function translates the new-style ServiceStatus structure into
  715. the old-style service info structures. The Info level of the output
  716. structure is stated on entry. Since we cannot obtain PID values from
  717. the new Service Controller, zero is always returned. Since
  718. the new Service Controller will never return text as part of the status,
  719. The text field is always set to NULL.
  720. NOTE:
  721. Since it is possible for this function to get called with
  722. ServiceName and BufPtr pointing to the same location, we must
  723. be careful to not write to the BufPtr location until we have
  724. finished reading all the information from the ServiceStatus
  725. structure.
  726. Arguments:
  727. BufPtr - This is a pointer to a buffer that has already been allocated
  728. for the returned information. The buffer must be of a size that
  729. matches the info level.
  730. ServiceStatus - This is a pointer to the new-style ServiceStatus
  731. structure.
  732. ServiceName - This is a pointer to the service name.
  733. Level - This indicates the desired info level to be output.
  734. DisplayName - If non-NULL, this points to a string that is to be
  735. the internationalized display name for the service.
  736. DestString - This is the buffer where the ServiceName is to be copied.
  737. All info levels require a ServiceName.
  738. Return Value:
  739. Note:
  740. --*/
  741. {
  742. LPSERVICE_INFO_0 serviceInfo0;
  743. LPSERVICE_INFO_1 serviceInfo1;
  744. LPSERVICE_INFO_2 serviceInfo2;
  745. DWORD currentState;
  746. DWORD exitCode;
  747. DWORD checkPoint;
  748. DWORD waitHint;
  749. DWORD controlsAccepted;
  750. DWORD specificError;
  751. NetpAssert( BufPtr != NULL );
  752. NetpAssert( ServiceName != NULL );
  753. NetpAssert( (*ServiceName) != TCHAR_EOS );
  754. //
  755. // Read all the important information into a temporary holding place.
  756. //
  757. exitCode = ServiceStatus->dwWin32ExitCode;
  758. checkPoint = ServiceStatus->dwCheckPoint;
  759. currentState = ServiceStatus->dwCurrentState;
  760. waitHint = ServiceStatus->dwWaitHint;
  761. controlsAccepted= ServiceStatus->dwControlsAccepted;
  762. specificError = ServiceStatus->dwServiceSpecificExitCode;
  763. //
  764. // Sometimes, (in the case of enum) the name string is already in
  765. // the correct location. In that case we skip the copy, and just
  766. // put the pointer in the correct place.
  767. //
  768. if (DestString != ServiceName) {
  769. (VOID) STRCPY(DestString, ServiceName);
  770. }
  771. switch(Level) {
  772. case LEVEL_0:
  773. serviceInfo0 = (LPSERVICE_INFO_0)BufPtr;
  774. serviceInfo0->svci0_name = DestString;
  775. break;
  776. case LEVEL_1:
  777. serviceInfo1 = (LPSERVICE_INFO_1)BufPtr;
  778. serviceInfo1->svci1_name = DestString;
  779. serviceInfo1->svci1_status= MakeStatus(currentState,controlsAccepted);
  780. serviceInfo1->svci1_code = MakeCode(exitCode,checkPoint,waitHint);
  781. serviceInfo1->svci1_pid = 0L;
  782. break;
  783. case LEVEL_2:
  784. serviceInfo2 = (LPSERVICE_INFO_2)BufPtr;
  785. serviceInfo2->svci2_name = DestString;
  786. serviceInfo2->svci2_status= MakeStatus(currentState,controlsAccepted);
  787. serviceInfo2->svci2_code = MakeCode(exitCode,checkPoint,waitHint);
  788. serviceInfo2->svci2_pid = 0L;
  789. serviceInfo2->svci2_text = NULL;
  790. serviceInfo2->svci2_specific_error = specificError;
  791. //
  792. // If DisplayName is present, use it. Otherwise, use the
  793. // ServiceName for the DisplayName.
  794. //
  795. if (DisplayName != NULL) {
  796. serviceInfo2->svci2_display_name = DisplayName;
  797. }
  798. else {
  799. serviceInfo2->svci2_display_name = DestString;
  800. }
  801. break;
  802. default:
  803. return(ERROR_INVALID_LEVEL);
  804. }
  805. NetpAssert( (*DestString) != TCHAR_EOS );
  806. return(NERR_Success);
  807. } // TranslateStatus
  808. DBGSTATIC DWORD
  809. MakeStatus (
  810. IN DWORD CurrentState,
  811. IN DWORD ControlsAccepted
  812. )
  813. /*++
  814. Routine Description:
  815. Makes an old-style (lanman) status word out of the service's
  816. currentState and ControlsAccepted information.
  817. Arguments:
  818. Return Value:
  819. --*/
  820. {
  821. DWORD state = 0;
  822. //
  823. // Determine the correct "old-style" service status to return.
  824. //
  825. switch(CurrentState) {
  826. case SERVICE_STOPPED:
  827. state = SERVICE_UNINSTALLED;
  828. break;
  829. case SERVICE_START_PENDING:
  830. state = SERVICE_INSTALL_PENDING;
  831. break;
  832. case SERVICE_STOP_PENDING:
  833. state = SERVICE_UNINSTALL_PENDING;
  834. break;
  835. case SERVICE_RUNNING:
  836. state = SERVICE_INSTALLED;
  837. break;
  838. case SERVICE_CONTINUE_PENDING:
  839. state = LM20_SERVICE_CONTINUE_PENDING | SERVICE_INSTALLED;
  840. break;
  841. case SERVICE_PAUSE_PENDING:
  842. state = LM20_SERVICE_PAUSE_PENDING | SERVICE_INSTALLED;
  843. break;
  844. case SERVICE_PAUSED:
  845. state = LM20_SERVICE_PAUSED | SERVICE_INSTALLED;
  846. break;
  847. default:
  848. break;
  849. }
  850. //
  851. // Modify that service status to include information about the
  852. // type of controls accepted.
  853. //
  854. if (ControlsAccepted & SERVICE_ACCEPT_STOP) {
  855. state |= SERVICE_UNINSTALLABLE;
  856. }
  857. if (ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) {
  858. state |= SERVICE_PAUSABLE;
  859. }
  860. return(state);
  861. }
  862. DBGSTATIC DWORD
  863. MakeCode(
  864. IN DWORD ExitCode,
  865. IN DWORD CheckPoint,
  866. IN DWORD WaitHint
  867. )
  868. {
  869. DWORD exitState=0;
  870. DWORD time=0;
  871. if ((WaitHint !=0 ) || (CheckPoint != 0)) {
  872. if (WaitHint != 0) {
  873. //
  874. // Convert the time in milliseconds to time in 10ths of seconds
  875. //
  876. time = WaitHint;
  877. if (time > 100) {
  878. time = time / 100;
  879. }
  880. else {
  881. time = 0;
  882. }
  883. }
  884. //
  885. // Limit the wait hint to the SERVICE_NT_MAXTIME.
  886. // ( currently 6553.5 seconds (1.82 hours) or 0x0000FFFF ).
  887. //
  888. if (time > SERVICE_NT_MAXTIME) {
  889. time = SERVICE_NT_MAXTIME;
  890. }
  891. exitState = SERVICE_NT_CCP_CODE(time,CheckPoint);
  892. }
  893. else {
  894. //
  895. // Otherwise, the exitState should be whatever is in the
  896. // ExitCode field.
  897. //
  898. exitState = 0;
  899. if (ExitCode != NO_ERROR) {
  900. exitState = SERVICE_UIC_CODE(SERVICE_UIC_SYSTEM, ExitCode);
  901. }
  902. }
  903. return(exitState);
  904. }
  905. DBGSTATIC NET_API_STATUS
  906. MapError(
  907. IN DWORD WinSvcError
  908. )
  909. {
  910. switch(WinSvcError) {
  911. case ERROR_INVALID_SERVICE_CONTROL:
  912. return NERR_ServiceCtlNotValid;
  913. case ERROR_SERVICE_REQUEST_TIMEOUT:
  914. return NERR_ServiceCtlTimeout;
  915. case ERROR_SERVICE_NO_THREAD:
  916. return NERR_ServiceNotStarting;
  917. case ERROR_SERVICE_DATABASE_LOCKED:
  918. return NERR_ServiceTableLocked;
  919. case ERROR_SERVICE_ALREADY_RUNNING:
  920. return NERR_ServiceInstalled;
  921. case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
  922. return NERR_ServiceNotCtrl;
  923. case ERROR_SERVICE_DOES_NOT_EXIST:
  924. return NERR_BadServiceName;
  925. case ERROR_SERVICE_NOT_ACTIVE:
  926. return NERR_ServiceNotInstalled;
  927. default:
  928. SCC_LOG( TRACE, "MapError: unmapped error code (dec) "
  929. FORMAT_API_STATUS ".\n", WinSvcError );
  930. SCC_LOG( TRACE, "MapError: unmapped error code (hex) "
  931. FORMAT_HEX_DWORD ".\n", (DWORD) WinSvcError );
  932. return WinSvcError; // not mapped
  933. }
  934. }