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.

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