Source code of Windows XP (NT5)
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.

880 lines
21 KiB

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1995 Microsoft Corporation. All Rights Reserved.
  7. //
  8. // MODULE: service.c
  9. //
  10. // PURPOSE: Implements functions required by all services
  11. // and takes into account dumbed-down win95 services
  12. //
  13. // FUNCTIONS:
  14. // main(int argc, char **argv);
  15. // service_ctrl(DWORD dwCtrlCode);
  16. // CryptServiceMain(DWORD dwArgc, LPWSTR *lpszArgv);
  17. // WinNTDebugService(int argc, char **argv);
  18. // ControlHandler ( DWORD dwCtrlType );
  19. //
  20. // COMMENTS:
  21. //
  22. // AUTHOR: Craig Link - Microsoft Developer Support
  23. // MODIFIED: Matt Thomlinson
  24. // Scott Field
  25. //
  26. #include <nt.h>
  27. #include <ntrtl.h>
  28. #include <nturtl.h>
  29. #include <windows.h>
  30. #include <svcs.h> // SVCS_
  31. #include <wincrypt.h>
  32. #include <cryptui.h>
  33. #include "keysvr.h"
  34. #include "lenroll.h"
  35. #include "keysvc.h"
  36. #include "keysvcc.h"
  37. #include "cerrpc.h"
  38. #include "service.h"
  39. #include "unicode.h"
  40. #include "unicode5.h"
  41. #include "catdb.h"
  42. #define CRYPTSVC_EVENT_STOP "CRYPTSVC_EVENT_STOP"
  43. #define RTN_OK 0 // no errors
  44. #define RTN_USAGE 1 // usage error (invalid commandline)
  45. #define RTN_ERROR_INIT 2 // error during service initialization
  46. #define RTN_ERROR_INSTALL 13 // error during -install or -remove
  47. #define RTN_ERROR_INSTALL_SIG 14 // error installing signature(s)
  48. #define RTN_ERROR_INSTALL_START 15 // could not start service during install
  49. #define RTN_ERROR_INSTALL_SHEXT 16 // error installing shell extension
  50. //
  51. // global module handle used to reference resources contained in this module.
  52. //
  53. HINSTANCE g_hInst = NULL;
  54. // internal variables
  55. static SERVICE_STATUS ssStatus; // current status of the service
  56. SERVICE_STATUS_HANDLE sshStatusHandle;
  57. // internal function prototypes
  58. void WINAPI service_ctrl(DWORD dwCtrlCode);
  59. void WINAPI CryptServiceMain(DWORD dwArgc, LPWSTR *lpszArgv);
  60. extern BOOL _CatDBServiceInit(BOOL fUnInit);
  61. //
  62. // forward declaration for security callbacks
  63. //
  64. RPC_IF_CALLBACK_FN CryptSvcSecurityCallback;
  65. long __stdcall
  66. CryptSvcSecurityCallback(void * Interface, void *Context)
  67. {
  68. RPC_STATUS Status;
  69. unsigned int RpcClientLocalFlag;
  70. Status = I_RpcBindingIsClientLocal(NULL, &RpcClientLocalFlag);
  71. if (Status != RPC_S_OK)
  72. {
  73. return (RPC_S_ACCESS_DENIED);
  74. }
  75. if (RpcClientLocalFlag == 0)
  76. {
  77. return (RPC_S_ACCESS_DENIED);
  78. }
  79. return (RPC_S_OK);
  80. }
  81. BOOL
  82. WINAPI
  83. DllMain(
  84. HMODULE hInst,
  85. DWORD dwReason,
  86. LPVOID lpReserved
  87. )
  88. {
  89. if( dwReason == DLL_PROCESS_ATTACH ) {
  90. g_hInst = hInst;
  91. DisableThreadLibraryCalls(hInst);
  92. }
  93. return TRUE;
  94. }
  95. DWORD
  96. WINAPI
  97. Start(
  98. LPVOID lpV
  99. )
  100. {
  101. BOOL fIsNT = FIsWinNT();
  102. int iRet;
  103. //
  104. // surpress dialog boxes generated by missing files, etc.
  105. //
  106. SetErrorMode(SEM_NOOPENFILEERRORBOX);
  107. SERVICE_TABLE_ENTRYW dispatchTable[] =
  108. {
  109. { SZSERVICENAME, (LPSERVICE_MAIN_FUNCTIONW)CryptServiceMain },
  110. { NULL, NULL }
  111. };
  112. #ifdef WIN95_LEGACY
  113. if (!fIsNT)
  114. goto dispatch95;
  115. #endif // WIN95_LEGACY
  116. // if it doesn't match any of the above parameters
  117. // the service control manager may be starting the service
  118. // so we must call StartServiceCtrlDispatcher
  119. if(!FIsWinNT5()) {
  120. if (!StartServiceCtrlDispatcherW(dispatchTable))
  121. AddToMessageLog(L"StartServiceCtrlDispatcher failed.");
  122. } else {
  123. CryptServiceMain( 0, NULL );
  124. }
  125. return RTN_OK;
  126. #ifdef WIN95_LEGACY
  127. dispatch95:
  128. //
  129. // Win95 doesn't support services, except as pseudo-.exe files
  130. //
  131. HMODULE hKernel = GetModuleHandleA("kernel32.dll");
  132. if (NULL == hKernel)
  133. {
  134. AddToMessageLog(L"RegisterServiceProcess module handle failed");
  135. return RTN_ERROR_INIT;
  136. }
  137. // inline typedef: COOL!
  138. typedef DWORD REGISTERSERVICEPROCESS(
  139. DWORD dwProcessId,
  140. DWORD dwServiceType);
  141. REGISTERSERVICEPROCESS* pfnRegSvcProc = NULL;
  142. // Make sure Win95 Logoff won't stop our .exe
  143. if (NULL == (pfnRegSvcProc = (REGISTERSERVICEPROCESS*)GetProcAddress(hKernel, "RegisterServiceProcess")))
  144. {
  145. AddToMessageLog(L"RegisterServiceProcess failed");
  146. return RTN_ERROR_INIT;
  147. }
  148. pfnRegSvcProc(GetCurrentProcessId(), TRUE); // register this process ID as a service process
  149. //
  150. // call re-entry point and return with result of it.
  151. //
  152. iRet = ServiceStart(0, 0);
  153. if(iRet != ERROR_SUCCESS)
  154. AddToMessageLog(L"ServiceStart error!");
  155. return iRet;
  156. #endif // WIN95_LEGACY
  157. }
  158. //
  159. // FUNCTION: CryptServiceMain
  160. //
  161. // PURPOSE: To perform actual initialization of the service
  162. //
  163. // PARAMETERS:
  164. // dwArgc - number of command line arguments
  165. // lpszArgv - array of command line arguments
  166. //
  167. // RETURN VALUE:
  168. // none
  169. //
  170. // COMMENTS:
  171. // This routine performs the service initialization and then calls
  172. // the user defined ServiceStart() routine to perform majority
  173. // of the work.
  174. //
  175. void WINAPI CryptServiceMain(DWORD dwArgc, LPWSTR * /*lpszArgv*/)
  176. {
  177. DWORD dwLastError = ERROR_SUCCESS;
  178. // register our service control handler:
  179. //
  180. sshStatusHandle = RegisterServiceCtrlHandlerW( SZSERVICENAME, service_ctrl);
  181. if (!sshStatusHandle)
  182. return;
  183. // SERVICE_STATUS members that don't change in example
  184. //
  185. ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  186. ssStatus.dwServiceSpecificExitCode = 0;
  187. // report the status to the service control manager.
  188. //
  189. if (!ReportStatusToSCMgr(
  190. SERVICE_START_PENDING, // service state
  191. NO_ERROR, // exit code
  192. 3000 // wait hint
  193. )) return ;
  194. dwLastError = ServiceStart(0, 0);
  195. return;
  196. }
  197. //
  198. // FUNCTION: service_ctrl
  199. //
  200. // PURPOSE: This function is called by the SCM whenever
  201. // ControlService() is called on this service.
  202. //
  203. // PARAMETERS:
  204. // dwCtrlCode - type of control requested
  205. //
  206. // RETURN VALUE:
  207. // none
  208. //
  209. // COMMENTS:
  210. //
  211. VOID WINAPI service_ctrl(DWORD dwCtrlCode)
  212. {
  213. // Handle the requested control code.
  214. //
  215. switch(dwCtrlCode)
  216. {
  217. // Stop the service.
  218. //
  219. case SERVICE_CONTROL_STOP:
  220. //
  221. // tell the SCM we are stopping before triggering StopService() code
  222. // to avoid potential race condition during STOP_PENDING -> STOPPED transition
  223. //
  224. ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
  225. ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
  226. ServiceStop();
  227. return;
  228. case SERVICE_CONTROL_SHUTDOWN:
  229. ServiceStop();
  230. return;
  231. // Update the service status.
  232. //
  233. case SERVICE_CONTROL_INTERROGATE:
  234. break;
  235. // invalid control code
  236. //
  237. default:
  238. break;
  239. }
  240. ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
  241. }
  242. //
  243. // FUNCTION: ReportStatusToSCMgr()
  244. //
  245. // PURPOSE: Sets the current status of the service and
  246. // reports it to the Service Control Manager
  247. //
  248. // PARAMETERS:
  249. // dwCurrentState - the state of the service
  250. // dwWin32ExitCode - error code to report
  251. // dwWaitHint - worst case estimate to next checkpoint
  252. //
  253. // RETURN VALUE:
  254. // TRUE - success
  255. // FALSE - failure
  256. //
  257. // COMMENTS:
  258. //
  259. BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
  260. DWORD dwWin32ExitCode,
  261. DWORD dwWaitHint)
  262. {
  263. static DWORD dwCheckPoint = 1;
  264. BOOL fResult = TRUE;
  265. if (dwCurrentState == SERVICE_START_PENDING)
  266. ssStatus.dwControlsAccepted = 0;
  267. else
  268. ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  269. SERVICE_ACCEPT_SHUTDOWN;
  270. ssStatus.dwCurrentState = dwCurrentState;
  271. if(dwWin32ExitCode == 0) {
  272. ssStatus.dwWin32ExitCode = 0;
  273. } else {
  274. ssStatus.dwServiceSpecificExitCode = dwWin32ExitCode;
  275. ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  276. }
  277. ssStatus.dwWaitHint = dwWaitHint;
  278. if ( ( dwCurrentState == SERVICE_RUNNING ) ||
  279. ( dwCurrentState == SERVICE_STOPPED ) )
  280. ssStatus.dwCheckPoint = 0;
  281. else
  282. ssStatus.dwCheckPoint = dwCheckPoint++;
  283. // Report the status of the service to the service control manager.
  284. //
  285. if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus))) {
  286. AddToMessageLog(L"SetServiceStatus");
  287. }
  288. return fResult;
  289. }
  290. //
  291. // FUNCTION: AddToMessageLog(LPWSTR lpszMsg)
  292. //
  293. // PURPOSE: Allows any thread to log an error message
  294. //
  295. // PARAMETERS:
  296. // lpszMsg - text for message
  297. //
  298. // RETURN VALUE:
  299. // none
  300. //
  301. // COMMENTS:
  302. //
  303. VOID AddToMessageLog(LPWSTR lpszMsg)
  304. {
  305. DWORD dwLastError = GetLastError();
  306. if(FIsWinNT()) {
  307. //
  308. // WinNT: Use event logging to log the error.
  309. //
  310. WCHAR szMsg[512];
  311. HANDLE hEventSource;
  312. LPWSTR lpszStrings[2];
  313. hEventSource = RegisterEventSourceW(NULL, SZSERVICENAME);
  314. if(hEventSource == NULL)
  315. return;
  316. wsprintfW(szMsg, L"%s error: %lu", SZSERVICENAME, dwLastError);
  317. lpszStrings[0] = szMsg;
  318. lpszStrings[1] = lpszMsg;
  319. ReportEventW(hEventSource, // handle of event source
  320. EVENTLOG_ERROR_TYPE, // event type
  321. 0, // event category
  322. 0, // event ID
  323. NULL, // current user's SID
  324. 2, // strings in lpszStrings
  325. 0, // no bytes of raw data
  326. (LPCWSTR*)lpszStrings, // array of error strings
  327. NULL); // no raw data
  328. (VOID) DeregisterEventSource(hEventSource);
  329. }
  330. #ifdef WIN95_LEGACY
  331. else {
  332. //
  333. // Win95: log error to file
  334. //
  335. HANDLE hFile;
  336. SYSTEMTIME st;
  337. CHAR szMsgOut[512];
  338. DWORD cchMsgOut;
  339. DWORD dwBytesWritten;
  340. hFile = CreateFileA(
  341. "pstore.log",
  342. GENERIC_WRITE,
  343. FILE_SHARE_READ,
  344. NULL,
  345. OPEN_ALWAYS,
  346. 0,
  347. NULL
  348. );
  349. if(hFile == INVALID_HANDLE_VALUE)
  350. return;
  351. GetSystemTime( &st );
  352. cchMsgOut = wsprintfA(szMsgOut, "%.2u-%.2u-%.2u %.2u:%.2u:%.2u %ls (rc=%lu)\015\012",
  353. st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond,
  354. lpszMsg,
  355. dwLastError
  356. );
  357. //
  358. // seek to EOF
  359. //
  360. SetFilePointer(hFile, 0, NULL, FILE_END);
  361. WriteFile(hFile, szMsgOut, cchMsgOut, &dwBytesWritten, NULL);
  362. CloseHandle(hFile);
  363. }
  364. #endif // WIN95_LEGACY
  365. }
  366. // this event is signalled when the
  367. // service should end
  368. //
  369. HANDLE hServerStopEvent = NULL;
  370. extern DWORD GlobalSecurityMask;
  371. extern BOOL g_bAudit;
  372. //
  373. // waitable thread pool handle.
  374. //
  375. HANDLE hRegisteredWait = NULL;
  376. VOID
  377. TeardownServer(
  378. DWORD dwLastError
  379. );
  380. VOID
  381. NTAPI
  382. TerminationNotify(
  383. PVOID Context,
  384. BOOLEAN TimerOrWaitFired
  385. );
  386. //
  387. // FUNCTION: ServiceStart
  388. //
  389. // COMMENTS:
  390. // The service
  391. // stops when hServerStopEvent is signalled
  392. DWORD
  393. ServiceStart(
  394. HINSTANCE hInstance,
  395. int nCmdShow
  396. )
  397. {
  398. DWORD dwLastError = ERROR_SUCCESS;
  399. BOOL fStartedKeyService = FALSE;
  400. BOOL bListConstruct = FALSE;
  401. LPWSTR pwszServerPrincipalName = NULL;
  402. // Only on Win95 do we use a named event, in order to support shutting
  403. // down the server cleanly on that platform, since Win95 does not support
  404. // real services.
  405. hServerStopEvent = CreateEventA(
  406. NULL,
  407. TRUE, // manual reset event
  408. FALSE, // not-signalled
  409. (FIsWinNT() ? NULL : CRYPTSVC_EVENT_STOP) // WinNT: unnamed, Win95 named
  410. );
  411. //
  412. // if event already exists, terminate quietly so that only one instance
  413. // of the service is allowed.
  414. //
  415. if(hServerStopEvent && GetLastError() == ERROR_ALREADY_EXISTS) {
  416. CloseHandle(hServerStopEvent);
  417. hServerStopEvent = NULL;
  418. }
  419. if(hServerStopEvent == NULL) {
  420. dwLastError = GetLastError();
  421. goto cleanup;
  422. }
  423. //
  424. // report the status to the service control manager.
  425. // (service start still pending).
  426. //
  427. if (!ReportStatusToSCMgr(
  428. SERVICE_START_PENDING, // service state
  429. NO_ERROR, // exit code
  430. 3000 // wait hint
  431. )) {
  432. dwLastError = GetLastError();
  433. goto cleanup;
  434. }
  435. dwLastError = StartKeyService();
  436. if(ERROR_SUCCESS != dwLastError)
  437. {
  438. dwLastError = GetLastError();
  439. goto cleanup;
  440. }
  441. if (!_CatDBServiceInit(FALSE))
  442. {
  443. dwLastError = GetLastError();
  444. goto cleanup;
  445. }
  446. //
  447. // Initialize the RPC interfaces for
  448. // Key Service, ICertProt, etc.
  449. RPC_STATUS status;
  450. status = RpcServerUseProtseqEpW(KEYSVC_DEFAULT_PROT_SEQ,
  451. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  452. KEYSVC_DEFAULT_ENDPOINT,
  453. NULL); //Security Descriptor
  454. if(RPC_S_DUPLICATE_ENDPOINT == status)
  455. {
  456. status = RPC_S_OK;
  457. }
  458. if (status)
  459. {
  460. dwLastError = status;
  461. goto cleanup;
  462. }
  463. status = RpcServerUseProtseqEpW(KEYSVC_LOCAL_PROT_SEQ, //ncalrpc
  464. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  465. KEYSVC_LOCAL_ENDPOINT, //keysvc
  466. NULL); //Security Descriptor
  467. if(RPC_S_DUPLICATE_ENDPOINT == status)
  468. {
  469. status = RPC_S_OK;
  470. }
  471. if (status)
  472. {
  473. dwLastError = status;
  474. goto cleanup;
  475. }
  476. status = RpcServerRegisterIfEx(s_IKeySvc_v1_0_s_ifspec,
  477. NULL,
  478. NULL,
  479. RPC_IF_AUTOLISTEN,
  480. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  481. NULL);
  482. if (status)
  483. {
  484. dwLastError = status;
  485. goto cleanup;
  486. }
  487. status = RpcServerRegisterIfEx(s_IKeySvcR_v1_0_s_ifspec,
  488. NULL,
  489. NULL,
  490. RPC_IF_AUTOLISTEN,
  491. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  492. NULL);
  493. if (status)
  494. {
  495. dwLastError = status;
  496. goto cleanup;
  497. }
  498. status = RpcServerRegisterIfEx(s_ICertProtectFunctions_v1_0_s_ifspec,
  499. NULL,
  500. NULL,
  501. RPC_IF_AUTOLISTEN,
  502. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  503. CryptSvcSecurityCallback);
  504. if (status)
  505. {
  506. dwLastError = status;
  507. goto cleanup;
  508. }
  509. status = RpcServerRegisterIfEx(s_ICatDBSvc_v1_0_s_ifspec,
  510. NULL,
  511. NULL,
  512. RPC_IF_AUTOLISTEN,
  513. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  514. CryptSvcSecurityCallback);
  515. if (status)
  516. {
  517. dwLastError = status;
  518. goto cleanup;
  519. }
  520. //
  521. // report the status to the service control manager.
  522. //
  523. if (!ReportStatusToSCMgr(
  524. SERVICE_RUNNING, // service state
  525. NO_ERROR, // exit code
  526. 0 // wait hint
  527. )) {
  528. dwLastError = GetLastError();
  529. goto cleanup;
  530. }
  531. // allow clients to make authenticated requests
  532. status = RpcServerInqDefaultPrincName(RPC_C_AUTHN_GSS_NEGOTIATE, &pwszServerPrincipalName);
  533. if (RPC_S_OK != status)
  534. {
  535. //BUGBUG: Shouldn't prevent service from startin just because auth failed.
  536. // We should log an event here.
  537. }
  538. else
  539. {
  540. status = RpcServerRegisterAuthInfo
  541. (pwszServerPrincipalName,
  542. RPC_C_AUTHN_GSS_NEGOTIATE,
  543. NULL, // Use default key acquisiting function
  544. NULL // Use default creds
  545. );
  546. if (RPC_S_OK != status)
  547. {
  548. //BUGBUG: Shouldn't prevent service from startin just because auth failed.
  549. // We should log an event here.
  550. }
  551. }
  552. //
  553. // on WinNT5, ask services.exe to notify us when the service is shutting
  554. // down, and return this thread to the work item queue.
  555. //
  556. if(!RegisterWaitForSingleObject(
  557. &hRegisteredWait,
  558. hServerStopEvent, // wait handle
  559. TerminationNotify, // callback fcn
  560. NULL, // parameter
  561. INFINITE, // timeout
  562. WT_EXECUTELONGFUNCTION | WT_EXECUTEONLYONCE
  563. )) {
  564. hRegisteredWait = NULL;
  565. dwLastError = GetLastError();
  566. }
  567. if (NULL != pwszServerPrincipalName) { RpcStringFreeW(&pwszServerPrincipalName); }
  568. return dwLastError;
  569. cleanup:
  570. TeardownServer( dwLastError );
  571. if (NULL != pwszServerPrincipalName) { RpcStringFreeW(&pwszServerPrincipalName); }
  572. return dwLastError;
  573. }
  574. VOID
  575. NTAPI
  576. TerminationNotify(
  577. PVOID Context,
  578. BOOLEAN TimerOrWaitFired
  579. )
  580. /*++
  581. Routine Description:
  582. This function gets called by a services worker thread when the
  583. termination event gets signaled.
  584. Arguments:
  585. Return Value:
  586. --*/
  587. {
  588. //
  589. // per JSchwart:
  590. // safe to unregister during callback.
  591. //
  592. if( hRegisteredWait ) {
  593. UnregisterWaitEx( hRegisteredWait, NULL );
  594. hRegisteredWait = NULL;
  595. }
  596. TeardownServer( ERROR_SUCCESS );
  597. }
  598. VOID
  599. TeardownServer(
  600. DWORD dwLastError
  601. )
  602. {
  603. RPC_STATUS rpcStatus;
  604. DWORD dwErrToReport = dwLastError;
  605. //
  606. // Unregister RPC Interfaces
  607. rpcStatus = RpcServerUnregisterIf(s_IKeySvc_v1_0_s_ifspec, 0, 0);
  608. if ((rpcStatus != RPC_S_OK) && (dwErrToReport == ERROR_SUCCESS))
  609. {
  610. dwErrToReport = rpcStatus;
  611. }
  612. rpcStatus = RpcServerUnregisterIf(s_IKeySvcR_v1_0_s_ifspec, 0, 0);
  613. if ((rpcStatus != RPC_S_OK) && (dwErrToReport == ERROR_SUCCESS))
  614. {
  615. dwErrToReport = rpcStatus;
  616. }
  617. rpcStatus = RpcServerUnregisterIf(s_ICertProtectFunctions_v1_0_s_ifspec, 0, 0);
  618. if ((rpcStatus != RPC_S_OK) && (dwErrToReport == ERROR_SUCCESS))
  619. {
  620. dwErrToReport = rpcStatus;
  621. }
  622. rpcStatus = RpcServerUnregisterIf(s_ICatDBSvc_v1_0_s_ifspec, 0, 0);
  623. if ((rpcStatus != RPC_S_OK) && (dwErrToReport == ERROR_SUCCESS))
  624. {
  625. dwErrToReport = rpcStatus;
  626. }
  627. //
  628. // stop backup key server
  629. // Note: this function knows internally whether the backup key server
  630. // really started or not.
  631. //
  632. StopKeyService();
  633. _CatDBServiceInit(TRUE);
  634. if(hServerStopEvent) {
  635. SetEvent(hServerStopEvent); // make event signalled to release anyone waiting for termination
  636. CloseHandle(hServerStopEvent);
  637. hServerStopEvent = NULL;
  638. }
  639. ReportStatusToSCMgr(
  640. SERVICE_STOPPED,
  641. dwErrToReport,
  642. 0
  643. );
  644. }
  645. // FUNCTION: ServiceStop
  646. //
  647. // PURPOSE: Stops the service
  648. //
  649. // COMMENTS:
  650. // If a ServiceStop procedure is going to
  651. // take longer than 3 seconds to execute,
  652. // it should spawn a thread to execute the
  653. // stop code, and return. Otherwise, the
  654. // ServiceControlManager will believe that
  655. // the service has stopped responding.
  656. //
  657. VOID ServiceStop()
  658. {
  659. if(hServerStopEvent)
  660. {
  661. PulseEvent(hServerStopEvent); // signal waiting threads and reset to non-signalled
  662. }
  663. }
  664. extern "C"
  665. {
  666. /*********************************************************************/
  667. /* MIDL allocate and free */
  668. /*********************************************************************/
  669. void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)
  670. {
  671. return(LocalAlloc(LMEM_ZEROINIT, len));
  672. }
  673. void __RPC_API midl_user_free(void __RPC_FAR * ptr)
  674. {
  675. //
  676. // sfield: zero memory before freeing it.
  677. // do this because RPC allocates alot on our behalf, and we want to
  678. // be as sanitary as possible with respect to not letting anything
  679. // sensitive go to pagefile.
  680. //
  681. ZeroMemory( ptr, LocalSize( ptr ) );
  682. LocalFree(ptr);
  683. }
  684. void __RPC_FAR * __RPC_API midl_user_reallocate(void __RPC_FAR * ptr, size_t len)
  685. {
  686. return(LocalReAlloc(ptr, len, LMEM_MOVEABLE | LMEM_ZEROINIT));
  687. }
  688. }