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.

1964 lines
51 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Service.cpp
  5. Abstract:
  6. General fax server service utility functions
  7. Author:
  8. Eran Yariv (EranY) Dec, 2000
  9. Revision History:
  10. --*/
  11. #include <windows.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <tchar.h>
  15. #include <Accctrl.h>
  16. #include <Aclapi.h>
  17. #include "faxutil.h"
  18. #include "faxreg.h"
  19. #include "FaxUIConstants.h"
  20. DWORD
  21. FaxOpenService (
  22. LPCTSTR lpctstrMachine,
  23. LPCTSTR lpctstrService,
  24. SC_HANDLE *phSCM,
  25. SC_HANDLE *phSvc,
  26. DWORD dwSCMDesiredAccess,
  27. DWORD dwSvcDesiredAccess,
  28. LPDWORD lpdwStatus
  29. );
  30. DWORD
  31. FaxCloseService (
  32. SC_HANDLE hScm,
  33. SC_HANDLE hSvc
  34. );
  35. DWORD
  36. WaitForServiceStopOrStart (
  37. SC_HANDLE hSvc,
  38. BOOL bStop,
  39. DWORD dwMaxWait
  40. );
  41. DWORD
  42. FaxOpenService (
  43. LPCTSTR lpctstrMachine,
  44. LPCTSTR lpctstrService,
  45. SC_HANDLE *phSCM,
  46. SC_HANDLE *phSvc,
  47. DWORD dwSCMDesiredAccess,
  48. DWORD dwSvcDesiredAccess,
  49. LPDWORD lpdwStatus
  50. )
  51. /*++
  52. Routine name : FaxOpenService
  53. Routine description:
  54. Opens a handle to a service and optionally queries its status
  55. Author:
  56. Eran Yariv (EranY), Oct, 2001
  57. Arguments:
  58. lpctstrMachine [in] - Machine on which the service handle should be obtained
  59. lpctstrService [in] - Service name
  60. phSCM [out] - Handle to the service control manager.
  61. phSvc [out] - Handle to the service
  62. dwSCMDesiredAccess [in] - Specifies the access to the service control manager
  63. dwSvcDesiredAccess [in] - Specifies the access to the service
  64. lpdwStatus [out] - Optional. If not NULL, point to a DWORD which we receive the current
  65. status of the service.
  66. Return Value:
  67. Standard Win32 error code
  68. Remarks:
  69. If the function succeeds, the caller should call FaxCloseService to free resources.
  70. --*/
  71. {
  72. SC_HANDLE hSvcMgr = NULL;
  73. SC_HANDLE hService = NULL;
  74. DWORD dwRes = ERROR_SUCCESS;
  75. DEBUG_FUNCTION_NAME(TEXT("FaxOpenService"))
  76. hSvcMgr = OpenSCManager(
  77. lpctstrMachine,
  78. NULL,
  79. dwSCMDesiredAccess
  80. );
  81. if (!hSvcMgr)
  82. {
  83. dwRes = GetLastError ();
  84. DebugPrintEx(
  85. DEBUG_ERR,
  86. TEXT("OpenSCManager failed with %ld"),
  87. dwRes);
  88. goto exit;
  89. }
  90. hService = OpenService(
  91. hSvcMgr,
  92. lpctstrService,
  93. dwSvcDesiredAccess
  94. );
  95. if (!hService)
  96. {
  97. dwRes = GetLastError ();
  98. DebugPrintEx(
  99. DEBUG_ERR,
  100. TEXT("OpenService failed with %ld"),
  101. dwRes);
  102. goto exit;
  103. }
  104. if (lpdwStatus)
  105. {
  106. SERVICE_STATUS Status;
  107. //
  108. // Caller wants to know the service status
  109. //
  110. if (!QueryServiceStatus( hService, &Status ))
  111. {
  112. dwRes = GetLastError ();
  113. DebugPrintEx(
  114. DEBUG_ERR,
  115. TEXT("QueryServiceStatus failed with %ld"),
  116. dwRes);
  117. goto exit;
  118. }
  119. *lpdwStatus = Status.dwCurrentState;
  120. }
  121. *phSCM = hSvcMgr;
  122. *phSvc = hService;
  123. Assert (ERROR_SUCCESS == dwRes);
  124. exit:
  125. if (ERROR_SUCCESS != dwRes)
  126. {
  127. FaxCloseService (hSvcMgr, hService);
  128. }
  129. return dwRes;
  130. } // FaxOpenService
  131. DWORD
  132. FaxCloseService (
  133. SC_HANDLE hScm,
  134. SC_HANDLE hSvc
  135. )
  136. /*++
  137. Routine name : FaxCloseService
  138. Routine description:
  139. Closes all handles to the service obtained by a call to FaxOpenService
  140. Author:
  141. Eran Yariv (EranY), Oct, 2001
  142. Arguments:
  143. hScm [in] - Handle to the service control manager
  144. hSvc [in] - Handle to the service
  145. Return Value:
  146. Standard Win32 error code
  147. --*/
  148. {
  149. DWORD dwRes = ERROR_SUCCESS;
  150. DEBUG_FUNCTION_NAME(TEXT("FaxCloseService"))
  151. if (hSvc)
  152. {
  153. if (!CloseServiceHandle(hSvc))
  154. {
  155. dwRes = GetLastError ();
  156. DebugPrintEx(
  157. DEBUG_ERR,
  158. TEXT("CloseServiceHandle failed with %ld"),
  159. dwRes);
  160. }
  161. }
  162. if (hScm)
  163. {
  164. if (!CloseServiceHandle(hScm))
  165. {
  166. dwRes = GetLastError ();
  167. DebugPrintEx(
  168. DEBUG_ERR,
  169. TEXT("CloseServiceHandle failed with %ld"),
  170. dwRes);
  171. }
  172. }
  173. return dwRes;
  174. } // FaxCloseService
  175. HANDLE
  176. CreateSvcStartEventWithGlobalNamedEvent()
  177. /*++
  178. Routine name : CreateSvcStartEventWithGlobalNamedEvent
  179. Routine description:
  180. Opens (or creates) the global named-event which signals a fax server service startup.
  181. This function is here so the client side modules can talk to a WinXP RTM fax service.
  182. This function is called by CreateSvcStartEvent if a WinXP RTM fax service is detected locally.
  183. For why and how see extensive remarks in CreateSvcStartEvent.
  184. Author:
  185. Eran Yariv (EranY), Dec, 2000
  186. Arguments:
  187. Return Value:
  188. Handle to the event or NULL on error (sets last error).
  189. --*/
  190. {
  191. DEBUG_FUNCTION_NAME(TEXT("CreateSvcStartEventWithGlobalNamedEvent"));
  192. HANDLE hEvent = NULL;
  193. #define FAX_SERVER_EVENT_NAME TEXT("Global\\FaxSvcRPCStarted-1ed23866-f90b-4ec5-b77e-36e8709422b6") // Name of event that notifies service RPC is on (WinXP RTM only).
  194. //
  195. // First, try to open the event, asking for synchronization only.
  196. //
  197. hEvent = OpenEvent(SYNCHRONIZE, FALSE, FAX_SERVER_EVENT_NAME);
  198. if (hEvent)
  199. {
  200. //
  201. // Good! return now.
  202. //
  203. return hEvent;
  204. }
  205. //
  206. // Houston, we've got a problem...
  207. //
  208. if (ERROR_FILE_NOT_FOUND != GetLastError())
  209. {
  210. //
  211. // The event is there, we just can't open it
  212. //
  213. DebugPrintEx(DEBUG_ERR,
  214. TEXT("OpenEvent(FAX_SERVER_EVENT_NAME) failed (ec: %ld)"),
  215. GetLastError());
  216. return NULL;
  217. }
  218. //
  219. // The event does not exist yet.
  220. //
  221. SECURITY_ATTRIBUTES* pSA = NULL;
  222. //
  223. // We create the event, giving everyone SYNCHRONIZE access only.
  224. // Notice that network service account (underwhich the service is running)
  225. // get full access.
  226. //
  227. pSA = CreateSecurityAttributesWithThreadAsOwner (SYNCHRONIZE, SYNCHRONIZE, EVENT_ALL_ACCESS);
  228. if(!pSA)
  229. {
  230. DebugPrintEx(DEBUG_ERR,
  231. TEXT("CreateSecurityAttributesWithThreadAsOwner failed (ec: %ld)"),
  232. GetLastError());
  233. return NULL;
  234. }
  235. hEvent = CreateEvent(pSA, TRUE, FALSE, FAX_SERVER_EVENT_NAME);
  236. DWORD dwRes = ERROR_SUCCESS;
  237. if (!hEvent)
  238. {
  239. dwRes = GetLastError();
  240. DebugPrintEx(DEBUG_ERR,
  241. TEXT("CreateEvent(FAX_SERVER_EVENT_NAME) failed (ec: %ld)"),
  242. dwRes);
  243. }
  244. DestroySecurityAttributes (pSA);
  245. if (!hEvent)
  246. {
  247. SetLastError (dwRes);
  248. }
  249. return hEvent;
  250. } // CreateSvcStartEventWithGlobalNamedEvent
  251. DWORD
  252. CreateSvcStartEvent(
  253. HANDLE *lphEvent,
  254. HKEY *lphKey
  255. )
  256. /*++
  257. Routine name : CreateSvcStartEvent
  258. Routine description:
  259. Creates a local event which signals a fax server service startup
  260. Author:
  261. Eran Yariv (EranY), Dec, 2000
  262. Arguments:
  263. lphEvent [out] - Handle to newly created event.
  264. This event is signaled when the service is up and running.
  265. The event is manual-reset.
  266. The caller should CloseHandle on this parameter.
  267. lphKey [out] - Handle to registry key.
  268. The caller should RegCloseKey this handle ONLY AFTER it no longer
  269. needs the event. Otherwise, the event will be signaled.
  270. This value may return NULL, in which case the caller should not call RegCloseKey.
  271. Return Value:
  272. Standard Win32 error code
  273. Remarks:
  274. The event returned from this function is a single-shot event.
  275. After a call to WaitForSingleObject (or multiple objects) on it, the caller
  276. should close the event and obtain a new one.
  277. --*/
  278. {
  279. DWORD ec = ERROR_SUCCESS;
  280. HANDLE hEvent = NULL;
  281. HKEY hKey = NULL;
  282. SC_HANDLE hScm = NULL;
  283. SC_HANDLE hFax = NULL;
  284. DWORD dwSvcStatus;
  285. DEBUG_FUNCTION_NAME(TEXT("CreateSvcStartEvent"));
  286. if (IsWinXPOS() && IsDesktopSKU())
  287. {
  288. //
  289. // In WinXP desktop SKU (PER/PRO) RTM, the service used to signal a global named event.
  290. // This has changed since Win .NET Server and WinXP SP1.
  291. // When a network printer connection is added, the new version of the client side dll (fxsapi.dll)
  292. // gets copied as the printer driver. It will be used by any application which prints, event to the
  293. // local fax server. In the local fax server case, it is crucial we find what is the event mechanism
  294. // the service uses to signal it is ready for RPC calls.
  295. //
  296. // Q: Why no check the OS version?
  297. // A: Because of the following scenario:
  298. // - User installs WinXP RTM
  299. // - User installs WinXP SP1
  300. // - User installs fax (from the RTM CD)
  301. // In that case, the service will be running using the WinXP RTM bits but the system
  302. // will report it is WinXP SP1. The only way to know for sure is by getting the file
  303. // version of fxssvc.exe
  304. //
  305. FAX_VERSION FaxVer;
  306. TCHAR tszSysDir[MAX_PATH + 1] = {0};
  307. TCHAR tszFxsSvc[MAX_PATH * 2] = {0};
  308. if (!GetSystemDirectory (tszSysDir, ARR_SIZE(tszSysDir)))
  309. {
  310. ec = GetLastError ();
  311. DebugPrintEx(
  312. DEBUG_ERR,
  313. TEXT("GetSystemDirectory failed with %ld"),
  314. ec);
  315. return ec;
  316. }
  317. if (0 > _sntprintf (tszFxsSvc, ARR_SIZE (tszFxsSvc) - 1, TEXT("%s\\") FAX_SERVICE_EXE_NAME, tszSysDir))
  318. {
  319. ec = ERROR_DIRECTORY;
  320. DebugPrintEx(
  321. DEBUG_ERR,
  322. TEXT("building the full path to fxssvc.exe failed with %ld"),
  323. ec);
  324. return ec;
  325. }
  326. FaxVer.dwSizeOfStruct = sizeof (FaxVer);
  327. ec = GetFileVersion (tszFxsSvc, &FaxVer);
  328. if (ERROR_SUCCESS != ec)
  329. {
  330. DebugPrintEx(
  331. DEBUG_ERR,
  332. TEXT("GetFileVersion failed with %ld"),
  333. ec);
  334. return ec;
  335. }
  336. if ((5 == FaxVer.wMajorVersion) &&
  337. (2 == FaxVer.wMinorVersion) &&
  338. (1776 == FaxVer.wMajorBuildNumber))
  339. {
  340. //
  341. // Build 5.2.1776 was the WinXP RTM Fax version.
  342. // The service is of that version and is using a global named event to signal
  343. // it is ready for RPC connections.
  344. //
  345. hEvent = CreateSvcStartEventWithGlobalNamedEvent ();
  346. if (NULL == hEvent)
  347. {
  348. ec = GetLastError ();
  349. DebugPrintEx(
  350. DEBUG_ERR,
  351. TEXT("CreateSvcStartEventWithGlobalNamedEvent failed with %ld"),
  352. ec);
  353. return ec;
  354. }
  355. //
  356. // Succeeded, return new event handle.
  357. //
  358. *lphKey = NULL;
  359. *lphEvent = hEvent;
  360. return ERROR_SUCCESS;
  361. }
  362. //
  363. // Else, fall through to the current implementation (listening on registry change event).
  364. //
  365. }
  366. ec = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  367. REGKEY_FAX_SERVICESTARTUP,
  368. 0,
  369. KEY_QUERY_VALUE | KEY_NOTIFY,
  370. &hKey);
  371. if (ERROR_SUCCESS != ec)
  372. {
  373. DebugPrintEx(
  374. DEBUG_ERR,
  375. TEXT("RegOpenKeyEx failed with %ld"),
  376. ec);
  377. return ec;
  378. }
  379. //
  380. // First, register for events
  381. //
  382. hEvent = CreateEvent (NULL, // Default security
  383. TRUE, // Manual reset
  384. FALSE, // Start non-signaled
  385. NULL); // Unnamed
  386. if (!hEvent)
  387. {
  388. ec = GetLastError ();
  389. DebugPrintEx(
  390. DEBUG_ERR,
  391. TEXT("CreateEvent failed with %ld"),
  392. ec);
  393. goto Exit;
  394. }
  395. ec = RegNotifyChangeKeyValue (hKey, // Watch for changes in key
  396. FALSE, // Don't care about subtrees
  397. REG_NOTIFY_CHANGE_LAST_SET, // Tell me when data changes there
  398. hEvent, // Event used
  399. TRUE); // Asynchronous
  400. if (ERROR_SUCCESS != ec)
  401. {
  402. DebugPrintEx(
  403. DEBUG_ERR,
  404. TEXT("RegNotifyChangeKeyValue failed with %ld"),
  405. ec);
  406. goto Exit;
  407. }
  408. //
  409. // Now, read and see if the service is up
  410. // NOTICE: Order matters!!!! We must first register for events and only later read
  411. //
  412. //
  413. // Let's see if the service is running...
  414. //
  415. ec = FaxOpenService (NULL,
  416. FAX_SERVICE_NAME,
  417. &hScm,
  418. &hFax,
  419. SC_MANAGER_CONNECT,
  420. SERVICE_QUERY_STATUS,
  421. &dwSvcStatus);
  422. if (ERROR_SUCCESS != ec)
  423. {
  424. goto Exit;
  425. }
  426. FaxCloseService (hScm, hFax);
  427. if (SERVICE_RUNNING == dwSvcStatus)
  428. {
  429. //
  430. // The service is up and running. Signal the event.
  431. //
  432. if (!SetEvent (hEvent))
  433. {
  434. ec = GetLastError ();
  435. DebugPrintEx(
  436. DEBUG_ERR,
  437. TEXT("SetEvent failed with %ld"),
  438. ec);
  439. goto Exit;
  440. }
  441. }
  442. Exit:
  443. if (ERROR_SUCCESS != ec)
  444. {
  445. //
  446. // Failure
  447. //
  448. if (hEvent)
  449. {
  450. CloseHandle (hEvent);
  451. }
  452. if (hKey)
  453. {
  454. RegCloseKey (hKey);
  455. }
  456. return ec;
  457. }
  458. else
  459. {
  460. //
  461. // Success
  462. //
  463. *lphEvent = hEvent;
  464. *lphKey = hKey;
  465. return ERROR_SUCCESS;
  466. }
  467. } // CreateSvcStartEvent
  468. BOOL
  469. EnsureFaxServiceIsStarted(
  470. LPCTSTR lpctstrMachineName
  471. )
  472. /*++
  473. Routine name : EnsureFaxServiceIsStarted
  474. Routine description:
  475. If the fax service is not running, attempts to start the service and waits for it to run
  476. Author:
  477. Eran Yariv (EranY), Jul, 2000
  478. Arguments:
  479. lpctstrMachineName [in] - Machine name (NULL for local)
  480. Return Value:
  481. TRUE if service is successfully runnig, FALSE otherwise.
  482. Use GetLastError() to retrieve errors.
  483. --*/
  484. {
  485. LPCTSTR lpctstrDelaySuicide = SERVICE_DELAY_SUICIDE; // Service command line parameter
  486. DWORD dwRes;
  487. DEBUG_FUNCTION_NAME(TEXT("EnsureFaxServiceIsStarted"))
  488. dwRes = StartServiceEx (lpctstrMachineName,
  489. FAX_SERVICE_NAME,
  490. 1,
  491. &lpctstrDelaySuicide,
  492. 10 * 60 * 1000); // Give up after ten minutes
  493. if (ERROR_SUCCESS != dwRes)
  494. {
  495. SetLastError (dwRes);
  496. return FALSE;
  497. }
  498. return TRUE;
  499. } // EnsureFaxServiceIsStarted
  500. BOOL
  501. StopService (
  502. LPCTSTR lpctstrMachineName,
  503. LPCTSTR lpctstrServiceName,
  504. BOOL bStopDependents,
  505. DWORD dwMaxWait
  506. )
  507. /*++
  508. Routine name : StopService
  509. Routine description:
  510. Stops a service
  511. Author:
  512. Eran Yariv (EranY), Aug, 2000
  513. Arguments:
  514. lpctstrMachineName [in] - The machine name when the service should stop. NULL for local machine
  515. lpctstrServiceName [in] - The service name
  516. bStopDependents [in] - Stop dependent services too?
  517. dwMaxWait [in] - Max time (millisecs) to wait for service to stop. 0 = Don't wait.
  518. Return Value:
  519. TRUE if successful, FALSE otherwise.
  520. Sets thread last error in case of failure.
  521. --*/
  522. {
  523. BOOL bRes = FALSE;
  524. SC_HANDLE hScm = NULL;
  525. SC_HANDLE hSvc = NULL;
  526. DWORD dwCnt;
  527. SERVICE_STATUS serviceStatus = {0};
  528. LPENUM_SERVICE_STATUS lpEnumSS = NULL;
  529. DWORD dwRes;
  530. DEBUG_FUNCTION_NAME(TEXT("StopService"));
  531. dwRes = FaxOpenService (lpctstrMachineName,
  532. lpctstrServiceName,
  533. &hScm,
  534. &hSvc,
  535. SC_MANAGER_CONNECT,
  536. SERVICE_QUERY_STATUS | SERVICE_STOP | SERVICE_ENUMERATE_DEPENDENTS,
  537. &(serviceStatus.dwCurrentState));
  538. if (ERROR_SUCCESS != dwRes)
  539. {
  540. goto exit;
  541. }
  542. if(SERVICE_STOPPED == serviceStatus.dwCurrentState)
  543. {
  544. //
  545. // Service already stopped
  546. //
  547. DebugPrintEx(DEBUG_MSG, TEXT("Service is already stopped."));
  548. bRes = TRUE;
  549. goto exit;
  550. }
  551. if (bStopDependents)
  552. {
  553. //
  554. // Look for dependent services first
  555. //
  556. DWORD dwNumDependents = 0;
  557. DWORD dwBufSize = 0;
  558. if (!EnumDependentServices (hSvc,
  559. SERVICE_ACTIVE,
  560. NULL,
  561. 0,
  562. &dwBufSize,
  563. &dwNumDependents))
  564. {
  565. dwRes = GetLastError ();
  566. if (ERROR_MORE_DATA != dwRes)
  567. {
  568. //
  569. // Real error
  570. //
  571. DebugPrintEx(DEBUG_MSG, TEXT("EnumDependentServices failed with %ld"), dwRes);
  572. goto exit;
  573. }
  574. //
  575. // Allocate buffer
  576. //
  577. if (!dwBufSize)
  578. {
  579. //
  580. // No services
  581. //
  582. goto StopOurService;
  583. }
  584. lpEnumSS = (LPENUM_SERVICE_STATUS)MemAlloc (dwBufSize);
  585. if (!lpEnumSS)
  586. {
  587. DebugPrintEx(DEBUG_MSG, TEXT("MemAlloc(%ld) failed with %ld"), dwBufSize, dwRes);
  588. goto exit;
  589. }
  590. }
  591. //
  592. // 2nd call
  593. //
  594. if (!EnumDependentServices (hSvc,
  595. SERVICE_ACTIVE,
  596. lpEnumSS,
  597. dwBufSize,
  598. &dwBufSize,
  599. &dwNumDependents))
  600. {
  601. DebugPrintEx(DEBUG_MSG, TEXT("EnumDependentServices failed with %ld"), GetLastError());
  602. goto exit;
  603. }
  604. //
  605. // Walk the services and stop each one
  606. //
  607. for (dwCnt = 0; dwCnt < dwNumDependents; dwCnt++)
  608. {
  609. if (!StopService (lpctstrMachineName, lpEnumSS[dwCnt].lpServiceName, FALSE))
  610. {
  611. goto exit;
  612. }
  613. }
  614. }
  615. StopOurService:
  616. //
  617. // Stop the service
  618. //
  619. if(!ControlService(hSvc, SERVICE_CONTROL_STOP, &serviceStatus))
  620. {
  621. DebugPrintEx(DEBUG_ERR, TEXT("ControlService(STOP) failed: error=%d"), GetLastError());
  622. goto exit;
  623. }
  624. if (0 == dwMaxWait)
  625. {
  626. //
  627. // Don't wait.
  628. //
  629. bRes = TRUE;
  630. goto exit;
  631. }
  632. //
  633. // Wait till the service is really stopped
  634. //
  635. dwRes = WaitForServiceStopOrStart (hSvc, TRUE, dwMaxWait);
  636. if (ERROR_SUCCESS == dwRes)
  637. {
  638. //
  639. // Service is really stopped now
  640. //
  641. bRes = TRUE;
  642. }
  643. exit:
  644. MemFree (lpEnumSS);
  645. FaxCloseService (hScm, hSvc);
  646. return bRes;
  647. } // StopService
  648. BOOL
  649. WaitForServiceRPCServer (
  650. DWORD dwTimeOut
  651. )
  652. /*++
  653. Routine name : WaitForServiceRPCServer
  654. Routine description:
  655. Waits until the service RPC server is up and running (or timeouts)
  656. Author:
  657. Eran Yariv (EranY), Jul, 2000
  658. Arguments:
  659. dwTimeOut [in] - Wait timeout (in millisecs). Can be INFINITE.
  660. Return Value:
  661. TRUE if the service RPC server is up and running, FALSE otherwise.
  662. --*/
  663. {
  664. DWORD dwRes;
  665. LONG lRes;
  666. HANDLE hFaxServerEvent = NULL;
  667. HKEY hKey = NULL;
  668. DEBUG_FUNCTION_NAME(TEXT("WaitForServiceRPCServer"))
  669. dwRes = CreateSvcStartEvent (&hFaxServerEvent, &hKey);
  670. if (ERROR_SUCCESS != dwRes)
  671. {
  672. SetLastError (dwRes);
  673. return FALSE;
  674. }
  675. //
  676. // Wait for the fax service to complete its initialization
  677. //
  678. dwRes = WaitForSingleObject(hFaxServerEvent, dwTimeOut);
  679. switch (dwRes)
  680. {
  681. case WAIT_FAILED:
  682. dwRes = GetLastError();
  683. DebugPrintEx(
  684. DEBUG_ERR,
  685. TEXT("WaitForSingleObject failed with %ld"),
  686. dwRes);
  687. break;
  688. case WAIT_OBJECT_0:
  689. dwRes = ERROR_SUCCESS;
  690. break;
  691. case WAIT_TIMEOUT:
  692. DebugPrintEx(
  693. DEBUG_ERR,
  694. TEXT("Service did not signal the event - timeout"));
  695. break;
  696. default:
  697. ASSERT_FALSE;
  698. break;
  699. }
  700. if (!CloseHandle (hFaxServerEvent))
  701. {
  702. DebugPrintEx(
  703. DEBUG_ERR,
  704. TEXT("CloseHandle failed with %ld"),
  705. GetLastError ());
  706. }
  707. if (hKey)
  708. {
  709. lRes = RegCloseKey (hKey);
  710. if (ERROR_SUCCESS != lRes)
  711. {
  712. DebugPrintEx(
  713. DEBUG_ERR,
  714. TEXT("RegCloseKey failed with %ld"),
  715. lRes);
  716. }
  717. }
  718. if (ERROR_SUCCESS != dwRes)
  719. {
  720. SetLastError (dwRes);
  721. return FALSE;
  722. }
  723. return TRUE;
  724. } // WaitForServiceRPCServer
  725. DWORD
  726. IsFaxServiceRunningUnderLocalSystemAccount (
  727. LPCTSTR lpctstrMachineName,
  728. LPBOOL lbpResultFlag
  729. )
  730. /*++
  731. Routine name : IsFaxServiceRunningUnderLocalSystemAccount
  732. Routine description:
  733. Checks if the fax service is running under the local system account
  734. Author:
  735. Eran Yariv (EranY), Jul, 2000
  736. Arguments:
  737. lpctstrMachineName [in] - Machine name of the fax service
  738. lbpResultFlag [out] - Result buffer
  739. Return Value:
  740. Standard Win32 error code
  741. --*/
  742. {
  743. SC_HANDLE hScm = NULL;
  744. SC_HANDLE hFax = NULL;
  745. DWORD dwRes;
  746. DWORD dwNeededSize;
  747. QUERY_SERVICE_CONFIG qsc = {0};
  748. LPQUERY_SERVICE_CONFIG lpSvcCfg = &qsc;
  749. DEBUG_FUNCTION_NAME(TEXT("IsFaxServiceRunningUnderLocalSystemAccount"))
  750. dwRes = FaxOpenService (lpctstrMachineName,
  751. FAX_SERVICE_NAME,
  752. &hScm,
  753. &hFax,
  754. SC_MANAGER_CONNECT,
  755. SERVICE_QUERY_CONFIG,
  756. NULL);
  757. if (ERROR_SUCCESS != dwRes)
  758. {
  759. goto exit;
  760. }
  761. if (!QueryServiceConfig(hFax, lpSvcCfg, sizeof (qsc), &dwNeededSize))
  762. {
  763. dwRes = GetLastError ();
  764. if (ERROR_INSUFFICIENT_BUFFER != dwRes)
  765. {
  766. //
  767. // Real error here
  768. //
  769. DebugPrintEx(
  770. DEBUG_ERR,
  771. TEXT("QueryServiceStatus failed with %ld"),
  772. dwRes);
  773. goto exit;
  774. }
  775. //
  776. // Allocate buffer
  777. //
  778. lpSvcCfg = (LPQUERY_SERVICE_CONFIG) MemAlloc (dwNeededSize);
  779. if (!lpSvcCfg)
  780. {
  781. DebugPrintEx(
  782. DEBUG_ERR,
  783. TEXT("Can't allocate %ld bytes for QUERY_SERVICE_CONFIG structure"),
  784. dwNeededSize);
  785. goto exit;
  786. }
  787. //
  788. // Call with good buffer size now
  789. //
  790. if (!QueryServiceConfig(hFax, lpSvcCfg, dwNeededSize, &dwNeededSize))
  791. {
  792. dwRes = GetLastError ();
  793. DebugPrintEx(
  794. DEBUG_ERR,
  795. TEXT("QueryServiceStatus failed with %ld"),
  796. dwRes);
  797. goto exit;
  798. }
  799. }
  800. if (!lpSvcCfg->lpServiceStartName ||
  801. !lstrcmp (TEXT("LocalSystem"), lpSvcCfg->lpServiceStartName))
  802. {
  803. *lbpResultFlag = TRUE;
  804. }
  805. else
  806. {
  807. *lbpResultFlag = FALSE;
  808. }
  809. dwRes = ERROR_SUCCESS;
  810. exit:
  811. FaxCloseService (hScm, hFax);
  812. if (lpSvcCfg != &qsc)
  813. {
  814. //
  815. // We allocated a buffer becuase the buffer on the stack was too small
  816. //
  817. MemFree (lpSvcCfg);
  818. }
  819. return dwRes;
  820. } // IsFaxServiceRunningUnderLocalSystemAccount
  821. PSID
  822. GetCurrentThreadSID ()
  823. /*++
  824. Routine name : GetCurrentThreadSID
  825. Routine description:
  826. Returns the SID of the user running the current thread.
  827. Supports impersonated threads.
  828. Author:
  829. Eran Yariv (EranY), Aug, 2000
  830. Arguments:
  831. Return Value:
  832. PSID or NULL on error (call GetLastError()).
  833. Call MemFree() on return value.
  834. --*/
  835. {
  836. HANDLE hToken = NULL;
  837. PSID pSid = NULL;
  838. DWORD dwSidSize;
  839. PSID pUserSid;
  840. DWORD dwReqSize;
  841. LPBYTE lpbTokenUser = NULL;
  842. DWORD ec = ERROR_SUCCESS;
  843. DEBUG_FUNCTION_NAME(TEXT("GetCurrentThreadSID"));
  844. //
  845. // Open the thread token.
  846. //
  847. if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken))
  848. {
  849. ec = GetLastError();
  850. if (ERROR_NO_TOKEN == ec)
  851. {
  852. //
  853. // This thread is not impersonated and has no SID.
  854. // Try to open process token instead
  855. //
  856. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
  857. {
  858. ec = GetLastError();
  859. DebugPrintEx(
  860. DEBUG_ERR,
  861. TEXT("OpenProcessToken failed. (ec: %ld)"),
  862. ec);
  863. goto exit;
  864. }
  865. }
  866. else
  867. {
  868. DebugPrintEx(
  869. DEBUG_ERR,
  870. TEXT("OpenThreadToken failed. (ec: %ld)"),
  871. ec);
  872. goto exit;
  873. }
  874. }
  875. //
  876. // Get the user's SID.
  877. //
  878. if (!GetTokenInformation(hToken,
  879. TokenUser,
  880. NULL,
  881. 0,
  882. &dwReqSize))
  883. {
  884. ec = GetLastError();
  885. if( ec != ERROR_INSUFFICIENT_BUFFER )
  886. {
  887. DebugPrintEx(
  888. DEBUG_ERR,
  889. TEXT("GetTokenInformation failed. (ec: %ld)"),
  890. ec);
  891. goto exit;
  892. }
  893. ec = ERROR_SUCCESS;
  894. }
  895. lpbTokenUser = (LPBYTE) MemAlloc( dwReqSize );
  896. if (lpbTokenUser == NULL)
  897. {
  898. DebugPrintEx(
  899. DEBUG_ERR,
  900. TEXT("Failed to allocate SID buffer (%ld bytes)"),
  901. dwReqSize
  902. );
  903. ec = GetLastError();
  904. goto exit;
  905. }
  906. if (!GetTokenInformation(hToken,
  907. TokenUser,
  908. (LPVOID)lpbTokenUser,
  909. dwReqSize,
  910. &dwReqSize))
  911. {
  912. ec = GetLastError();
  913. DebugPrintEx(
  914. DEBUG_ERR,
  915. TEXT("GetTokenInformation failed. (ec: %ld)"),
  916. ec);
  917. goto exit;
  918. }
  919. pUserSid = ((TOKEN_USER *)lpbTokenUser)->User.Sid;
  920. Assert (pUserSid);
  921. if (!IsValidSid(pUserSid))
  922. {
  923. DebugPrintEx(
  924. DEBUG_ERR,
  925. TEXT("Not a valid SID")
  926. );
  927. ec = ERROR_INVALID_SID;
  928. goto exit;
  929. }
  930. dwSidSize = GetLengthSid( pUserSid );
  931. //
  932. // Allocate return buffer
  933. //
  934. pSid = (PSID) MemAlloc( dwSidSize );
  935. if (pSid == NULL)
  936. {
  937. DebugPrintEx(
  938. DEBUG_ERR,
  939. TEXT("Failed to allocate SID buffer (%ld bytes)"),
  940. dwSidSize
  941. );
  942. ec = ERROR_OUTOFMEMORY;
  943. goto exit;
  944. }
  945. //
  946. // Copy thread's SID to return buffer
  947. //
  948. if (!CopySid(dwSidSize, pSid, pUserSid))
  949. {
  950. ec = GetLastError();
  951. DebugPrintEx(
  952. DEBUG_ERR,
  953. TEXT("CopySid Failed, Error : %ld"),
  954. ec
  955. );
  956. goto exit;
  957. }
  958. Assert (ec == ERROR_SUCCESS);
  959. exit:
  960. MemFree (lpbTokenUser);
  961. if (hToken)
  962. {
  963. CloseHandle(hToken);
  964. }
  965. if (ec != ERROR_SUCCESS)
  966. {
  967. MemFree (pSid);
  968. pSid = NULL;
  969. SetLastError (ec);
  970. }
  971. return pSid;
  972. } // GetCurrentThreadSID
  973. SECURITY_ATTRIBUTES *
  974. CreateSecurityAttributesWithThreadAsOwner (
  975. DWORD dwCurrentThreadRights,
  976. DWORD dwAuthUsersAccessRights,
  977. DWORD dwNetworkServiceRights
  978. )
  979. /*++
  980. Routine name : CreateSecurityAttributesWithThreadAsOwner
  981. Routine description:
  982. Create a security attribute structure with current thread's SID as owner.
  983. Gives dwCurrentThreadRights access rights to current thread sid.
  984. Can also grant specific rights to authenticated users.
  985. Can also grant specific rights to network service account.
  986. Author:
  987. Eran Yariv (EranY), Aug, 2000
  988. Arguments:
  989. dwCurrentThreadRights [in] - Access rights to grant to current thread.
  990. If zero, current thread is denied access.
  991. dwAuthUsersAccessRights [in] - Access rights to grant to authenticated users.
  992. If zero, authenticated users are denied access.
  993. dwNetworkServiceRights [in] - Access rights to grant to network service.
  994. If zero, network service is denied access.
  995. Return Value:
  996. Allocated security attributes or NULL on failure.
  997. Call DestroySecurityAttributes to free returned buffer.
  998. --*/
  999. {
  1000. DEBUG_FUNCTION_NAME(TEXT("CreateSecurityAttributesWithThreadAsOwner"))
  1001. //
  1002. // SetEntriesInAcl() Requires Windows NT 4.0 or later
  1003. //
  1004. #ifdef UNICODE
  1005. SECURITY_ATTRIBUTES *pSA = NULL;
  1006. SECURITY_DESCRIPTOR *pSD = NULL;
  1007. PSID pSidCurThread = NULL;
  1008. PSID pSidAuthUsers = NULL;
  1009. PSID pSidNetworkService = NULL;
  1010. PACL pACL = NULL;
  1011. EXPLICIT_ACCESS ea[3] = {0};
  1012. // Entry 0 - give dwCurrentThreadRights to current thread's SID.
  1013. // Entry 1 (optional) - give dwNetworkServiceRights to NetworkService account.
  1014. // Entry 2 (optional) - give dwAuthUsersAccessRights to authenticated users group.
  1015. DWORD rc;
  1016. DWORD dwIndex = 0;
  1017. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1018. //
  1019. // Allocate return SECURITY_ATTRIBUTES buffer
  1020. //
  1021. pSA = (SECURITY_ATTRIBUTES *)MemAlloc (sizeof (SECURITY_ATTRIBUTES));
  1022. if (!pSA)
  1023. {
  1024. DebugPrintEx(
  1025. DEBUG_ERR,
  1026. TEXT("Could not allocate %ld bytes for SECURITY_ATTRIBUTES"),
  1027. sizeof (SECURITY_ATTRIBUTES));
  1028. return NULL;
  1029. }
  1030. //
  1031. // Allocate SECURITY_DESCRIPTOR for the return SECURITY_ATTRIBUTES buffer
  1032. //
  1033. pSD = (SECURITY_DESCRIPTOR *)MemAlloc (sizeof (SECURITY_DESCRIPTOR));
  1034. if (!pSD)
  1035. {
  1036. DebugPrintEx(
  1037. DEBUG_ERR,
  1038. TEXT("Could not allocate %ld bytes for SECURITY_DESCRIPTOR"),
  1039. sizeof (SECURITY_DESCRIPTOR));
  1040. goto err_exit;
  1041. }
  1042. pSA->nLength = sizeof(SECURITY_ATTRIBUTES);
  1043. pSA->bInheritHandle = TRUE;
  1044. pSA->lpSecurityDescriptor = pSD;
  1045. //
  1046. // Init the security descriptor
  1047. //
  1048. if (!InitializeSecurityDescriptor (pSD, SECURITY_DESCRIPTOR_REVISION))
  1049. {
  1050. DebugPrintEx(
  1051. DEBUG_ERR,
  1052. TEXT("InitializeSecurityDescriptor failed with %ld"),
  1053. GetLastError());
  1054. goto err_exit;
  1055. }
  1056. //
  1057. // Get SID of current thread
  1058. //
  1059. pSidCurThread = GetCurrentThreadSID ();
  1060. if (!pSidCurThread)
  1061. {
  1062. DebugPrintEx(
  1063. DEBUG_ERR,
  1064. TEXT("GetCurrentThreadSID failed with %ld"),
  1065. GetLastError());
  1066. goto err_exit;
  1067. }
  1068. //
  1069. // Set the current thread's SID as SD owner (giving full access to the object)
  1070. //
  1071. if (!SetSecurityDescriptorOwner (pSD, pSidCurThread, FALSE))
  1072. {
  1073. DebugPrintEx(
  1074. DEBUG_ERR,
  1075. TEXT("SetSecurityDescriptorOwner failed with %ld"),
  1076. GetLastError());
  1077. goto err_exit;
  1078. }
  1079. //
  1080. // Set the current thread's SID as SD group (giving full access to the object)
  1081. //
  1082. if (!SetSecurityDescriptorGroup (pSD, pSidCurThread, FALSE))
  1083. {
  1084. DebugPrintEx(
  1085. DEBUG_ERR,
  1086. TEXT("SetSecurityDescriptorGroup failed with %ld"),
  1087. GetLastError());
  1088. goto err_exit;
  1089. }
  1090. if (dwNetworkServiceRights)
  1091. {
  1092. //
  1093. // Get the network service account sid
  1094. //
  1095. if (!AllocateAndInitializeSid(&NtAuthority,
  1096. 1, // 1 sub-authority
  1097. SECURITY_NETWORK_SERVICE_RID,
  1098. 0,0,0,0,0,0,0,
  1099. &pSidNetworkService))
  1100. {
  1101. DebugPrintEx(
  1102. DEBUG_ERR,
  1103. TEXT("AllocateAndInitializeSid(SECURITY_NETWORK_SERVICE_RID) failed with %ld"),
  1104. GetLastError());
  1105. goto err_exit;
  1106. }
  1107. Assert (pSidNetworkService);
  1108. }
  1109. if (dwAuthUsersAccessRights)
  1110. {
  1111. //
  1112. // We should also grant some rights to authenticated users
  1113. // Get 'Authenticated users' SID
  1114. //
  1115. if (!AllocateAndInitializeSid(&NtAuthority,
  1116. 1, // 1 sub-authority
  1117. SECURITY_AUTHENTICATED_USER_RID,
  1118. 0,0,0,0,0,0,0,
  1119. &pSidAuthUsers))
  1120. {
  1121. DebugPrintEx(
  1122. DEBUG_ERR,
  1123. TEXT("AllocateAndInitializeSid(SECURITY_AUTHENTICATED_USER_RID) failed with %ld"),
  1124. GetLastError());
  1125. goto err_exit;
  1126. }
  1127. Assert (pSidAuthUsers);
  1128. }
  1129. ea[0].grfAccessPermissions = dwCurrentThreadRights;
  1130. ea[0].grfAccessMode = SET_ACCESS;
  1131. ea[0].grfInheritance= NO_INHERITANCE;
  1132. ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  1133. ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  1134. ea[0].Trustee.ptstrName = (LPTSTR) pSidCurThread;
  1135. if (dwNetworkServiceRights)
  1136. {
  1137. dwIndex++;
  1138. ea[dwIndex].grfAccessPermissions = dwNetworkServiceRights;
  1139. ea[dwIndex].grfAccessMode = SET_ACCESS;
  1140. ea[dwIndex].grfInheritance= NO_INHERITANCE;
  1141. ea[dwIndex].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  1142. ea[dwIndex].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  1143. ea[dwIndex].Trustee.ptstrName = (LPTSTR) pSidNetworkService;
  1144. }
  1145. if (dwAuthUsersAccessRights)
  1146. {
  1147. dwIndex++;
  1148. ea[dwIndex].grfAccessPermissions = dwAuthUsersAccessRights;
  1149. ea[dwIndex].grfAccessMode = SET_ACCESS;
  1150. ea[dwIndex].grfInheritance= NO_INHERITANCE;
  1151. ea[dwIndex].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  1152. ea[dwIndex].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  1153. ea[dwIndex].Trustee.ptstrName = (LPTSTR) pSidAuthUsers;
  1154. }
  1155. dwIndex++;
  1156. //
  1157. // Create a new ACL that contains the new ACE.
  1158. //
  1159. rc = SetEntriesInAcl(dwIndex,
  1160. ea,
  1161. NULL,
  1162. &pACL);
  1163. if (ERROR_SUCCESS != rc)
  1164. {
  1165. DebugPrintEx(
  1166. DEBUG_ERR,
  1167. TEXT("SetEntriesInAcl() failed (ec: %ld)"),
  1168. rc);
  1169. SetLastError (rc);
  1170. goto err_exit;
  1171. }
  1172. Assert (pACL);
  1173. //
  1174. // The ACL we just got contains a copy of the pSidAuthUsers, so we can discard pSidAuthUsers and pSidLocalSystem
  1175. //
  1176. if (pSidAuthUsers)
  1177. {
  1178. FreeSid (pSidAuthUsers);
  1179. pSidAuthUsers = NULL;
  1180. }
  1181. if (pSidNetworkService)
  1182. {
  1183. FreeSid (pSidNetworkService);
  1184. pSidNetworkService = NULL;
  1185. }
  1186. //
  1187. // Add the ACL to the security descriptor.
  1188. //
  1189. if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE))
  1190. {
  1191. DebugPrintEx(
  1192. DEBUG_ERR,
  1193. TEXT("SetSecurityDescriptorDacl() failed (ec: %ld)"),
  1194. GetLastError());
  1195. goto err_exit;
  1196. }
  1197. //
  1198. // All is fine, return the SA.
  1199. //
  1200. return pSA;
  1201. err_exit:
  1202. MemFree (pSA);
  1203. MemFree (pSD);
  1204. MemFree (pSidCurThread);
  1205. if (pSidAuthUsers)
  1206. {
  1207. FreeSid (pSidAuthUsers);
  1208. }
  1209. if (pSidNetworkService)
  1210. {
  1211. FreeSid (pSidNetworkService);
  1212. }
  1213. if (pACL)
  1214. {
  1215. LocalFree (pACL);
  1216. }
  1217. #endif // UNICODE
  1218. return NULL;
  1219. } // CreateSecurityAttributesWithThreadAsOwner
  1220. VOID
  1221. DestroySecurityAttributes (
  1222. SECURITY_ATTRIBUTES *pSA
  1223. )
  1224. /*++
  1225. Routine name : DestroySecurityAttributes
  1226. Routine description:
  1227. Frees data allocated by call to CreateSecurityAttributesWithThreadAsOwner
  1228. Author:
  1229. Eran Yariv (EranY), Aug, 2000
  1230. Arguments:
  1231. pSA [in] - Return value from CreateSecurityAttributesWithThreadAsOwner
  1232. Return Value:
  1233. None.
  1234. --*/
  1235. {
  1236. DEBUG_FUNCTION_NAME(TEXT("DestroySecurityAttributes"))
  1237. BOOL bDefaulted;
  1238. BOOL bPresent;
  1239. PSID pSid;
  1240. PACL pACL;
  1241. PSECURITY_DESCRIPTOR pSD;
  1242. Assert (pSA);
  1243. pSD = pSA->lpSecurityDescriptor;
  1244. Assert (pSD);
  1245. if (!GetSecurityDescriptorOwner (pSD, &pSid, &bDefaulted))
  1246. {
  1247. DebugPrintEx(
  1248. DEBUG_ERR,
  1249. TEXT("GetSecurityDescriptorOwner() failed (ec: %ld)"),
  1250. GetLastError());
  1251. ASSERT_FALSE;
  1252. }
  1253. else
  1254. {
  1255. //
  1256. // Free current thread's SID (SD owner)
  1257. //
  1258. MemFree (pSid);
  1259. }
  1260. if (!GetSecurityDescriptorDacl (pSD, &bPresent, &pACL, &bDefaulted))
  1261. {
  1262. DebugPrintEx(
  1263. DEBUG_ERR,
  1264. TEXT("GetSecurityDescriptorDacl() failed (ec: %ld)"),
  1265. GetLastError());
  1266. ASSERT_FALSE
  1267. }
  1268. else
  1269. {
  1270. //
  1271. // Free ACL
  1272. //
  1273. LocalFree (pACL);
  1274. }
  1275. MemFree (pSA);
  1276. MemFree (pSD);
  1277. } // DestroySecurityAttributes
  1278. DWORD
  1279. GetServiceStartupType (
  1280. LPCTSTR lpctstrMachine,
  1281. LPCTSTR lpctstrService,
  1282. LPDWORD lpdwStartupType
  1283. )
  1284. /*++
  1285. Routine name : GetServiceStartupType
  1286. Routine description:
  1287. Retreives the service startup type.
  1288. Author:
  1289. Eran Yariv (EranY), Jan, 2002
  1290. Arguments:
  1291. lpctstrMachine [in] - Machine where the service is installed
  1292. lpctstrService [in] - Service name
  1293. lpdwStartupType [out] - Service startup type. For example: SERVICE_AUTO_START, SERVICE_DISABLED, etc.
  1294. Return Value:
  1295. Standard Win32 error code
  1296. --*/
  1297. {
  1298. DWORD dwRes = ERROR_SUCCESS;
  1299. SC_HANDLE hScm = NULL;
  1300. SC_HANDLE hSvc = NULL;
  1301. BYTE bBuf[1000];
  1302. DWORD dwBufSize = sizeof (bBuf);
  1303. DWORD dwNeeded;
  1304. LPQUERY_SERVICE_CONFIG lpQSC = (LPQUERY_SERVICE_CONFIG)bBuf;
  1305. DEBUG_FUNCTION_NAME(TEXT("GetServiceStartupType"))
  1306. Assert (lpdwStartupType);
  1307. dwRes = FaxOpenService (lpctstrMachine, lpctstrService, &hScm, &hSvc, SC_MANAGER_CONNECT, SERVICE_QUERY_CONFIG, NULL);
  1308. if (ERROR_SUCCESS != dwRes)
  1309. {
  1310. return dwRes;
  1311. }
  1312. if (!QueryServiceConfig (hSvc, lpQSC, dwBufSize, &dwNeeded))
  1313. {
  1314. if (ERROR_INSUFFICIENT_BUFFER != GetLastError ())
  1315. {
  1316. //
  1317. // Some real error
  1318. //
  1319. dwRes = GetLastError ();
  1320. DebugPrintEx(
  1321. DEBUG_ERR,
  1322. TEXT("QueryServiceConfig failed with %ld"),
  1323. dwRes);
  1324. goto exit;
  1325. }
  1326. //
  1327. // Buffer size issues
  1328. //
  1329. lpQSC = (LPQUERY_SERVICE_CONFIG)MemAlloc (dwNeeded);
  1330. if (!lpQSC)
  1331. {
  1332. dwRes = GetLastError ();
  1333. DebugPrintEx(
  1334. DEBUG_ERR,
  1335. TEXT("MemAlloc(%d) failed"),
  1336. dwNeeded);
  1337. goto exit;
  1338. }
  1339. dwBufSize = dwNeeded;
  1340. if (!QueryServiceConfig (hSvc, lpQSC, dwBufSize, &dwNeeded))
  1341. {
  1342. //
  1343. // Any error now is serious
  1344. //
  1345. dwRes = GetLastError ();
  1346. DebugPrintEx(
  1347. DEBUG_ERR,
  1348. TEXT("QueryServiceConfig failed with %ld"),
  1349. dwRes);
  1350. goto exit;
  1351. }
  1352. //
  1353. // Success
  1354. //
  1355. dwRes = ERROR_SUCCESS;
  1356. }
  1357. Assert (ERROR_SUCCESS == dwRes);
  1358. *lpdwStartupType = lpQSC->dwStartType;
  1359. exit:
  1360. FaxCloseService (hScm, hSvc);
  1361. if (lpQSC && (lpQSC != (LPQUERY_SERVICE_CONFIG)bBuf))
  1362. {
  1363. MemFree (lpQSC);
  1364. }
  1365. return dwRes;
  1366. } // GetServiceStartupType
  1367. DWORD
  1368. SetServiceStartupType (
  1369. LPCTSTR lpctstrMachine,
  1370. LPCTSTR lpctstrService,
  1371. DWORD dwStartupType
  1372. )
  1373. /*++
  1374. Routine name : SetServiceStartupType
  1375. Routine description:
  1376. Sets the service startup type.
  1377. Author:
  1378. Eran Yariv (EranY), Jan, 2002
  1379. Arguments:
  1380. lpctstrMachine [in] - Machine where the service is installed
  1381. lpctstrService [in] - Service name
  1382. dwStartupType [in] - Service startup type. For example: SERVICE_AUTO_START, SERVICE_DISABLED, etc.
  1383. Return Value:
  1384. Standard Win32 error code
  1385. --*/
  1386. {
  1387. DWORD dwRes = ERROR_SUCCESS;
  1388. SC_HANDLE hScm = NULL;
  1389. SC_HANDLE hSvc = NULL;
  1390. DEBUG_FUNCTION_NAME(TEXT("SetServiceStartupType"))
  1391. dwRes = FaxOpenService (lpctstrMachine, lpctstrService, &hScm, &hSvc, SC_MANAGER_CONNECT, SERVICE_CHANGE_CONFIG, NULL);
  1392. if (ERROR_SUCCESS != dwRes)
  1393. {
  1394. return dwRes;
  1395. }
  1396. if (!ChangeServiceConfig (hSvc,
  1397. SERVICE_NO_CHANGE, // Service type
  1398. dwStartupType, // Startup
  1399. SERVICE_NO_CHANGE, // Error control
  1400. NULL, // Binary path - no change
  1401. NULL, // Load order group - no change
  1402. NULL, // Tag id - no change
  1403. NULL, // Dependencies - no change
  1404. NULL, // Service start name - no change
  1405. NULL, // Password - no change
  1406. NULL)) // Display name - no change
  1407. {
  1408. dwRes = GetLastError ();
  1409. DebugPrintEx(
  1410. DEBUG_ERR,
  1411. TEXT("ChangeServiceConfig failed with %ld"),
  1412. dwRes);
  1413. goto exit;
  1414. }
  1415. Assert (ERROR_SUCCESS == dwRes);
  1416. exit:
  1417. FaxCloseService (hScm, hSvc);
  1418. return dwRes;
  1419. } // SetServiceStartupType
  1420. DWORD
  1421. WaitForServiceStopOrStart (
  1422. SC_HANDLE hSvc,
  1423. BOOL bStop,
  1424. DWORD dwMaxWait
  1425. )
  1426. /*++
  1427. Routine name : WaitForServiceStopOrStart
  1428. Routine description:
  1429. Waits for a service to stop or start
  1430. Author:
  1431. Eran Yariv (EranY), Jan, 2002
  1432. Arguments:
  1433. hSvc [in] - Open service handle.
  1434. bStop [in] - TRUE if service was just stopped. FALSE if service was just started
  1435. dwMaxWait [in] - Max wait time (in millisecs).
  1436. Return Value:
  1437. Standard Win32 error code
  1438. --*/
  1439. {
  1440. SERVICE_STATUS Status;
  1441. DWORD dwRes = ERROR_SUCCESS;
  1442. DWORD dwOldCheckPoint = 0;
  1443. DWORD dwStartTick;
  1444. DWORD dwOldCheckPointTime;
  1445. DEBUG_FUNCTION_NAME(TEXT("WaitForServiceStopOrStart"))
  1446. if (!QueryServiceStatus(hSvc, &Status))
  1447. {
  1448. dwRes = GetLastError ();
  1449. DebugPrintEx(
  1450. DEBUG_ERR,
  1451. TEXT("QueryServiceStatus failed with %ld"),
  1452. dwRes);
  1453. return dwRes;
  1454. }
  1455. if (bStop)
  1456. {
  1457. if (SERVICE_STOPPED == Status.dwCurrentState)
  1458. {
  1459. //
  1460. // Service is already stopped
  1461. //
  1462. return dwRes;
  1463. }
  1464. }
  1465. else
  1466. {
  1467. if (SERVICE_RUNNING == Status.dwCurrentState)
  1468. {
  1469. //
  1470. // Service is already running
  1471. //
  1472. return dwRes;
  1473. }
  1474. }
  1475. //
  1476. // Let's wait for the service to start / stop
  1477. //
  1478. dwOldCheckPointTime = dwStartTick = GetTickCount ();
  1479. for (;;)
  1480. {
  1481. DWORD dwWait;
  1482. if (!QueryServiceStatus(hSvc, &Status))
  1483. {
  1484. dwRes = GetLastError ();
  1485. DebugPrintEx(
  1486. DEBUG_ERR,
  1487. TEXT("QueryServiceStatus failed with %ld"),
  1488. dwRes);
  1489. return dwRes;
  1490. }
  1491. //
  1492. // Let's see if all is ok now
  1493. //
  1494. if (bStop)
  1495. {
  1496. if (SERVICE_STOPPED == Status.dwCurrentState)
  1497. {
  1498. //
  1499. // Service is now stopped
  1500. //
  1501. return dwRes;
  1502. }
  1503. }
  1504. else
  1505. {
  1506. if (SERVICE_RUNNING == Status.dwCurrentState)
  1507. {
  1508. //
  1509. // Service is now running
  1510. //
  1511. return dwRes;
  1512. }
  1513. }
  1514. //
  1515. // Let's see if it's pending
  1516. //
  1517. if ((bStop && SERVICE_STOP_PENDING != Status.dwCurrentState) ||
  1518. (!bStop && SERVICE_START_PENDING != Status.dwCurrentState))
  1519. {
  1520. //
  1521. // Something is wrong
  1522. //
  1523. DebugPrintEx(
  1524. DEBUG_ERR,
  1525. TEXT("Service cannot be started / stopped. Current state is %ld"),
  1526. Status.dwCurrentState);
  1527. return ERROR_SERVICE_NOT_ACTIVE;
  1528. }
  1529. //
  1530. // Service is pending to stop / start
  1531. //
  1532. if (GetTickCount() - dwStartTick > dwMaxWait)
  1533. {
  1534. //
  1535. // We've waited too long (globally).
  1536. //
  1537. DebugPrintEx(
  1538. DEBUG_ERR,
  1539. TEXT("We've waited too long (globally)"));
  1540. return ERROR_TIMEOUT;
  1541. }
  1542. Assert (dwOldCheckPoint <= Status.dwCheckPoint);
  1543. if (dwOldCheckPoint >= Status.dwCheckPoint)
  1544. {
  1545. //
  1546. // Check point did not advance
  1547. //
  1548. if (GetTickCount() - dwOldCheckPointTime >= Status.dwWaitHint)
  1549. {
  1550. //
  1551. // We've been waiting on the same checkpoint for more than the recommended hint.
  1552. // Something is wrong.
  1553. //
  1554. DebugPrintEx(
  1555. DEBUG_ERR,
  1556. TEXT("We've been waiting on the same checkpoint for more than the recommend hint"));
  1557. return ERROR_TIMEOUT;
  1558. }
  1559. }
  1560. else
  1561. {
  1562. //
  1563. // Check point advanced
  1564. //
  1565. dwOldCheckPoint = Status.dwCheckPoint;
  1566. dwOldCheckPointTime = GetTickCount();
  1567. }
  1568. //
  1569. // Never sleep longer than 5 seconds
  1570. //
  1571. dwWait = min (Status.dwWaitHint / 2, 1000 * 5);
  1572. Sleep (dwWait);
  1573. }
  1574. return ERROR_SUCCESS;
  1575. } // WaitForServiceStopOrStart
  1576. DWORD
  1577. StartServiceEx (
  1578. LPCTSTR lpctstrMachine,
  1579. LPCTSTR lpctstrService,
  1580. DWORD dwNumArgs,
  1581. LPCTSTR*lppctstrCommandLineArgs,
  1582. DWORD dwMaxWait
  1583. )
  1584. /*++
  1585. Routine name : StartServiceEx
  1586. Routine description:
  1587. Starts a service
  1588. Author:
  1589. Eran Yariv (EranY), Jan, 2002
  1590. Arguments:
  1591. lpctstrMachine [in] - Machine where service is installed
  1592. lpctstrService [in] - Service name
  1593. dwNumArgs [in] - Number of service command line arguments
  1594. lppctstrCommandLineArgs [in] - Command line strings.
  1595. dwMaxWait [in] - Max time to wait for service to start (millisecs)
  1596. Return Value:
  1597. Standard Win32 error code
  1598. --*/
  1599. {
  1600. DWORD dwRes = ERROR_SUCCESS;
  1601. SC_HANDLE hScm = NULL;
  1602. SC_HANDLE hSvc = NULL;
  1603. DWORD dwStatus;
  1604. DEBUG_FUNCTION_NAME(TEXT("StartServiceEx"))
  1605. dwRes = FaxOpenService(lpctstrMachine,
  1606. lpctstrService,
  1607. &hScm,
  1608. &hSvc,
  1609. SC_MANAGER_CONNECT,
  1610. SERVICE_QUERY_STATUS | SERVICE_START,
  1611. &dwStatus);
  1612. if (ERROR_SUCCESS != dwRes)
  1613. {
  1614. return dwRes;
  1615. }
  1616. if (SERVICE_RUNNING == dwStatus)
  1617. {
  1618. //
  1619. // Service is already running
  1620. //
  1621. goto exit;
  1622. }
  1623. //
  1624. // Start the sevice
  1625. //
  1626. if (!StartService(hSvc, dwNumArgs, lppctstrCommandLineArgs))
  1627. {
  1628. DebugPrintEx(
  1629. DEBUG_ERR,
  1630. TEXT("StartService failed with %ld"),
  1631. GetLastError ());
  1632. goto exit;
  1633. }
  1634. if (dwMaxWait > 0)
  1635. {
  1636. //
  1637. // User wants us to wait for the service to stop.
  1638. //
  1639. dwRes = WaitForServiceStopOrStart (hSvc, FALSE, dwMaxWait);
  1640. }
  1641. exit:
  1642. FaxCloseService (hScm, hSvc);
  1643. return dwRes;
  1644. } // StartServiceEx
  1645. DWORD
  1646. SetServiceFailureActions (
  1647. LPCTSTR lpctstrMachine,
  1648. LPCTSTR lpctstrService,
  1649. LPSERVICE_FAILURE_ACTIONS lpFailureActions
  1650. )
  1651. /*++
  1652. Routine name : SetServiceFailureActions
  1653. Routine description:
  1654. Sets the failure actions for a given service.
  1655. For more information, refer to the SERVICE_FAILURE_ACTIONS structure documentation and the
  1656. ChangeServiceConfig2 function documentation.
  1657. Author:
  1658. Eran Yariv (EranY), May, 2002
  1659. Arguments:
  1660. lpctstrMachine [in] - Machine where service is installed
  1661. lpctstrService [in] - Service name
  1662. lpFailureActions [in] - Failure actions information
  1663. Return Value:
  1664. Standard Win32 error code
  1665. --*/
  1666. {
  1667. DWORD dwRes = ERROR_SUCCESS;
  1668. SC_HANDLE hScm = NULL;
  1669. SC_HANDLE hSvc = NULL;
  1670. DEBUG_FUNCTION_NAME(TEXT("SetServiceFailureActions"))
  1671. dwRes = FaxOpenService(lpctstrMachine,
  1672. lpctstrService,
  1673. &hScm,
  1674. &hSvc,
  1675. SC_MANAGER_CONNECT,
  1676. SERVICE_CHANGE_CONFIG | SERVICE_START,
  1677. NULL);
  1678. if (ERROR_SUCCESS != dwRes)
  1679. {
  1680. return dwRes;
  1681. }
  1682. if (!ChangeServiceConfig2(hSvc, SERVICE_CONFIG_FAILURE_ACTIONS, lpFailureActions))
  1683. {
  1684. dwRes = GetLastError ();
  1685. DebugPrintEx(
  1686. DEBUG_ERR,
  1687. TEXT("ChangeServiceConfig2 failed with %ld"),
  1688. dwRes);
  1689. goto exit;
  1690. }
  1691. exit:
  1692. FaxCloseService (hScm, hSvc);
  1693. return dwRes;
  1694. } // SetServiceFailureActions