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.

2222 lines
63 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. faxsvc.c
  5. Abstract:
  6. This module contains the service specific code.
  7. Author:
  8. Wesley Witt (wesw) 16-Jan-1996
  9. Revision History:
  10. --*/
  11. #include "faxsvc.h"
  12. #pragma hdrstop
  13. #include <ExpDef.h>
  14. #include <ErrorRep.h>
  15. class CComBSTR;
  16. #define SERVICE_DEBUG_LOG_FILE _T("FXSSVCDebugLogFile.txt")
  17. static SERVICE_STATUS gs_FaxServiceStatus;
  18. static SERVICE_STATUS_HANDLE gs_FaxServiceStatusHandle;
  19. static LPCWSTR gs_lpcwstrUnhandledExceptionSourceName; // Points to the friendly name of the last
  20. // FSP / R.Ext which caused an unhandled
  21. // exception in a direct function call.
  22. // Used for event logging
  23. // in FaxUnhandledExceptionFilter().
  24. static EXCEPTION_SOURCE_TYPE gs_UnhandledExceptionSource; // Specifies the source of an unhandled
  25. // exception.
  26. // Used for event logging
  27. // in FaxUnhandledExceptionFilter().
  28. static DWORD gs_dwUnhandledExceptionCode; // Holds the exception code of the last
  29. // unhandled exception in a direct function call
  30. // to an FSP / R.Ext
  31. // Used for event logging
  32. // in FaxUnhandledExceptionFilter().
  33. static BOOL gs_bUseDefaultFaultHandlingPolicy; // Read from the registry during service
  34. // startup. If non-zero, FaxUnhandledExceptionFilter
  35. // behaves as if it did not exist.
  36. HANDLE g_hServiceShutDownEvent; // This event is set after the service got g_hSCMServiceShutDownEvent from SCM and signals the various threads to terminate!
  37. HANDLE g_hSCMServiceShutDownEvent; // This event is set when SCM tells the service to STOP!
  38. HANDLE g_hServiceIsDownSemaphore; // This semaphore is used to synchronize TapiWorkerThread() JobQueueThread() and EndFaxSvc()
  39. SERVICE_TABLE_ENTRY ServiceDispatchTable[] = {
  40. { FAX_SERVICE_NAME, FaxServiceMain },
  41. { NULL, NULL }
  42. };
  43. static
  44. BOOL
  45. InitializeFaxLibrariesGlobals(
  46. VOID
  47. )
  48. /*++
  49. Routine Description:
  50. Initialize Fax libraries globals.
  51. Becuase the process is not always terminated when the service is stopped,
  52. We must not have any staticly initialized global variables.
  53. Initialize all fax libraries global variables before starting the service
  54. Arguments:
  55. None.
  56. Return Value:
  57. BOOL
  58. --*/
  59. {
  60. BOOL bRet = TRUE;
  61. DEBUG_FUNCTION_NAME(TEXT("InitializeFaxLibraries"));
  62. if (!FXSEVENTInitialize())
  63. {
  64. DebugPrintEx(DEBUG_ERR,
  65. TEXT("FXSEVENTInitialize failed"));
  66. bRet = FALSE;
  67. }
  68. if (!FXSTIFFInitialize())
  69. {
  70. DebugPrintEx(DEBUG_ERR,
  71. TEXT("FXSTIFFInitialize failed"));
  72. bRet = FALSE;
  73. }
  74. return bRet;
  75. }
  76. static
  77. VOID
  78. FreeFaxLibrariesGlobals(
  79. VOID
  80. )
  81. /*++
  82. Routine Description:
  83. Frees Fax libraries globals.
  84. Arguments:
  85. None.
  86. Return Value:
  87. BOOL
  88. --*/
  89. {
  90. FXSEVENTFree();
  91. HeapCleanup();
  92. return;
  93. }
  94. static
  95. BOOL
  96. InitializeServiceGlobals(
  97. VOID
  98. )
  99. /*++
  100. Routine Description:
  101. Initialize service globals.
  102. Becuase the process is not always terminated when the service is stopped,
  103. We must not have any staticly initialized global variables.
  104. Initialize all service global variables before starting the service
  105. Arguments:
  106. None.
  107. Return Value:
  108. BOOL
  109. --*/
  110. {
  111. DWORD Index;
  112. DWORD ec = ERROR_SUCCESS;
  113. DEBUG_FUNCTION_NAME(TEXT("InitializeServiceGlobals"));
  114. //
  115. // Initialize static allocated globals
  116. //
  117. g_pFaxPerfCounters = NULL;
  118. #ifdef DBG
  119. g_hCritSecLogFile = INVALID_HANDLE_VALUE;
  120. #endif
  121. gs_lpcwstrUnhandledExceptionSourceName = NULL;
  122. gs_UnhandledExceptionSource = EXCEPTION_SOURCE_UNKNOWN;
  123. gs_dwUnhandledExceptionCode = 0;
  124. gs_bUseDefaultFaultHandlingPolicy = FALSE;
  125. ZeroMemory (&g_ReceiptsConfig, sizeof(g_ReceiptsConfig)); // Global receipts configuration
  126. g_ReceiptsConfig.dwSizeOfStruct = sizeof(g_ReceiptsConfig);
  127. ZeroMemory (g_ArchivesConfig, sizeof(g_ArchivesConfig)); // Global archives configuration
  128. g_ArchivesConfig[0].dwSizeOfStruct = sizeof(g_ArchivesConfig[0]);
  129. g_ArchivesConfig[1].dwSizeOfStruct = sizeof(g_ArchivesConfig[1]);
  130. ZeroMemory (&g_ActivityLoggingConfig, sizeof(g_ActivityLoggingConfig)); // Global activity logging configuration
  131. g_ActivityLoggingConfig.dwSizeOfStruct = sizeof(g_ActivityLoggingConfig);
  132. ZeroMemory (&g_ServerActivity, sizeof(g_ServerActivity)); // Global Fax Service Activity
  133. g_ServerActivity.dwSizeOfStruct = sizeof(FAX_SERVER_ACTIVITY);
  134. ZeroMemory (g_wszFaxQueueDir, sizeof(g_wszFaxQueueDir));
  135. g_hDispatchEventsCompPort = NULL; // Dispatch Events completion port
  136. g_hSendEventsCompPort = NULL; // Send Events completion port = NULL; // Events completion port
  137. g_dwlClientID = 0; // Client ID
  138. ZeroMemory (g_FaxQuotaWarn, sizeof(g_FaxQuotaWarn));
  139. g_hArchiveQuotaWarningEvent = NULL;
  140. g_dwConnectionCount = 0; // Represents the number of active rpc connections.
  141. g_hInboxActivityLogFile = INVALID_HANDLE_VALUE;
  142. g_hOutboxActivityLogFile = INVALID_HANDLE_VALUE;
  143. g_fLogStringTableInit = FALSE; // activity logging string table
  144. g_dwQueueCount = 0; // Count of jobs (both parent and non-parent) in the queue. Protected by g_CsQueue
  145. g_hJobQueueEvent = NULL;
  146. g_dwQueueState = 0;
  147. g_ScanQueueAfterTimeout = FALSE; // The JobQueueThread checks this if waked up after JOB_QUEUE_TIMEOUT.
  148. // If it is TRUE - g_hQueueTimer or g_hJobQueueEvent were not set - Scan the queue.
  149. g_dwReceiveDevicesCount = 0; // Count of devices that are receive-enabled. Protected by g_CsLine.
  150. g_bDelaySuicideAttempt = FALSE; // If TRUE, the service waits
  151. // before checking if it can commit suicide.
  152. // Initially FALSE, can be set to true if the service is launched
  153. // with SERVICE_DELAY_SUICIDE command line parameter.
  154. g_bServiceCanSuicide = TRUE;
  155. g_dwCountRoutingMethods = 0;
  156. g_pLineCountryList = NULL;
  157. g_dwLastUniqueId = 0;
  158. g_bServiceIsDown = FALSE; // This is set to TRUE by FaxEndSvc()
  159. g_TapiCompletionPort = NULL;
  160. g_hLineApp = NULL;
  161. g_pAdaptiveFileBuffer = NULL;
  162. gs_FaxServiceStatus.dwServiceType = SERVICE_WIN32;
  163. gs_FaxServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  164. gs_FaxServiceStatus.dwWin32ExitCode = 0;
  165. gs_FaxServiceStatus.dwServiceSpecificExitCode = 0;
  166. gs_FaxServiceStatus.dwCheckPoint = 0;
  167. gs_FaxServiceStatus.dwWaitHint = 0;
  168. g_hRPCListeningThread = NULL;
  169. g_lServiceThreadsCount = 0;
  170. g_hThreadCountEvent = NULL;
  171. g_dwAllowRemote = 0; // By default, do not allow remote calls if the printer is not shared.
  172. for (Index = 0; Index < gc_dwCountInboxTable; Index++)
  173. {
  174. g_InboxTable[Index].String = NULL;
  175. }
  176. for (Index = 0; Index < gc_dwCountOutboxTable; Index++)
  177. {
  178. g_OutboxTable[Index].String = NULL;
  179. }
  180. for (Index = 0; Index < gc_dwCountServiceStringTable; Index++)
  181. {
  182. g_ServiceStringTable[Index].String = NULL;
  183. }
  184. g_StatusCompletionPortHandle = NULL;
  185. g_pFaxSD = NULL;
  186. g_dwDeviceCount = 0;
  187. g_dwDeviceEnabledCount = 0;
  188. g_dwDeviceEnabledLimit = GetDeviceLimit();
  189. g_hFaxPerfCountersMap = 0;
  190. g_hTapiWorkerThread = NULL;
  191. g_hJobQueueThread = NULL;
  192. g_dwRecipientsLimit = 0;
  193. g_hResource = GetResInstance(NULL);
  194. if(!g_hResource)
  195. {
  196. ec = GetLastError();
  197. goto Error;
  198. }
  199. //
  200. // Create an event to signal service shutdown from service to various threads
  201. //
  202. g_hServiceShutDownEvent = CreateEvent(
  203. NULL, // SD
  204. TRUE, // reset type - Manual
  205. FALSE, // initial state - Not signaled. The event is signaled when the service gets g_hSCMServiceShutDownEvent
  206. NULL // object name
  207. );
  208. if (NULL == g_hServiceShutDownEvent)
  209. {
  210. ec = GetLastError();
  211. DebugPrintEx(DEBUG_ERR,
  212. TEXT("CreateEvent (g_hServiceShutDownEvent) failed (ec: %ld)"),
  213. ec);
  214. goto Error;
  215. }
  216. //
  217. // Create an event used by SCM to signal service shutdown
  218. //
  219. g_hSCMServiceShutDownEvent = CreateEvent(
  220. NULL, // SD
  221. TRUE, // reset type - Manual
  222. FALSE, // initial state - Not signaled. The event is signaled when the service gets SERVICE_CONTROL_STOP or SERVICE_CONTROL_SHUTDOWN.
  223. NULL // object name
  224. );
  225. if (NULL == g_hSCMServiceShutDownEvent)
  226. {
  227. ec = GetLastError();
  228. DebugPrintEx(DEBUG_ERR,
  229. TEXT("CreateEvent (g_hSCMServiceShutDownEvent) failed (ec: %ld)"),
  230. ec);
  231. goto Error;
  232. }
  233. //
  234. // Create a semaphore to syncronize TapiWorkerThread() JobQueueThread() and EndFaxSvc()
  235. //
  236. g_hServiceIsDownSemaphore = CreateSemaphore(
  237. NULL, // SD
  238. 0, // initial count - Not signaled
  239. 2, // maximum count - JobQueueThread and TapiWorkerThread
  240. NULL // object name
  241. );
  242. if (NULL == g_hServiceIsDownSemaphore)
  243. {
  244. ec = GetLastError();
  245. DebugPrintEx(DEBUG_ERR,
  246. TEXT("CreateSemaphore (g_hServiceIsDownSemaphore) failed (ec: %ld)"),
  247. ec);
  248. goto Error;
  249. }
  250. //
  251. // Try to init some global critical sections
  252. //
  253. #ifdef DBG
  254. if (!g_CsCritSecList.Initialize())
  255. {
  256. ec = GetLastError();
  257. DebugPrintEx(
  258. DEBUG_ERR,
  259. TEXT("CFaxCriticalSection::Initialize failed: err = %d"),
  260. ec);
  261. goto Error;
  262. }
  263. #endif
  264. if (!g_CsConfig.Initialize() ||
  265. !g_CsInboundActivityLogging.Initialize() ||
  266. !g_CsOutboundActivityLogging.Initialize() ||
  267. !g_CsJob.Initialize() ||
  268. !g_CsQueue.Initialize() ||
  269. !g_CsPerfCounters.Initialize() ||
  270. !g_CsSecurity.Initialize() ||
  271. !g_csUniqueQueueFile.Initialize() ||
  272. !g_CsLine.Initialize() ||
  273. !g_CsRouting.Initialize() ||
  274. !g_CsServiceThreads.Initialize() ||
  275. !g_CsHandleTable.Initialize() ||
  276. !g_CsActivity.Initialize() ||
  277. !g_CsClients.Initialize())
  278. {
  279. ec = GetLastError();
  280. DebugPrintEx(
  281. DEBUG_ERR,
  282. TEXT("CFaxCriticalSection::Initialize failed: err = %d"),
  283. ec);
  284. goto Error;
  285. }
  286. //
  287. // Initialize service linked lists
  288. //
  289. InitializeListHead( &g_DeviceProvidersListHead );
  290. InitializeListHead( &g_HandleTableListHead );
  291. InitializeListHead( &g_JobListHead );
  292. InitializeListHead( &g_QueueListHead );
  293. InitializeListHead( &g_QueueListHead);
  294. InitializeListHead( &g_lstRoutingExtensions );
  295. InitializeListHead( &g_lstRoutingMethods );
  296. #if DBG
  297. InitializeListHead( &g_CritSecListHead );
  298. #endif
  299. InitializeListHead( &g_TapiLinesListHead );
  300. InitializeListHead( &g_RemovedTapiLinesListHead );
  301. //
  302. // Initialize dynamic allocated global classes
  303. //
  304. g_pClientsMap = NULL;
  305. g_pNotificationMap = NULL;
  306. g_pTAPIDevicesIdsMap = NULL;
  307. g_pGroupsMap = NULL;
  308. g_pRulesMap = NULL;
  309. g_pClientsMap = new (std::nothrow) CClientsMap;
  310. if (NULL == g_pClientsMap)
  311. {
  312. ec = ERROR_NOT_ENOUGH_MEMORY;
  313. goto Error;
  314. }
  315. g_pNotificationMap = new (std::nothrow) CNotificationMap;
  316. if (NULL == g_pNotificationMap)
  317. {
  318. ec = ERROR_NOT_ENOUGH_MEMORY;
  319. goto Error;
  320. }
  321. g_pTAPIDevicesIdsMap = new (std::nothrow) CMapDeviceId;
  322. if (NULL == g_pTAPIDevicesIdsMap)
  323. {
  324. ec = ERROR_NOT_ENOUGH_MEMORY;
  325. goto Error;
  326. }
  327. g_pGroupsMap = new (std::nothrow) COutboundRoutingGroupsMap;
  328. if (NULL == g_pGroupsMap)
  329. {
  330. ec = ERROR_NOT_ENOUGH_MEMORY;
  331. goto Error;
  332. }
  333. g_pRulesMap = new (std::nothrow) COutboundRulesMap;
  334. if (NULL == g_pRulesMap)
  335. {
  336. ec = ERROR_NOT_ENOUGH_MEMORY;
  337. goto Error;
  338. }
  339. return TRUE;
  340. Error:
  341. Assert(ec != ERROR_SUCCESS);
  342. SetLastError (ec);
  343. return FALSE;
  344. }
  345. LONG
  346. HandleFaxExtensionFault (
  347. EXCEPTION_SOURCE_TYPE ExSrc,
  348. LPCWSTR lpcswstrExtFriendlyName,
  349. DWORD dwCode
  350. )
  351. /*++
  352. Routine Description:
  353. This function handles all exceptions thrown as a result from direct calls into fax extensions (FSPs and routing extensions).
  354. All it does is store the friendly name of the FSP/R.Ext and the exception code and re-throws the exception.
  355. It should be used as an exception filter in the __except keyword.
  356. The FaxUnhandledExceptionFilter() function uses that store information to log an event message.
  357. Arguments:
  358. ExSrc - [in] The source of the exception (FSP / R.Ext)
  359. lpcswstrExtFriendlyName - [in] Extension friendly name
  360. dwCode - [in] Exception code
  361. Return Value:
  362. Exception handling code
  363. --*/
  364. {
  365. DEBUG_FUNCTION_NAME(TEXT("HandleFaxExtensionFault"));
  366. Assert (lpcswstrExtFriendlyName);
  367. Assert (ExSrc > EXCEPTION_SOURCE_UNKNOWN);
  368. Assert (ExSrc <= EXCEPTION_SOURCE_ROUTING_EXT);
  369. gs_lpcwstrUnhandledExceptionSourceName = lpcswstrExtFriendlyName;
  370. gs_UnhandledExceptionSource = ExSrc;
  371. gs_dwUnhandledExceptionCode = dwCode;
  372. return EXCEPTION_CONTINUE_SEARCH;
  373. } // HandleFaxExtensionFault
  374. LONG FaxUnhandledExceptionFilter(
  375. _EXCEPTION_POINTERS *pExceptionInfo
  376. )
  377. /*++
  378. Routine Description:
  379. This function serves as the catch-all exception handler for the entire process.
  380. When an unhandled exception is thrown, this function will be called and:
  381. 1. Increase unhandled exceptions count
  382. 2. For first unhandled exception only
  383. 2.1. Generate a Dr. Watson report
  384. 2.2. Write an event log entry
  385. 2.3. Attempt to shut down all FSPs
  386. 3. Terminate the process
  387. Arguments:
  388. pExceptionInfo - Pointer to exception information
  389. Return Value:
  390. Exception handling code
  391. Remarks:
  392. This function gets called by kernel32!UnhandledExceptionFilterEx.
  393. kernel32!UnhandledExceptionFilterEx doesn't call this function if a debugger is attached
  394. while a unhandled exception occurs. Instead, it returns EXCEPTION_CONTINUE_SEARCH which let's
  395. the debugger handle the 2nd chance exception.
  396. If this function returns EXCEPTION_EXECUTE_HANDLER, kernel32!UnhandledExceptionFilterEx does nothing and
  397. kernel32!BaseThreadStart calls kernel32!ExitProcess.
  398. This basically means:
  399. - No GP fault UI
  400. - No Dr. Watson report (direct or queued)
  401. - No support for AeDebug in the registry for attaching a debugger to a crashing process
  402. if this function EXCEPTION_CONTINUE_SEARCH, kernel32!UnhandledExceptionFilterEx acts normally.
  403. This basically means:
  404. - GP fault UI (which might be disabled by calling SetErrorMode(), which we never do)
  405. - A Dr. Watson report is generated
  406. - AeDebug support is enabled
  407. - If none of the above is used, kernel32!BaseThreadStart calls kernel32!ExitProcess
  408. --*/
  409. {
  410. static volatile long lFaultCount = 0;
  411. DEBUG_FUNCTION_NAME(TEXT("FaxUnhandledExceptionFilter"));
  412. DebugPrintEx (
  413. DEBUG_MSG,
  414. TEXT("Unhandled exception from %s (code %d)."),
  415. gs_lpcwstrUnhandledExceptionSourceName,
  416. gs_dwUnhandledExceptionCode);
  417. if (STATUS_BREAKPOINT == pExceptionInfo->ExceptionRecord->ExceptionCode)
  418. {
  419. //
  420. // Debug break exception caught here.
  421. // Make sure the user sees the normal system behavior.
  422. //
  423. DebugPrintEx (DEBUG_MSG, TEXT("Debug break exception caught."));
  424. return EXCEPTION_CONTINUE_SEARCH;
  425. }
  426. if (1 == InterlockedIncrement (&lFaultCount))
  427. {
  428. if (gs_bUseDefaultFaultHandlingPolicy)
  429. {
  430. //
  431. // User chose (in the registry) to disable the SCM revival feature by using the
  432. // system's default fault handling policy.
  433. //
  434. DebugPrintEx (DEBUG_MSG, TEXT("UseDefaultFaultHandlingPolicy is set. Exception is ignored to be handled by the system."));
  435. return EXCEPTION_CONTINUE_SEARCH;
  436. }
  437. // First unhandled exception caught here.
  438. // Try to nicely shutdown the FSPs.
  439. // Start by generating a Dr. Watson report.
  440. //
  441. EFaultRepRetVal ret = ReportFault (pExceptionInfo, 0);
  442. if (frrvOk != ret &&
  443. frrvOkHeadless != ret &&
  444. frrvOkQueued != ret &&
  445. frrvOkManifest != ret)
  446. {
  447. //
  448. // Error generating a Dr. Watson report
  449. //
  450. DebugPrintEx (
  451. DEBUG_MSG,
  452. TEXT("ReportFault failed with %ld."),
  453. ret);
  454. }
  455. //
  456. // Log a fault event entry
  457. //
  458. switch (gs_UnhandledExceptionSource)
  459. {
  460. case EXCEPTION_SOURCE_UNKNOWN:
  461. FaxLog(FAXLOG_CATEGORY_UNKNOWN,
  462. FAXLOG_LEVEL_MIN,
  463. 1,
  464. MSG_FAX_GENERAL_FAULT,
  465. DWORD2HEX(gs_dwUnhandledExceptionCode)
  466. );
  467. break;
  468. case EXCEPTION_SOURCE_FSP:
  469. FaxLog(FAXLOG_CATEGORY_UNKNOWN,
  470. FAXLOG_LEVEL_MIN,
  471. 2,
  472. MSG_FAX_FSP_GENERAL_FAULT,
  473. gs_lpcwstrUnhandledExceptionSourceName,
  474. DWORD2HEX(gs_dwUnhandledExceptionCode)
  475. );
  476. break;
  477. case EXCEPTION_SOURCE_ROUTING_EXT:
  478. FaxLog(FAXLOG_CATEGORY_UNKNOWN,
  479. FAXLOG_LEVEL_MIN,
  480. 2,
  481. MSG_FAX_ROUTING_EXT_GENERAL_FAULT,
  482. gs_lpcwstrUnhandledExceptionSourceName,
  483. DWORD2HEX(gs_dwUnhandledExceptionCode)
  484. );
  485. break;
  486. default:
  487. ASSERT_FALSE;
  488. break;
  489. }
  490. //
  491. // Attempt to gracefully stop the FSPs.
  492. // This is crucial for releasing the H/W to the correct state before our process gets killed.
  493. //
  494. StopAllInProgressJobs();
  495. StopFaxServiceProviders();
  496. //
  497. // Ask kernel32!BaseThreadStart to call kernel32!ExitProcess
  498. //
  499. return EXCEPTION_EXECUTE_HANDLER;
  500. }
  501. else
  502. {
  503. //
  504. // Fault caught while shutting down.
  505. //
  506. DebugPrintEx (
  507. DEBUG_MSG,
  508. TEXT("Unhandled exception number %d from %s (code %d) ignored."),
  509. lFaultCount,
  510. gs_lpcwstrUnhandledExceptionSourceName,
  511. gs_dwUnhandledExceptionCode);
  512. //
  513. // Ask kernel32!BaseThreadStart to call kernel32!ExitProcess
  514. //
  515. return EXCEPTION_EXECUTE_HANDLER;
  516. }
  517. } // FaxUnhandledExceptionFilter
  518. #ifdef __cplusplus
  519. extern "C"
  520. #endif
  521. int
  522. WINAPI
  523. #ifdef UNICODE
  524. wWinMain(
  525. #else
  526. WinMain(
  527. #endif
  528. HINSTANCE hInstance,
  529. HINSTANCE hPrevInstance,
  530. LPTSTR lpCmdLine,
  531. int nShowCmd
  532. );
  533. int
  534. WINAPI
  535. #ifdef UNICODE
  536. wWinMain(
  537. #else
  538. WinMain(
  539. #endif
  540. HINSTANCE hInstance,
  541. HINSTANCE hPrevInstance,
  542. LPTSTR lpCmdLine,
  543. int nShowCmd
  544. )
  545. /*++
  546. Routine Description:
  547. Main entry point for the TIFF image viewer.
  548. Arguments:
  549. hInstance - Instance handle
  550. hPrevInstance - Not used
  551. lpCmdLine - Command line arguments
  552. nShowCmd - How to show the window
  553. Return Value:
  554. Return code, zero for success.
  555. --*/
  556. {
  557. DWORD ec = ERROR_SUCCESS;
  558. DEBUG_FUNCTION_NAME(TEXT("WinMain"));
  559. OPEN_DEBUG_FILE (SERVICE_DEBUG_LOG_FILE);
  560. if (!StartServiceCtrlDispatcher( ServiceDispatchTable))
  561. {
  562. ec = GetLastError();
  563. DebugPrintEx (
  564. DEBUG_ERR,
  565. TEXT("StartServiceCtrlDispatcher error =%d"),
  566. ec);
  567. }
  568. CLOSE_DEBUG_FILE;
  569. return ec;
  570. }
  571. static
  572. VOID
  573. FreeServiceGlobals (
  574. VOID
  575. )
  576. {
  577. DWORD Index;
  578. DEBUG_FUNCTION_NAME(TEXT("FreeServiceGlobals"));
  579. //
  580. // Delete all global critical sections
  581. //
  582. g_CsHandleTable.SafeDelete();
  583. #ifdef DBG
  584. g_CsCritSecList.SafeDelete();
  585. #endif
  586. g_CsConfig.SafeDelete();
  587. g_CsInboundActivityLogging.SafeDelete();
  588. g_CsOutboundActivityLogging.SafeDelete();
  589. g_CsJob.SafeDelete();
  590. g_CsQueue.SafeDelete();
  591. g_CsPerfCounters.SafeDelete();
  592. g_CsSecurity.SafeDelete();
  593. g_csUniqueQueueFile.SafeDelete();
  594. g_CsLine.SafeDelete();
  595. g_CsRouting.SafeDelete();
  596. g_CsActivity.SafeDelete();
  597. g_CsClients.SafeDelete();
  598. g_CsServiceThreads.SafeDelete();
  599. if (g_pClientsMap)
  600. {
  601. delete g_pClientsMap;
  602. g_pClientsMap = NULL;
  603. }
  604. if (g_pNotificationMap)
  605. {
  606. delete g_pNotificationMap;
  607. g_pNotificationMap = NULL;
  608. }
  609. if (g_pTAPIDevicesIdsMap)
  610. {
  611. delete g_pTAPIDevicesIdsMap;
  612. g_pTAPIDevicesIdsMap = NULL;
  613. }
  614. if (g_pGroupsMap)
  615. {
  616. delete g_pGroupsMap;
  617. g_pGroupsMap = NULL;
  618. }
  619. if (g_pRulesMap)
  620. {
  621. delete g_pRulesMap;
  622. g_pRulesMap = NULL;
  623. }
  624. //
  625. // Close global Handles and free globaly allocated memory
  626. //
  627. if (NULL != g_pFaxSD)
  628. {
  629. if (!DestroyPrivateObjectSecurity (&g_pFaxSD))
  630. {
  631. DebugPrintEx(
  632. DEBUG_ERR,
  633. TEXT("DestroyPrivateObjectSecurity() failed. (ec: %ld)"),
  634. GetLastError());
  635. }
  636. g_pFaxSD = NULL;
  637. }
  638. if (INVALID_HANDLE_VALUE != g_hOutboxActivityLogFile)
  639. {
  640. if (!CloseHandle (g_hOutboxActivityLogFile))
  641. {
  642. DebugPrintEx(DEBUG_ERR,
  643. TEXT("CloseHandle failed (ec: %ld)"),
  644. GetLastError());
  645. }
  646. g_hOutboxActivityLogFile = INVALID_HANDLE_VALUE;
  647. }
  648. if (INVALID_HANDLE_VALUE != g_hInboxActivityLogFile)
  649. {
  650. if (!CloseHandle (g_hInboxActivityLogFile))
  651. {
  652. DebugPrintEx(DEBUG_ERR,
  653. TEXT("CloseHandle failed (ec: %ld)"),
  654. GetLastError());
  655. }
  656. g_hInboxActivityLogFile = INVALID_HANDLE_VALUE;
  657. }
  658. #if DBG
  659. if (INVALID_HANDLE_VALUE != g_hCritSecLogFile)
  660. {
  661. CloseHandle(g_hCritSecLogFile);
  662. g_hCritSecLogFile = INVALID_HANDLE_VALUE;
  663. }
  664. #endif
  665. if (NULL != g_hSendEventsCompPort)
  666. {
  667. if (!CloseHandle (g_hSendEventsCompPort))
  668. {
  669. DebugPrintEx(DEBUG_ERR,
  670. TEXT("CloseHandle failed (ec: %ld)"),
  671. GetLastError());
  672. }
  673. g_hSendEventsCompPort = NULL;
  674. }
  675. if (NULL != g_hDispatchEventsCompPort)
  676. {
  677. if (!CloseHandle (g_hDispatchEventsCompPort))
  678. {
  679. DebugPrintEx(DEBUG_ERR,
  680. TEXT("CloseHandle failed (ec: %ld)"),
  681. GetLastError());
  682. }
  683. g_hDispatchEventsCompPort = NULL;
  684. }
  685. if (NULL != g_hArchiveQuotaWarningEvent)
  686. {
  687. if (!CloseHandle(g_hArchiveQuotaWarningEvent))
  688. {
  689. DebugPrintEx(
  690. DEBUG_ERR,
  691. TEXT("Failed to close archive config event handle - quota warnings [handle = %p] (ec=0x%08x)."),
  692. g_hArchiveQuotaWarningEvent,
  693. GetLastError());
  694. }
  695. g_hArchiveQuotaWarningEvent = NULL;
  696. }
  697. for (Index = 0; Index < gc_dwCountInboxTable; Index++)
  698. {
  699. MemFree(g_InboxTable[Index].String);
  700. g_InboxTable[Index].String = NULL;
  701. }
  702. for (Index = 0; Index < gc_dwCountOutboxTable; Index++)
  703. {
  704. MemFree(g_OutboxTable[Index].String);
  705. g_OutboxTable[Index].String = NULL;
  706. }
  707. for (Index = 0; Index < gc_dwCountServiceStringTable; Index++)
  708. {
  709. MemFree(g_ServiceStringTable[Index].String);
  710. g_ServiceStringTable[Index].String = NULL;
  711. }
  712. if (NULL != g_StatusCompletionPortHandle)
  713. {
  714. if (!CloseHandle(g_StatusCompletionPortHandle))
  715. {
  716. DebugPrintEx(
  717. DEBUG_ERR,
  718. TEXT("CloseHandle Failed (ec: %ld"),
  719. GetLastError());
  720. }
  721. g_StatusCompletionPortHandle = NULL;
  722. }
  723. if (NULL != g_pFaxPerfCounters)
  724. {
  725. if (!UnmapViewOfFile(g_pFaxPerfCounters))
  726. {
  727. DebugPrintEx(
  728. DEBUG_ERR,
  729. TEXT("UnmapViewOfFile Failed (ec: %ld"),
  730. GetLastError());
  731. }
  732. g_pFaxPerfCounters = NULL;
  733. }
  734. if (NULL != g_hFaxPerfCountersMap)
  735. {
  736. if (!CloseHandle(g_hFaxPerfCountersMap))
  737. {
  738. DebugPrintEx(
  739. DEBUG_ERR,
  740. TEXT("CloseHandle Failed (ec: %ld"),
  741. GetLastError());
  742. }
  743. g_hFaxPerfCountersMap = NULL;
  744. }
  745. if (NULL != g_hLineApp)
  746. {
  747. LONG Rslt = lineShutdown(g_hLineApp);
  748. if (Rslt)
  749. {
  750. DebugPrintEx(
  751. DEBUG_ERR,
  752. TEXT("lineShutdown() failed (ec: %ld)"),
  753. Rslt);
  754. }
  755. g_hLineApp = NULL;
  756. }
  757. if (NULL != g_hThreadCountEvent)
  758. {
  759. if (!CloseHandle(g_hThreadCountEvent))
  760. {
  761. DebugPrintEx(
  762. DEBUG_ERR,
  763. TEXT("CloseHandle for g_hThreadCountEvent Failed (ec: %ld"),
  764. GetLastError());
  765. }
  766. g_hThreadCountEvent = NULL;
  767. }
  768. if (NULL != g_hServiceShutDownEvent)
  769. {
  770. if (!CloseHandle(g_hServiceShutDownEvent))
  771. {
  772. DebugPrintEx(
  773. DEBUG_ERR,
  774. TEXT("CloseHandle for g_hServiceShutDownEvent Failed (ec: %ld"),
  775. GetLastError());
  776. }
  777. g_hServiceShutDownEvent = NULL;
  778. }
  779. if (NULL != g_hSCMServiceShutDownEvent)
  780. {
  781. if (!CloseHandle(g_hSCMServiceShutDownEvent))
  782. {
  783. DebugPrintEx(
  784. DEBUG_ERR,
  785. TEXT("CloseHandle for g_hSCMServiceShutDownEvent Failed (ec: %ld"),
  786. GetLastError());
  787. }
  788. g_hSCMServiceShutDownEvent = NULL;
  789. }
  790. if (NULL != g_hServiceIsDownSemaphore)
  791. {
  792. if (!CloseHandle(g_hServiceIsDownSemaphore))
  793. {
  794. DebugPrintEx(
  795. DEBUG_ERR,
  796. TEXT("CloseHandle for g_hServiceIsDownSemaphore Failed (ec: %ld"),
  797. GetLastError());
  798. }
  799. g_hServiceIsDownSemaphore = NULL;
  800. }
  801. if (NULL != g_hTapiWorkerThread)
  802. {
  803. if (!CloseHandle(g_hTapiWorkerThread))
  804. {
  805. DebugPrintEx(
  806. DEBUG_ERR,
  807. TEXT("CloseHandle for g_hTapiWorkerThread Failed (ec: %ld"),
  808. GetLastError());
  809. }
  810. g_hTapiWorkerThread = NULL;
  811. }
  812. if (NULL != g_hJobQueueThread)
  813. {
  814. if (!CloseHandle(g_hJobQueueThread))
  815. {
  816. DebugPrintEx(
  817. DEBUG_ERR,
  818. TEXT("CloseHandle for g_hJobQueueThread Failed (ec: %ld"),
  819. GetLastError());
  820. }
  821. g_hJobQueueThread = NULL;
  822. }
  823. MemFree(g_pAdaptiveFileBuffer);
  824. g_pAdaptiveFileBuffer = NULL;
  825. MemFree(g_pLineCountryList);
  826. g_pLineCountryList = NULL;
  827. FreeRecieptsConfiguration( &g_ReceiptsConfig, FALSE);
  828. //
  829. // free g_ArchivesConfig strings memory
  830. //
  831. MemFree(g_ArchivesConfig[0].lpcstrFolder);
  832. MemFree(g_ArchivesConfig[1].lpcstrFolder);
  833. //
  834. // free g_ActivityLoggingConfig strings memory
  835. //
  836. MemFree(g_ActivityLoggingConfig.lptstrDBPath);
  837. FreeResInstance();
  838. Assert ((ULONG_PTR)g_HandleTableListHead.Flink == (ULONG_PTR)&g_HandleTableListHead);
  839. Assert ((ULONG_PTR)g_DeviceProvidersListHead.Flink == (ULONG_PTR)&g_DeviceProvidersListHead);
  840. Assert ((ULONG_PTR)g_JobListHead.Flink == (ULONG_PTR)&g_JobListHead);
  841. Assert ((ULONG_PTR)g_QueueListHead.Flink == (ULONG_PTR)&g_QueueListHead);
  842. Assert ((ULONG_PTR)g_lstRoutingMethods .Flink == (ULONG_PTR)&g_lstRoutingMethods );
  843. Assert ((ULONG_PTR)g_lstRoutingExtensions .Flink == (ULONG_PTR)&g_lstRoutingExtensions );
  844. #if DBG
  845. Assert ((ULONG_PTR)g_CritSecListHead .Flink == (ULONG_PTR)&g_CritSecListHead );
  846. #endif
  847. Assert ((ULONG_PTR)g_TapiLinesListHead .Flink == (ULONG_PTR)&g_TapiLinesListHead );
  848. Assert ((ULONG_PTR)g_RemovedTapiLinesListHead .Flink == (ULONG_PTR)&g_RemovedTapiLinesListHead );
  849. return;
  850. }
  851. VOID
  852. EncryptReceiptsPassword(
  853. VOID
  854. )
  855. /*++
  856. Routine Description:
  857. Checks if the receipts password is stored encrypted. If it is not encrypted, it encrypts the password.
  858. Unattended fax installation stores this password as clear text in the registry.
  859. Arguments:
  860. None.
  861. Return Value:
  862. None.
  863. --*/
  864. {
  865. DEBUG_FUNCTION_NAME(TEXT("EncryptReceiptsPassword"));
  866. FAX_ENUM_DATA_ENCRYPTION DataEncrypted;
  867. HKEY hKey;
  868. LPWSTR lpwstrPassword = NULL;
  869. BOOL bDeletePassword = FALSE;
  870. hKey = OpenRegistryKey(HKEY_LOCAL_MACHINE, REGKEY_FAX_RECEIPTS, FALSE, KEY_READ | KEY_WRITE);
  871. if (NULL == hKey)
  872. {
  873. DebugPrintEx(DEBUG_ERR,
  874. TEXT("OpenRegistryKey failed (ec: %ld)"),
  875. GetLastError());
  876. return;
  877. }
  878. lpwstrPassword = GetRegistrySecureString(hKey, REGVAL_RECEIPTS_PASSWORD, NULL, TRUE, &DataEncrypted);
  879. if (FAX_DATA_ENCRYPTED == DataEncrypted)
  880. {
  881. //
  882. // We are done!
  883. //
  884. goto exit;
  885. }
  886. else if(FAX_NO_DATA == DataEncrypted)
  887. {
  888. //
  889. // We do not know if the data is encrypted or not.
  890. // Delete the password
  891. //
  892. bDeletePassword = TRUE;
  893. }
  894. else
  895. {
  896. Assert (FAX_DATA_NOT_ENCRYPTED == DataEncrypted);
  897. //
  898. // Data is not encrypted, store it encrypted now.
  899. //
  900. if (!SetRegistrySecureString(
  901. hKey,
  902. REGVAL_RECEIPTS_PASSWORD,
  903. lpwstrPassword ? lpwstrPassword : EMPTY_STRING,
  904. TRUE // Optionally non-encrypted
  905. ))
  906. {
  907. DebugPrintEx(
  908. DEBUG_ERR,
  909. TEXT("SetRegistrySecureString failed : %ld"),
  910. GetLastError());
  911. bDeletePassword = TRUE;
  912. }
  913. }
  914. if (TRUE == bDeletePassword)
  915. {
  916. //
  917. // We do not want to leave clear text password in the registry
  918. //
  919. LONG lResult;
  920. lResult = RegDeleteValue( hKey, REGVAL_RECEIPTS_PASSWORD);
  921. if (ERROR_SUCCESS != lResult)
  922. {
  923. DebugPrintEx(
  924. DEBUG_ERR,
  925. TEXT("RegDeleteValue failed : %ld"),
  926. lResult);
  927. }
  928. }
  929. exit:
  930. RegCloseKey(hKey);
  931. if (lpwstrPassword)
  932. {
  933. SecureZeroMemory(lpwstrPassword, wcslen(lpwstrPassword)*sizeof(WCHAR));
  934. MemFree(lpwstrPassword);
  935. }
  936. return;
  937. }
  938. VOID
  939. FaxServiceMain(
  940. DWORD argc,
  941. LPTSTR *argv
  942. )
  943. /*++
  944. Routine Description:
  945. This is the service main that is called by the
  946. service controller.
  947. Arguments:
  948. argc - argument count
  949. argv - argument array
  950. Return Value:
  951. None.
  952. --*/
  953. {
  954. OPEN_DEBUG_FILE(SERVICE_DEBUG_LOG_FILE);
  955. DEBUG_FUNCTION_NAME(TEXT("FaxServiceMain"));
  956. DWORD dwRet;
  957. HKEY hStartupKey = NULL; // Key to signal clients the service is running
  958. HKEY hFaxRoot = NULL; // Key to root of fax prarmeters in the registry
  959. #if DBG
  960. for (int i = 1; i < argc; i++)
  961. {
  962. if (0 == _tcsicmp(argv[i], TEXT("/d")))
  963. {
  964. //
  965. // We are in debug mode. - attach the debugger
  966. //
  967. DebugPrintEx(DEBUG_MSG,
  968. TEXT("Entring debug mode..."));
  969. DebugBreak();
  970. }
  971. }
  972. #endif // #if DBG
  973. //
  974. // First of all make sure receipts password is stored encrypted
  975. // Unattended installation stores the password as clear text.
  976. //
  977. EncryptReceiptsPassword();
  978. //
  979. // Becuase the process is not always terminated when the service is stopped,
  980. // We must not have any staticly initialized global variables.
  981. // Initialize all service global variables before starting the service
  982. //
  983. if (!InitializeServiceGlobals())
  984. {
  985. DebugPrintEx(DEBUG_ERR,
  986. TEXT("InitializeServiceGlobals failed (ec: %ld)"),
  987. GetLastError());
  988. goto Exit;
  989. }
  990. if (!InitializeFaxLibrariesGlobals())
  991. {
  992. DebugPrintEx(DEBUG_ERR,
  993. TEXT("InitializeFaxLibrariesGlobals failed"));
  994. goto Exit;
  995. }
  996. hFaxRoot = OpenRegistryKey (HKEY_LOCAL_MACHINE,
  997. REGKEY_FAXSERVER,
  998. TRUE, // Create key if needed
  999. KEY_READ);
  1000. if (hFaxRoot)
  1001. {
  1002. GetRegistryDwordEx (hFaxRoot, REGVAL_USE_DEFAULT_FAULT_HANDLING_POLICY, (LPDWORD)&gs_bUseDefaultFaultHandlingPolicy);
  1003. RegCloseKey (hFaxRoot);
  1004. }
  1005. //
  1006. // This will prevent the system exception dialog from showing up.
  1007. // This is required so we can support the SCM service-recovery feature
  1008. // to auto-recovery from unhandled exceptions.
  1009. //
  1010. SetUnhandledExceptionFilter (FaxUnhandledExceptionFilter);
  1011. for (int i = 1; i < argc; i++)
  1012. {
  1013. if (0 == _tcsicmp(argv[i], SERVICE_ALWAYS_RUNS))
  1014. {
  1015. //
  1016. // Service must never suicide
  1017. //
  1018. g_bServiceCanSuicide = FALSE;
  1019. DebugPrintEx(DEBUG_MSG,
  1020. TEXT("Command line detected. Service will not suicide"));
  1021. }
  1022. else if (0 == _tcsicmp(argv[i], SERVICE_DELAY_SUICIDE))
  1023. {
  1024. //
  1025. // Service should delay suicide
  1026. //
  1027. g_bDelaySuicideAttempt = TRUE;
  1028. DebugPrintEx(DEBUG_MSG,
  1029. TEXT("Command line detected. Service will delay suicide attempts"));
  1030. }
  1031. }
  1032. gs_FaxServiceStatusHandle = RegisterServiceCtrlHandler(
  1033. FAX_SERVICE_NAME,
  1034. FaxServiceCtrlHandler
  1035. );
  1036. if (!gs_FaxServiceStatusHandle)
  1037. {
  1038. DebugPrintEx(DEBUG_ERR,
  1039. TEXT("RegisterServiceCtrlHandler failed %d"),
  1040. GetLastError());
  1041. goto Exit;
  1042. }
  1043. //
  1044. // Open the HKLM\Software\Microsoft\Fax\Client\ServiceStartup key
  1045. // to tell clients the service is up.
  1046. //
  1047. hStartupKey = OpenRegistryKey (HKEY_LOCAL_MACHINE,
  1048. REGKEY_FAX_SERVICESTARTUP,
  1049. TRUE, // Create key if needed
  1050. KEY_READ | KEY_WRITE);
  1051. if (!hStartupKey)
  1052. {
  1053. DebugPrintEx(DEBUG_ERR,
  1054. TEXT("Can't open reg key (ec = %ld)"),
  1055. GetLastError() );
  1056. goto Exit;
  1057. }
  1058. //
  1059. // Initialize service
  1060. //
  1061. dwRet = ServiceStart();
  1062. if (ERROR_SUCCESS != dwRet)
  1063. {
  1064. //
  1065. // The service failed to start correctly
  1066. //
  1067. DebugPrintEx(DEBUG_ERR,
  1068. TEXT("The service failed to start correctly (dwRet = %ld)"), dwRet );
  1069. }
  1070. else
  1071. {
  1072. //
  1073. // mark the service in the running state
  1074. //
  1075. DebugPrintEx(
  1076. DEBUG_MSG,
  1077. TEXT("Reporting SERVICE_RUNNING to the SCM"));
  1078. ReportServiceStatus( SERVICE_RUNNING, 0, 0 );
  1079. //
  1080. // Notify all clients (on local machine) that the server is up and running.
  1081. // For security reasons, we do that by writing to the registry
  1082. // (HKLM\Software\Microsoft\Fax\Client\ServiceStartup\RPCReady).
  1083. // The client modules listen to registry changes in that key.
  1084. //
  1085. if (!SetRegistryDword (hStartupKey,
  1086. REGVAL_FAX_RPC_READY,
  1087. GetRegistryDword (hStartupKey, REGVAL_FAX_RPC_READY) + 1))
  1088. {
  1089. DebugPrintEx(DEBUG_ERR,
  1090. TEXT("Can't open reg key (ec = %ld)"),
  1091. GetLastError() );
  1092. }
  1093. //
  1094. // Wait for service shutdown event from SCM
  1095. //
  1096. DebugPrintEx(DEBUG_MSG,
  1097. TEXT("Waiting for service shutdown event"));
  1098. DWORD dwWaitRes = WaitForSingleObject (g_hSCMServiceShutDownEvent ,INFINITE);
  1099. if (WAIT_OBJECT_0 != dwWaitRes)
  1100. {
  1101. DebugPrintEx(DEBUG_ERR,
  1102. TEXT("WaitForSingleObject failed (ec = %ld)"), GetLastError() );
  1103. }
  1104. }
  1105. //
  1106. // Close service
  1107. //
  1108. if (ERROR_SUCCESS != dwRet)
  1109. {
  1110. EndFaxSvc(FAXLOG_LEVEL_MIN);
  1111. }
  1112. else
  1113. {
  1114. EndFaxSvc(FAXLOG_LEVEL_MAX);
  1115. }
  1116. Exit:
  1117. if (hStartupKey)
  1118. {
  1119. RegCloseKey (hStartupKey);
  1120. }
  1121. FreeServiceGlobals();
  1122. FreeFaxLibrariesGlobals();
  1123. ReportServiceStatus( SERVICE_STOPPED, 0 , 0);
  1124. return;
  1125. } // FaxServiceMain
  1126. BOOL SetServiceIsDownFlag(VOID)
  1127. {
  1128. /*++
  1129. Routine Description:
  1130. Sets the g_bServiceIsDown to true.
  1131. Done by a separate thread while reporting SERVICE_STOP_PENDING to SCM.
  1132. Arguments:
  1133. None.
  1134. Return Value:
  1135. TRUE on success.
  1136. FALSE on failure - use GetLastError() to get standard win32 error code.
  1137. --*/
  1138. HANDLE hThread = NULL;
  1139. DWORD ec = ERROR_SUCCESS;
  1140. DEBUG_FUNCTION_NAME(TEXT("SetServiceIsDownFlag"));
  1141. //
  1142. // Call SetServiceIsDownFlagThread() to set the g_bServiceIsDown flag
  1143. //
  1144. hThread = CreateThread( NULL,
  1145. 0,
  1146. (LPTHREAD_START_ROUTINE) SetServiceIsDownFlagThread,
  1147. NULL,
  1148. 0,
  1149. NULL
  1150. );
  1151. if (NULL == hThread)
  1152. {
  1153. ec = GetLastError();
  1154. DebugPrintEx( DEBUG_ERR,
  1155. _T("Failed to create SetServiceIsDownFlagThread (ec: %ld)."),
  1156. ec);
  1157. goto Exit;
  1158. }
  1159. if (!WaitAndReportForThreadToTerminate(hThread,TEXT("Waiting for SetServiceIsDownFlagThread to terminate.")))
  1160. {
  1161. ec = GetLastError();
  1162. DebugPrintEx( DEBUG_ERR,
  1163. _T("Failed to WaitAndReportForThreadToTerminate (ec: %ld)."),
  1164. ec);
  1165. goto Exit;
  1166. }
  1167. Assert(ec == ERROR_SUCCESS);
  1168. Exit:
  1169. if (NULL != hThread)
  1170. {
  1171. if (!CloseHandle(hThread))
  1172. {
  1173. DebugPrintEx( DEBUG_ERR,
  1174. _T("CloseHandle Failed (ec: %ld)."),
  1175. GetLastError());
  1176. }
  1177. }
  1178. if (ERROR_SUCCESS != ec)
  1179. {
  1180. SetLastError(ec);
  1181. }
  1182. return (ERROR_SUCCESS == ec);
  1183. }
  1184. DWORD SetServiceIsDownFlagThread(
  1185. LPVOID pvUnused
  1186. )
  1187. /*++
  1188. Routine Description:
  1189. Sets the g_bServiceIsDown to true.
  1190. Done by a separate thread in order for FaxServiceCtrlHandler to return immediately.
  1191. Arguments:
  1192. None.
  1193. Return Value:
  1194. Return code. Return zero for success.
  1195. --*/
  1196. {
  1197. DWORD dwWaitCount = 2; // We wait for TapiWorkerThread() and JobQueueThread()
  1198. DEBUG_FUNCTION_NAME(TEXT("SetServiceIsDownFlagThread"));
  1199. //
  1200. // First set the global flag that the service is going down
  1201. //
  1202. g_bServiceIsDown = TRUE;
  1203. //
  1204. // Update dwWaitCount to the correct value
  1205. //
  1206. if (NULL == g_hTapiWorkerThread)
  1207. {
  1208. DebugPrintEx(
  1209. DEBUG_WRN,
  1210. TEXT("TapiWorkerThread was not created. Do not wait for an event from TapiWorkerThread()"));
  1211. dwWaitCount -= 1;
  1212. }
  1213. if (NULL == g_hJobQueueThread)
  1214. {
  1215. DebugPrintEx(
  1216. DEBUG_WRN,
  1217. TEXT("g_hJobQueueThread was not created. Do not wait for an event from g_hJobQueueThread()"));
  1218. dwWaitCount -= 1;
  1219. }
  1220. //
  1221. // Wake up TapiWorkerThread and JobQueueThread, so they can read g_bServiceIsDown
  1222. //
  1223. if (NULL != g_hJobQueueEvent)
  1224. {
  1225. if (!SetEvent( g_hJobQueueEvent ))
  1226. {
  1227. DebugPrintEx(
  1228. DEBUG_ERR,
  1229. TEXT("Failed to set g_hJobQueueEvent. (ec: %ld)"),
  1230. GetLastError());
  1231. }
  1232. }
  1233. if (NULL != g_TapiCompletionPort)
  1234. {
  1235. if (!PostQueuedCompletionStatus( g_TapiCompletionPort,
  1236. 0,
  1237. FAXDEV_EVENT_KEY,
  1238. (LPOVERLAPPED) NULL))
  1239. {
  1240. DebugPrintEx(
  1241. DEBUG_ERR,
  1242. TEXT("PostQueuedCompletionStatus failed (FAXDEV_EVENT_KEY - TapiWorkerThread). (ec: %ld)"),
  1243. GetLastError());
  1244. }
  1245. }
  1246. DebugPrintEx(
  1247. DEBUG_MSG,
  1248. TEXT("SetServiceIsDownFlagThread waits for %d Thread(s)"),
  1249. dwWaitCount);
  1250. //
  1251. // Wait for a signal from TapiWorkerThread and JobQueueThread that the global flag g_bServiceIsDown was read by them
  1252. //
  1253. for (DWORD i = 0; i < dwWaitCount; i++)
  1254. {
  1255. DWORD dwWaitRes = WaitForSingleObject (g_hServiceIsDownSemaphore ,INFINITE);
  1256. if (WAIT_OBJECT_0 != dwWaitRes)
  1257. {
  1258. DebugPrintEx(DEBUG_ERR,
  1259. TEXT("WaitForSingleObject failed (ec = %ld)"), GetLastError() );
  1260. }
  1261. }
  1262. return (ERROR_SUCCESS);
  1263. }
  1264. VOID
  1265. FaxServiceCtrlHandler(
  1266. DWORD Opcode
  1267. )
  1268. /*++
  1269. Routine Description:
  1270. This is the FAX service control dispatch function.
  1271. Arguments:
  1272. Opcode - requested control code
  1273. Return Value:
  1274. None.
  1275. --*/
  1276. {
  1277. DEBUG_FUNCTION_NAME(TEXT("FaxServiceCtrlHandler"));
  1278. switch(Opcode)
  1279. {
  1280. case SERVICE_CONTROL_STOP:
  1281. case SERVICE_CONTROL_SHUTDOWN:
  1282. ReportServiceStatus( SERVICE_STOP_PENDING, 0, 2000 );
  1283. if (!SetEvent(g_hSCMServiceShutDownEvent))
  1284. {
  1285. DebugPrintEx(
  1286. DEBUG_ERR,
  1287. TEXT("SetEvent failed (g_hSCMServiceShutDownEvent) (ec = %ld)"),
  1288. GetLastError());
  1289. }
  1290. return;
  1291. default:
  1292. DebugPrintEx(
  1293. DEBUG_WRN,
  1294. TEXT("Unrecognized opcode %ld"),
  1295. Opcode);
  1296. break;
  1297. }
  1298. ReportServiceStatus( 0, 0, 0 );
  1299. return;
  1300. }
  1301. BOOL
  1302. ReportServiceStatus(
  1303. DWORD CurrentState,
  1304. DWORD Win32ExitCode,
  1305. DWORD WaitHint
  1306. )
  1307. /*++
  1308. Routine Description:
  1309. This function updates the service control manager's status information for the FAX service.
  1310. Arguments:
  1311. CurrentState - Indicates the current state of the service
  1312. Win32ExitCode - Specifies a Win32 error code that the service uses to
  1313. report an error that occurs when it is starting or stopping.
  1314. WaitHint - Specifies an estimate of the amount of time, in milliseconds,
  1315. that the service expects a pending start, stop, or continue
  1316. operation to take before the service makes its next call to the
  1317. SetServiceStatus function with either an incremented dwCheckPoint
  1318. value or a change in dwCurrentState.
  1319. Return Value:
  1320. BOOL
  1321. --*/
  1322. {
  1323. BOOL rVal;
  1324. if (CurrentState == SERVICE_START_PENDING)
  1325. {
  1326. gs_FaxServiceStatus.dwControlsAccepted = 0;
  1327. }
  1328. else
  1329. {
  1330. gs_FaxServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  1331. }
  1332. if (CurrentState)
  1333. {
  1334. gs_FaxServiceStatus.dwCurrentState = CurrentState;
  1335. }
  1336. gs_FaxServiceStatus.dwWin32ExitCode = Win32ExitCode;
  1337. gs_FaxServiceStatus.dwWaitHint = WaitHint;
  1338. ++(gs_FaxServiceStatus.dwCheckPoint);
  1339. //
  1340. // Report the status of the service to the service control manager.
  1341. //
  1342. rVal = SetServiceStatus( gs_FaxServiceStatusHandle, &gs_FaxServiceStatus );
  1343. if (!rVal)
  1344. {
  1345. DebugPrint(( TEXT("SetServiceStatus() failed: ec=%d"), GetLastError() ));
  1346. }
  1347. return rVal;
  1348. }
  1349. DWORD
  1350. RpcBindToFaxClient(
  1351. IN LPCWSTR ServerName,
  1352. IN LPCWSTR Endpoint,
  1353. OUT RPC_BINDING_HANDLE *pBindingHandle
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. Binds to the Fax server to the Client RPC server if possible.
  1358. Arguments:
  1359. ServerName - Name of client RPC server to bind with.
  1360. Endpoint - Name of interface to bind with.
  1361. pBindingHandle - Location where binding handle is to be placed
  1362. Return Value:
  1363. STATUS_SUCCESS - The binding has been successfully completed.
  1364. STATUS_INVALID_COMPUTER_NAME - The ServerName syntax is invalid.
  1365. STATUS_NO_MEMORY - There is not sufficient memory available to the
  1366. caller to perform the binding.
  1367. --*/
  1368. {
  1369. RPC_STATUS RpcStatus;
  1370. LPWSTR StringBinding;
  1371. WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1372. LPWSTR NewServerName = LOCAL_HOST_ADDRESS;
  1373. DWORD bufLen = MAX_COMPUTERNAME_LENGTH + 1;
  1374. DEBUG_FUNCTION_NAME(TEXT("RpcBindToFaxClient"));
  1375. *pBindingHandle = NULL;
  1376. if (ServerName != NULL)
  1377. {
  1378. if (GetComputerNameW(ComputerName,&bufLen))
  1379. {
  1380. if ((_wcsicmp(ComputerName,ServerName) == 0) ||
  1381. ((ServerName[0] == '\\') &&
  1382. (ServerName[1] == '\\') &&
  1383. (_wcsicmp(ComputerName,&(ServerName[2]))==0)))
  1384. {
  1385. //
  1386. // We are binding to local machine - using LOCAL_HOST_ADDRESS (defined as _T("127.0.0.1")).
  1387. // Using this format we can help the RPC server to detect local calls.
  1388. //
  1389. NewServerName = LOCAL_HOST_ADDRESS;
  1390. }
  1391. else
  1392. {
  1393. NewServerName = (LPWSTR)ServerName;
  1394. }
  1395. }
  1396. else
  1397. {
  1398. DWORD ec = GetLastError();
  1399. DebugPrintEx(
  1400. DEBUG_ERR,
  1401. TEXT("GetComputerNameW failed (ec = %lu)"),
  1402. ec);
  1403. return ec;
  1404. }
  1405. }
  1406. RpcStatus = RpcStringBindingComposeW(0,
  1407. const_cast<LPTSTR>(RPC_PROT_SEQ_TCP_IP),
  1408. NewServerName,
  1409. (LPWSTR)Endpoint,
  1410. (LPWSTR)L"",
  1411. &StringBinding);
  1412. if ( RpcStatus != RPC_S_OK )
  1413. {
  1414. DebugPrintEx(
  1415. DEBUG_ERR,
  1416. TEXT("RpcStringBindingComposeW failed (ec = %ld)"),
  1417. RpcStatus);
  1418. return( STATUS_NO_MEMORY );
  1419. }
  1420. RpcStatus = RpcBindingFromStringBindingW(StringBinding, pBindingHandle);
  1421. RpcStringFreeW(&StringBinding);
  1422. if ( RpcStatus != RPC_S_OK )
  1423. {
  1424. DebugPrintEx(
  1425. DEBUG_ERR,
  1426. TEXT("RpcBindingFromStringBindingW failed (ec = %ld)"),
  1427. RpcStatus);
  1428. *pBindingHandle = NULL;
  1429. if ( (RpcStatus == RPC_S_INVALID_ENDPOINT_FORMAT)
  1430. || (RpcStatus == RPC_S_INVALID_NET_ADDR) )
  1431. {
  1432. return( ERROR_INVALID_COMPUTERNAME );
  1433. }
  1434. return(STATUS_NO_MEMORY);
  1435. }
  1436. //
  1437. // Ask for the highest level of privacy (autnetication + encryption)
  1438. //
  1439. RPC_SECURITY_QOS rpcSecurityQOS = { RPC_C_SECURITY_QOS_VERSION,
  1440. RPC_C_QOS_CAPABILITIES_DEFAULT,
  1441. RPC_C_QOS_IDENTITY_STATIC,
  1442. RPC_C_IMP_LEVEL_IDENTIFY // Server can obtain information about
  1443. // client security identifiers and privileges,
  1444. // but cannot impersonate the client.
  1445. };
  1446. RpcStatus = RpcBindingSetAuthInfoEx (
  1447. *pBindingHandle, // RPC binding handle
  1448. TEXT(""), // Server principal name - ignored for RPC_C_AUTHN_WINNT
  1449. RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Authentication level - fullest
  1450. // Authenticates, verifies, and privacy-encrypts the arguments passed
  1451. // to every remote call.
  1452. RPC_C_AUTHN_WINNT, // Authentication service (NTLMSSP)
  1453. NULL, // Authentication identity - use currently logged on user
  1454. 0, // Unused when Authentication service == RPC_C_AUTHN_WINNT
  1455. &rpcSecurityQOS); // Defines the security quality-of-service
  1456. if (RPC_S_OK != RpcStatus)
  1457. {
  1458. //
  1459. // Couldn't set RPC authentication mode
  1460. //
  1461. DebugPrintEx(
  1462. DEBUG_ERR,
  1463. TEXT("RpcBindingSetAuthInfoEx (RPC_C_AUTHN_LEVEL_PKT_PRIVACY) failed. (ec: %ld)"),
  1464. RpcStatus);
  1465. RpcBindingFree (pBindingHandle);
  1466. *pBindingHandle = NULL;
  1467. return RpcStatus;
  1468. }
  1469. //
  1470. // Set time out on RPC calls to 30 sec, to avoid denial of service by malicious user.
  1471. //
  1472. RpcStatus = RpcBindingSetOption(
  1473. *pBindingHandle,
  1474. RPC_C_OPT_CALL_TIMEOUT,
  1475. 30*1000);
  1476. if (RPC_S_OK != RpcStatus)
  1477. {
  1478. DebugPrintEx(
  1479. DEBUG_ERR,
  1480. TEXT("RpcBindingSetOption failed (ec = %ld)"),
  1481. RpcStatus);
  1482. RpcBindingFree (pBindingHandle);
  1483. *pBindingHandle = NULL;
  1484. return RpcStatus;
  1485. }
  1486. return(ERROR_SUCCESS);
  1487. }
  1488. RPC_STATUS RPC_ENTRY FaxServerSecurityCallBack(
  1489. IN RPC_IF_HANDLE idIF,
  1490. IN void *ctx
  1491. )
  1492. /*++
  1493. Routine Description:
  1494. Security callback function is automatically called when
  1495. any RPC server function is called. (usually, once per client - but in some cases,
  1496. the RPC run time may call the security-callback function more than
  1497. once per client-per interface)
  1498. o The call-back will deny access for clients with authentication level below RPC_C_AUTHN_LEVEL_PRIVACY.
  1499. Arguments:
  1500. idIF - UUID and version of the interface.
  1501. ctx - Pointer to an RPC_IF_ID server binding handle representing the client.
  1502. Return Value:
  1503. The callback function should return RPC_S_OK if the client is allowed to call methods in this interface.
  1504. Any other return code will cause the client to receive the exception RPC_S_ACCESS_DENIED.
  1505. --*/
  1506. {
  1507. RPC_AUTHZ_HANDLE hPrivs;
  1508. DWORD dwAuthn;
  1509. BOOL fLocal;
  1510. BOOL fPrinterShared;
  1511. DWORD dwRes;
  1512. RPC_STATUS status;
  1513. RPC_STATUS rpcStatRet = ERROR_ACCESS_DENIED;
  1514. LPWSTR lpwstrProtSeq = NULL;
  1515. DEBUG_FUNCTION_NAME(TEXT("FaxServerSecurityCallBack"));
  1516. //
  1517. // Query the client's protseq
  1518. //
  1519. status = GetRpcStringBindingInfo(ctx,
  1520. NULL,
  1521. &lpwstrProtSeq);
  1522. if (status != RPC_S_OK)
  1523. {
  1524. DebugPrintEx(DEBUG_ERR,
  1525. TEXT("RpcBindingServerFromClient failed - (ec: %lu)"),
  1526. status);
  1527. goto error;
  1528. }
  1529. if (_tcsicmp(lpwstrProtSeq, RPC_PROT_SEQ_NP))
  1530. {
  1531. DebugPrintEx(DEBUG_ERR,
  1532. TEXT("Client not using named pipes protSeq.")
  1533. );
  1534. goto error;
  1535. }
  1536. //
  1537. // Query the client's authentication level
  1538. //
  1539. status = RpcBindingInqAuthClient(
  1540. ctx,
  1541. &hPrivs,
  1542. NULL,
  1543. &dwAuthn,
  1544. NULL,
  1545. NULL);
  1546. if (status != RPC_S_OK)
  1547. {
  1548. DebugPrintEx(DEBUG_ERR,
  1549. TEXT("RpcBindingInqAuthClient returned: 0x%x"),
  1550. status);
  1551. goto error;
  1552. }
  1553. //
  1554. // Now check the authentication level.
  1555. // We require at least packet-level privacy (RPC_C_AUTHN_LEVEL_PKT_PRIVACY) authentication.
  1556. //
  1557. if (dwAuthn < RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
  1558. {
  1559. DebugPrintEx(DEBUG_ERR,
  1560. TEXT("Attempt by client to use weak authentication. - 0x%x"),
  1561. dwAuthn);
  1562. goto error;
  1563. }
  1564. if (0 == g_dwAllowRemote)
  1565. {
  1566. //
  1567. // The administrator did not set the registry to always allow remote calls
  1568. // If the printer is not shared, block remote connections
  1569. //
  1570. dwRes = IsLocalFaxPrinterShared(&fPrinterShared);
  1571. if (ERROR_SUCCESS != dwRes)
  1572. {
  1573. DebugPrintEx(
  1574. DEBUG_ERR,
  1575. TEXT("IsLocalFaxPrinterShared failed. - %ld"),
  1576. dwRes);
  1577. goto error;
  1578. }
  1579. if (FALSE == fPrinterShared)
  1580. {
  1581. status = IsLocalRPCConnectionNP(&fLocal);
  1582. if (RPC_S_OK != status)
  1583. {
  1584. DebugPrintEx(
  1585. DEBUG_ERR,
  1586. TEXT("IsLocalRPCConnectionNP failed. - %ld"),
  1587. status);
  1588. goto error;
  1589. }
  1590. if (FALSE == fLocal)
  1591. {
  1592. DebugPrintEx(
  1593. DEBUG_ERR,
  1594. TEXT("Printer is not shared, and a remote connection is done"));
  1595. goto error;
  1596. }
  1597. }
  1598. }
  1599. rpcStatRet = RPC_S_OK;
  1600. error:
  1601. if(NULL != lpwstrProtSeq)
  1602. {
  1603. MemFree(lpwstrProtSeq);
  1604. }
  1605. return rpcStatRet;
  1606. } // FaxServerSecurityCallBack
  1607. RPC_STATUS
  1608. AddFaxRpcInterface(
  1609. IN LPWSTR InterfaceName,
  1610. IN RPC_IF_HANDLE InterfaceSpecification
  1611. )
  1612. /*++
  1613. Routine Description:
  1614. Starts an RPC Server, adds the address (or port/pipe), and adds the
  1615. interface (dispatch table).
  1616. Arguments:
  1617. InterfaceName - points to the name of the interface.
  1618. InterfaceSpecification - Supplies the interface handle for the
  1619. interface which we wish to add.
  1620. Return Value:
  1621. NT_SUCCESS - Indicates the server was successfully started.
  1622. STATUS_NO_MEMORY - An attempt to allocate memory has failed.
  1623. Other - Status values that may be returned by:
  1624. RpcServerRegisterIfEx()
  1625. RpcServerUseProtseqEp()
  1626. , or any RPC error codes, or any windows error codes that
  1627. can be returned by LocalAlloc.
  1628. --*/
  1629. {
  1630. RPC_STATUS RpcStatus;
  1631. LPWSTR Endpoint = NULL;
  1632. DEBUG_FUNCTION_NAME(TEXT("AddFaxRpcInterface"));
  1633. // We need to concatenate \pipe\ to the front of the interface name.
  1634. Endpoint = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(NT_PIPE_PREFIX) + WCSSIZE(InterfaceName));
  1635. if (Endpoint == 0)
  1636. {
  1637. DebugPrintEx(
  1638. DEBUG_ERR,
  1639. TEXT("LocalAlloc failed"));
  1640. return(STATUS_NO_MEMORY);
  1641. }
  1642. wcscpy(Endpoint, NT_PIPE_PREFIX);
  1643. wcscat(Endpoint,InterfaceName);
  1644. RpcStatus = RpcServerUseProtseqEpW(const_cast<LPTSTR>(RPC_PROT_SEQ_NP), RPC_C_PROTSEQ_MAX_REQS_DEFAULT, Endpoint, NULL);
  1645. if (RpcStatus != RPC_S_OK)
  1646. {
  1647. DebugPrintEx(
  1648. DEBUG_ERR,
  1649. TEXT("RpcServerUseProtseqEpW failed (ec = %ld)"),
  1650. RpcStatus);
  1651. goto CleanExit;
  1652. }
  1653. RpcStatus = RpcServerRegisterIfEx(InterfaceSpecification,
  1654. 0,
  1655. 0,
  1656. RPC_IF_ALLOW_SECURE_ONLY, // Limits connections to clients that use an authorization level higher than RPC_C_AUTHN_LEVEL_NONE
  1657. RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Relieves the RPC run-time environment from enforcing an unnecessary restriction
  1658. FaxServerSecurityCallBack);
  1659. if (RpcStatus != RPC_S_OK)
  1660. {
  1661. DebugPrintEx(
  1662. DEBUG_ERR,
  1663. TEXT("RpcServerRegisterIf failed (ec = %ld)"),
  1664. RpcStatus);
  1665. }
  1666. CleanExit:
  1667. if ( Endpoint != NULL )
  1668. {
  1669. LocalFree(Endpoint);
  1670. }
  1671. return RpcStatus;
  1672. }
  1673. RPC_STATUS
  1674. StartFaxRpcServer(
  1675. IN LPWSTR InterfaceName,
  1676. IN RPC_IF_HANDLE InterfaceSpecification
  1677. )
  1678. /*++
  1679. Routine Description:
  1680. Starts an RPC Server, adds the address (or port/pipe), and adds the
  1681. interface (dispatch table).
  1682. Arguments:
  1683. InterfaceName - points to the name of the interface.
  1684. InterfaceSpecification - Supplies the interface handle for the
  1685. interface which we wish to add.
  1686. Return Value:
  1687. NT_SUCCESS - Indicates the server was successfully started.
  1688. STATUS_NO_MEMORY - An attempt to allocate memory has failed.
  1689. Other - Status values that may be returned by:
  1690. RpcServerRegisterIf()
  1691. RpcServerUseProtseqEp()
  1692. , or any RPC error codes, or any windows error codes that
  1693. can be returned by LocalAlloc.
  1694. --*/
  1695. {
  1696. RPC_STATUS RpcStatus = RPC_S_OK;
  1697. DEBUG_FUNCTION_NAME(TEXT("StartFaxRpcServer"));
  1698. RpcStatus = AddFaxRpcInterface( InterfaceName,
  1699. InterfaceSpecification );
  1700. if ( RpcStatus != RPC_S_OK )
  1701. {
  1702. DebugPrintEx(
  1703. DEBUG_ERR,
  1704. TEXT("AddFaxRpcInterface failed (ec = %ld)"),
  1705. RpcStatus);
  1706. return RpcStatus;
  1707. }
  1708. if (FALSE == IsDesktopSKU())
  1709. {
  1710. //
  1711. // We are not running on DesktopSKU, so remote connection is enabled. RPC data can be passed on the wire
  1712. // We use NTLM authentication for privacy level RPC calls
  1713. //
  1714. RpcStatus = RpcServerRegisterAuthInfo (
  1715. RPC_SERVER_PRINCIPAL_NAME, // Igonred by RPC_C_AUTHN_WINNT
  1716. RPC_C_AUTHN_WINNT, // NTLM SPP authenticator
  1717. NULL, // Ignored when using RPC_C_AUTHN_WINNT
  1718. NULL); // Ignored when using RPC_C_AUTHN_WINNT
  1719. if (RpcStatus != RPC_S_OK)
  1720. {
  1721. DebugPrintEx(
  1722. DEBUG_ERR,
  1723. TEXT("RpcServerRegisterAuthInfo() failed (ec: %ld)"),
  1724. RpcStatus);
  1725. RPC_STATUS RpcStatus2 = RpcServerUnregisterIf(InterfaceSpecification, 0, 1);
  1726. if (RpcStatus2 != RPC_S_OK)
  1727. {
  1728. //
  1729. // failed to unregister interface. don't propagate error
  1730. //
  1731. DebugPrintEx(
  1732. DEBUG_ERR,
  1733. TEXT("RpcServerUnregisterIf() failed (ec: %ld)"),
  1734. RpcStatus2);
  1735. }
  1736. return RpcStatus;
  1737. }
  1738. }
  1739. RpcStatus = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT , TRUE); // Do not wait
  1740. if ( RpcStatus != RPC_S_OK )
  1741. {
  1742. DebugPrintEx(
  1743. DEBUG_ERR,
  1744. TEXT("RpcServerListen failed (ec = %ld)"),
  1745. RpcStatus);
  1746. RPC_STATUS RpcStatus2 = RpcServerUnregisterIf(InterfaceSpecification, 0, 1);
  1747. if (RpcStatus2 != RPC_S_OK)
  1748. {
  1749. //
  1750. // failed to unregister interface. don't propagate error
  1751. //
  1752. DebugPrintEx(
  1753. DEBUG_ERR,
  1754. TEXT("RpcServerUnregisterIf() failed (ec: %ld)"),
  1755. RpcStatus2);
  1756. }
  1757. return RpcStatus;
  1758. }
  1759. return RpcStatus;
  1760. }
  1761. DWORD
  1762. StopFaxRpcServer(
  1763. VOID
  1764. )
  1765. /*++
  1766. Routine Description:
  1767. Stops the service RPC server.
  1768. Arguments:
  1769. Return Value:
  1770. --*/
  1771. {
  1772. RPC_STATUS RpcStatus = RPC_S_OK;
  1773. DEBUG_FUNCTION_NAME(TEXT("StopFaxRpcServer"));
  1774. DWORD dwRet = ERROR_SUCCESS;
  1775. RpcStatus = RpcMgmtStopServerListening(NULL);
  1776. if (RPC_S_OK != RpcStatus)
  1777. {
  1778. DebugPrintEx(
  1779. DEBUG_ERR,
  1780. TEXT("RpcMgmtStopServerListening failed. (ec: %ld)"),
  1781. RpcStatus);
  1782. dwRet = RpcStatus;
  1783. }
  1784. //
  1785. // Wait for the RPC listening thread to return.
  1786. // The thread returns only when all RPC calls are terminated
  1787. //
  1788. if (NULL != g_hRPCListeningThread)
  1789. {
  1790. if (!WaitAndReportForThreadToTerminate( g_hRPCListeningThread,
  1791. TEXT("Waiting for RPC listning thread to terminate.")) )
  1792. {
  1793. DebugPrintEx(
  1794. DEBUG_ERR,
  1795. _T("WaitAndReportForThreadToTerminate failed (ec: %ld)"),
  1796. GetLastError());
  1797. }
  1798. if (!CloseHandle(g_hRPCListeningThread))
  1799. {
  1800. DebugPrintEx(
  1801. DEBUG_ERR,
  1802. TEXT("CloseHandle for g_hRPCListeningThread Failed (ec: %ld"),
  1803. GetLastError());
  1804. }
  1805. g_hRPCListeningThread = NULL;
  1806. }
  1807. RpcStatus = RpcServerUnregisterIfEx(
  1808. fax_ServerIfHandle, // Specifies the interface to remove from the registry
  1809. NULL, // remove the interface specified in the IfSpec parameter for all previously registered type UUIDs from the registry.
  1810. FALSE); // RPC run time will not call the rundown routines.
  1811. if (RPC_S_OK != RpcStatus)
  1812. {
  1813. DebugPrintEx(
  1814. DEBUG_ERR,
  1815. TEXT("RpcServerUnregisterIfEx failed. (ec: %ld)"),
  1816. RpcStatus);
  1817. }
  1818. return ((ERROR_SUCCESS == dwRet) ? RpcStatus : dwRet);
  1819. }