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.

1054 lines
26 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 <stdio.h>
  34. #include "keysvr.h"
  35. #include "lenroll.h"
  36. #include "keysvc.h"
  37. #include "keysvcc.h"
  38. #include "cerrpc.h"
  39. #include "service.h"
  40. #include "unicode.h"
  41. #include "unicode5.h"
  42. #include "catdb.h"
  43. #include "cryptmsg.h"
  44. #define CRYPTSVC_EVENT_STOP "CRYPTSVC_EVENT_STOP"
  45. #define RTN_OK 0 // no errors
  46. #define RTN_USAGE 1 // usage error (invalid commandline)
  47. #define RTN_ERROR_INIT 2 // error during service initialization
  48. #define RTN_ERROR_INSTALL 13 // error during -install or -remove
  49. #define RTN_ERROR_INSTALL_SIG 14 // error installing signature(s)
  50. #define RTN_ERROR_INSTALL_START 15 // could not start service during install
  51. #define RTN_ERROR_INSTALL_SHEXT 16 // error installing shell extension
  52. //
  53. // global module handle used to reference resources contained in this module.
  54. //
  55. HINSTANCE g_hInst = NULL;
  56. // internal variables
  57. static SERVICE_STATUS ssStatus; // current status of the service
  58. SERVICE_STATUS_HANDLE sshStatusHandle;
  59. // internal function prototypes
  60. void WINAPI service_ctrl(DWORD dwCtrlCode);
  61. void WINAPI CryptServiceMain(DWORD dwArgc, LPWSTR *lpszArgv);
  62. BOOL IsAdministrator(VOID);
  63. extern BOOL _CatDBServiceInit(BOOL fUnInit);
  64. //
  65. // forward declaration for security callbacks
  66. //
  67. RPC_IF_CALLBACK_FN CryptSvcSecurityCallback;
  68. long __stdcall
  69. CryptSvcSecurityCallback(void * Interface, void *Context)
  70. {
  71. RPC_STATUS Status;
  72. unsigned int RpcClientLocalFlag;
  73. Status = I_RpcBindingIsClientLocal(NULL, &RpcClientLocalFlag);
  74. if (Status != RPC_S_OK)
  75. {
  76. return (RPC_S_ACCESS_DENIED);
  77. }
  78. if (RpcClientLocalFlag == 0)
  79. {
  80. return (RPC_S_ACCESS_DENIED);
  81. }
  82. return (RPC_S_OK);
  83. }
  84. //
  85. // Returns RPC_S_OK if the binding represents a local administrator on this box,
  86. // AND if the binding is local.
  87. //
  88. long __stdcall
  89. KeySvcSecurityCallback(void * Interface, void *Context)
  90. {
  91. BOOL fIsImpersonatingClient = FALSE;
  92. RPC_STATUS rpcStatus;
  93. unsigned int RpcClientLocalFlag;
  94. rpcStatus = I_RpcBindingIsClientLocal(NULL, &RpcClientLocalFlag);
  95. if (rpcStatus != RPC_S_OK)
  96. goto error;
  97. if (!RpcClientLocalFlag) {
  98. rpcStatus = RPC_S_ACCESS_DENIED;
  99. goto error;
  100. }
  101. rpcStatus = RpcImpersonateClient(NULL);
  102. if (rpcStatus != RPC_S_OK)
  103. goto error;
  104. fIsImpersonatingClient = TRUE;
  105. if (!IsAdministrator()) {
  106. rpcStatus = RPC_S_ACCESS_DENIED;
  107. goto error;
  108. }
  109. rpcStatus = RPC_S_OK;
  110. error:
  111. if (fIsImpersonatingClient) {
  112. RPC_STATUS rpcStatus2 = RpcRevertToSelfEx(NULL);
  113. if (RPC_S_OK != rpcStatus2) {
  114. MyLogErrorMessage(rpcStatus2, MSG_KEYSVC_REVERT_TO_SELF_FAILED);
  115. }
  116. }
  117. return rpcStatus;
  118. }
  119. //
  120. // Returns RPC_S_OK if the binding represents a local administrator on this box.
  121. // Does not require that the binding be local.
  122. //
  123. long __stdcall
  124. RKeySvcSecurityCallback(void * Interface, void *Context)
  125. {
  126. BOOL fIsImpersonatingClient = FALSE;
  127. RPC_STATUS rpcStatus;
  128. rpcStatus = RpcImpersonateClient(NULL);
  129. if (rpcStatus != RPC_S_OK)
  130. goto error;
  131. fIsImpersonatingClient = TRUE;
  132. if (!IsAdministrator()) {
  133. rpcStatus = RPC_S_ACCESS_DENIED;
  134. goto error;
  135. }
  136. rpcStatus = RPC_S_OK;
  137. error:
  138. if (fIsImpersonatingClient) {
  139. RPC_STATUS rpcStatus2 = RpcRevertToSelfEx(NULL);
  140. if (RPC_S_OK != rpcStatus2) {
  141. MyLogErrorMessage(rpcStatus2, MSG_KEYSVC_REVERT_TO_SELF_FAILED);
  142. }
  143. }
  144. return rpcStatus;
  145. }
  146. BOOL
  147. WINAPI
  148. DllMain(
  149. HMODULE hInst,
  150. DWORD dwReason,
  151. LPVOID lpReserved
  152. )
  153. {
  154. if( dwReason == DLL_PROCESS_ATTACH ) {
  155. g_hInst = hInst;
  156. DisableThreadLibraryCalls(hInst);
  157. }
  158. return TRUE;
  159. }
  160. DWORD
  161. WINAPI
  162. Start(
  163. LPVOID lpV
  164. )
  165. {
  166. BOOL fIsNT = FIsWinNT();
  167. int iRet;
  168. //
  169. // surpress dialog boxes generated by missing files, etc.
  170. //
  171. SetErrorMode(SEM_NOOPENFILEERRORBOX);
  172. SERVICE_TABLE_ENTRYW dispatchTable[] =
  173. {
  174. { SZSERVICENAME, (LPSERVICE_MAIN_FUNCTIONW)CryptServiceMain },
  175. { NULL, NULL }
  176. };
  177. #ifdef WIN95_LEGACY
  178. if (!fIsNT)
  179. goto dispatch95;
  180. #endif // WIN95_LEGACY
  181. // if it doesn't match any of the above parameters
  182. // the service control manager may be starting the service
  183. // so we must call StartServiceCtrlDispatcher
  184. if(!FIsWinNT5()) {
  185. if (!StartServiceCtrlDispatcherW(dispatchTable))
  186. AddToMessageLog(L"StartServiceCtrlDispatcher failed.");
  187. } else {
  188. CryptServiceMain( 0, NULL );
  189. }
  190. return RTN_OK;
  191. #ifdef WIN95_LEGACY
  192. dispatch95:
  193. //
  194. // Win95 doesn't support services, except as pseudo-.exe files
  195. //
  196. HMODULE hKernel = GetModuleHandleA("kernel32.dll");
  197. if (NULL == hKernel)
  198. {
  199. AddToMessageLog(L"RegisterServiceProcess module handle failed");
  200. return RTN_ERROR_INIT;
  201. }
  202. // inline typedef: COOL!
  203. typedef DWORD REGISTERSERVICEPROCESS(
  204. DWORD dwProcessId,
  205. DWORD dwServiceType);
  206. REGISTERSERVICEPROCESS* pfnRegSvcProc = NULL;
  207. // Make sure Win95 Logoff won't stop our .exe
  208. if (NULL == (pfnRegSvcProc = (REGISTERSERVICEPROCESS*)GetProcAddress(hKernel, "RegisterServiceProcess")))
  209. {
  210. AddToMessageLog(L"RegisterServiceProcess failed");
  211. return RTN_ERROR_INIT;
  212. }
  213. pfnRegSvcProc(GetCurrentProcessId(), TRUE); // register this process ID as a service process
  214. //
  215. // call re-entry point and return with result of it.
  216. //
  217. iRet = ServiceStart(0, 0);
  218. if(iRet != ERROR_SUCCESS)
  219. AddToMessageLog(L"ServiceStart error!");
  220. return iRet;
  221. #endif // WIN95_LEGACY
  222. }
  223. //
  224. // FUNCTION: CryptServiceMain
  225. //
  226. // PURPOSE: To perform actual initialization of the service
  227. //
  228. // PARAMETERS:
  229. // dwArgc - number of command line arguments
  230. // lpszArgv - array of command line arguments
  231. //
  232. // RETURN VALUE:
  233. // none
  234. //
  235. // COMMENTS:
  236. // This routine performs the service initialization and then calls
  237. // the user defined ServiceStart() routine to perform majority
  238. // of the work.
  239. //
  240. void WINAPI CryptServiceMain(DWORD dwArgc, LPWSTR * /*lpszArgv*/)
  241. {
  242. DWORD dwLastError = ERROR_SUCCESS;
  243. // register our service control handler:
  244. //
  245. sshStatusHandle = RegisterServiceCtrlHandlerW( SZSERVICENAME, service_ctrl);
  246. if (!sshStatusHandle)
  247. return;
  248. // SERVICE_STATUS members that don't change in example
  249. //
  250. ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  251. ssStatus.dwServiceSpecificExitCode = 0;
  252. // report the status to the service control manager.
  253. //
  254. if (!ReportStatusToSCMgr(
  255. SERVICE_START_PENDING, // service state
  256. NO_ERROR, // exit code
  257. 3000 // wait hint
  258. )) return ;
  259. dwLastError = ServiceStart(0, 0);
  260. return;
  261. }
  262. //
  263. // FUNCTION: service_ctrl
  264. //
  265. // PURPOSE: This function is called by the SCM whenever
  266. // ControlService() is called on this service.
  267. //
  268. // PARAMETERS:
  269. // dwCtrlCode - type of control requested
  270. //
  271. // RETURN VALUE:
  272. // none
  273. //
  274. // COMMENTS:
  275. //
  276. VOID WINAPI service_ctrl(DWORD dwCtrlCode)
  277. {
  278. // Handle the requested control code.
  279. //
  280. switch(dwCtrlCode)
  281. {
  282. // Stop the service.
  283. //
  284. case SERVICE_CONTROL_STOP:
  285. //
  286. // tell the SCM we are stopping before triggering StopService() code
  287. // to avoid potential race condition during STOP_PENDING -> STOPPED transition
  288. //
  289. ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
  290. ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
  291. ServiceStop();
  292. return;
  293. case SERVICE_CONTROL_SHUTDOWN:
  294. ServiceStop();
  295. return;
  296. // Update the service status.
  297. //
  298. case SERVICE_CONTROL_INTERROGATE:
  299. break;
  300. // invalid control code
  301. //
  302. default:
  303. break;
  304. }
  305. ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
  306. }
  307. //
  308. // FUNCTION: ReportStatusToSCMgr()
  309. //
  310. // PURPOSE: Sets the current status of the service and
  311. // reports it to the Service Control Manager
  312. //
  313. // PARAMETERS:
  314. // dwCurrentState - the state of the service
  315. // dwWin32ExitCode - error code to report
  316. // dwWaitHint - worst case estimate to next checkpoint
  317. //
  318. // RETURN VALUE:
  319. // TRUE - success
  320. // FALSE - failure
  321. //
  322. // COMMENTS:
  323. //
  324. BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
  325. DWORD dwWin32ExitCode,
  326. DWORD dwWaitHint)
  327. {
  328. static DWORD dwCheckPoint = 1;
  329. BOOL fResult = TRUE;
  330. if (dwCurrentState == SERVICE_START_PENDING)
  331. ssStatus.dwControlsAccepted = 0;
  332. else
  333. ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  334. SERVICE_ACCEPT_SHUTDOWN;
  335. ssStatus.dwCurrentState = dwCurrentState;
  336. if(dwWin32ExitCode == 0) {
  337. ssStatus.dwWin32ExitCode = 0;
  338. } else {
  339. ssStatus.dwServiceSpecificExitCode = dwWin32ExitCode;
  340. ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  341. }
  342. ssStatus.dwWaitHint = dwWaitHint;
  343. if ( ( dwCurrentState == SERVICE_RUNNING ) ||
  344. ( dwCurrentState == SERVICE_STOPPED ) )
  345. ssStatus.dwCheckPoint = 0;
  346. else
  347. ssStatus.dwCheckPoint = dwCheckPoint++;
  348. // Report the status of the service to the service control manager.
  349. //
  350. if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus))) {
  351. AddToMessageLog(L"SetServiceStatus");
  352. }
  353. return fResult;
  354. }
  355. //
  356. // FUNCTION: AddToMessageLog(LPWSTR lpszMsg)
  357. //
  358. // PURPOSE: Allows any thread to log an error message
  359. //
  360. // PARAMETERS:
  361. // lpszMsg - text for message
  362. //
  363. // RETURN VALUE:
  364. // none
  365. //
  366. // COMMENTS:
  367. //
  368. VOID AddToMessageLog(LPWSTR lpszMsg)
  369. {
  370. DWORD dwLastError = GetLastError();
  371. if(FIsWinNT()) {
  372. //
  373. // WinNT: Use event logging to log the error.
  374. //
  375. WCHAR szMsg[512];
  376. HANDLE hEventSource;
  377. LPWSTR lpszStrings[2];
  378. hEventSource = RegisterEventSourceW(NULL, SZSERVICENAME);
  379. if(hEventSource == NULL)
  380. return;
  381. wsprintfW(szMsg, L"%s error: %lu", SZSERVICENAME, dwLastError);
  382. lpszStrings[0] = szMsg;
  383. lpszStrings[1] = lpszMsg;
  384. ReportEventW(hEventSource, // handle of event source
  385. EVENTLOG_ERROR_TYPE, // event type
  386. 0, // event category
  387. 0, // event ID
  388. NULL, // current user's SID
  389. 2, // strings in lpszStrings
  390. 0, // no bytes of raw data
  391. (LPCWSTR*)lpszStrings, // array of error strings
  392. NULL); // no raw data
  393. (VOID) DeregisterEventSource(hEventSource);
  394. }
  395. #ifdef WIN95_LEGACY
  396. else {
  397. //
  398. // Win95: log error to file
  399. //
  400. HANDLE hFile;
  401. SYSTEMTIME st;
  402. CHAR szMsgOut[512];
  403. DWORD cchMsgOut;
  404. DWORD dwBytesWritten;
  405. hFile = CreateFileA(
  406. "pstore.log",
  407. GENERIC_WRITE,
  408. FILE_SHARE_READ,
  409. NULL,
  410. OPEN_ALWAYS,
  411. 0,
  412. NULL
  413. );
  414. if(hFile == INVALID_HANDLE_VALUE)
  415. return;
  416. GetSystemTime( &st );
  417. cchMsgOut = wsprintfA(szMsgOut, "%.2u-%.2u-%.2u %.2u:%.2u:%.2u %ls (rc=%lu)\015\012",
  418. st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond,
  419. lpszMsg,
  420. dwLastError
  421. );
  422. //
  423. // seek to EOF
  424. //
  425. SetFilePointer(hFile, 0, NULL, FILE_END);
  426. WriteFile(hFile, szMsgOut, cchMsgOut, &dwBytesWritten, NULL);
  427. CloseHandle(hFile);
  428. }
  429. #endif // WIN95_LEGACY
  430. }
  431. //--------------------------------------------------------------------
  432. VOID MyLogEvent(WORD wType, DWORD dwEventID, unsigned int nStrings, const WCHAR ** rgwszStrings) {
  433. HANDLE hEventLog = NULL;
  434. hEventLog = RegisterEventSource(NULL, L"cryptsvc");
  435. if (NULL == hEventLog) {
  436. goto error;
  437. }
  438. if (!ReportEvent(hEventLog, wType, 0/*category*/, dwEventID, NULL, (WORD)nStrings, 0, rgwszStrings, NULL)) {
  439. goto error;
  440. }
  441. error:
  442. if (NULL != hEventLog) {
  443. DeregisterEventSource(hEventLog);
  444. }
  445. }
  446. //--------------------------------------------------------------------
  447. VOID MyLogErrorMessage(DWORD dwErr, DWORD dwMsgId) {
  448. const WCHAR *rgwszStrings[2];
  449. WCHAR wszNumberBuf[20];
  450. WCHAR *pwszError = NULL;
  451. swprintf(wszNumberBuf, L"0x%08X", dwErr);
  452. rgwszStrings[0] = wszNumberBuf;
  453. if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  454. FORMAT_MESSAGE_FROM_SYSTEM |
  455. FORMAT_MESSAGE_IGNORE_INSERTS,
  456. NULL,
  457. dwErr,
  458. 0,
  459. (LPWSTR) &pwszError,
  460. 0,
  461. NULL)) {
  462. rgwszStrings[1] = pwszError;
  463. } else {
  464. rgwszStrings[1] = L"";
  465. }
  466. MyLogEvent(EVENTLOG_ERROR_TYPE, dwMsgId, 2, rgwszStrings);
  467. if (NULL != pwszError) {
  468. LocalFree(pwszError);
  469. }
  470. }
  471. BOOL IsAdministrator(
  472. VOID
  473. )
  474. /*++
  475. This function determines if the calling user is an Administrator.
  476. On Windows NT, the caller of this function must be impersonating
  477. the user which is to be queried. If the caller is not impersonating,
  478. this function will always return FALSE.
  479. --*/
  480. {
  481. HANDLE hAccessToken;
  482. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  483. PSID psidAdministrators = NULL;
  484. BOOL bSuccess;
  485. if(!OpenThreadToken(
  486. GetCurrentThread(),
  487. TOKEN_QUERY,
  488. TRUE,
  489. &hAccessToken
  490. )) return FALSE;
  491. bSuccess = AllocateAndInitializeSid(
  492. &siaNtAuthority,
  493. 2,
  494. SECURITY_BUILTIN_DOMAIN_RID,
  495. DOMAIN_ALIAS_RID_ADMINS,
  496. 0, 0, 0, 0, 0, 0,
  497. &psidAdministrators
  498. );
  499. if( bSuccess ) {
  500. BOOL fIsMember = FALSE;
  501. bSuccess = CheckTokenMembership( hAccessToken, psidAdministrators, &fIsMember );
  502. if( bSuccess && !fIsMember )
  503. bSuccess = FALSE;
  504. }
  505. CloseHandle( hAccessToken );
  506. if(psidAdministrators)
  507. FreeSid(psidAdministrators);
  508. return bSuccess;
  509. }
  510. // this event is signalled when the
  511. // service should end
  512. //
  513. HANDLE hServerStopEvent = NULL;
  514. extern DWORD GlobalSecurityMask;
  515. extern BOOL g_bAudit;
  516. //
  517. // waitable thread pool handle.
  518. //
  519. HANDLE hRegisteredWait = NULL;
  520. VOID
  521. TeardownServer(
  522. DWORD dwLastError
  523. );
  524. VOID
  525. NTAPI
  526. TerminationNotify(
  527. PVOID Context,
  528. BOOLEAN TimerOrWaitFired
  529. );
  530. //
  531. // FUNCTION: ServiceStart
  532. //
  533. // COMMENTS:
  534. // The service
  535. // stops when hServerStopEvent is signalled
  536. DWORD
  537. ServiceStart(
  538. HINSTANCE hInstance,
  539. int nCmdShow
  540. )
  541. {
  542. DWORD dwLastError = ERROR_SUCCESS;
  543. BOOL fStartedKeyService = FALSE;
  544. BOOL bListConstruct = FALSE;
  545. LPWSTR pwszServerPrincipalName = NULL;
  546. // Only on Win95 do we use a named event, in order to support shutting
  547. // down the server cleanly on that platform, since Win95 does not support
  548. // real services.
  549. hServerStopEvent = CreateEventA(
  550. NULL,
  551. TRUE, // manual reset event
  552. FALSE, // not-signalled
  553. (FIsWinNT() ? NULL : CRYPTSVC_EVENT_STOP) // WinNT: unnamed, Win95 named
  554. );
  555. //
  556. // if event already exists, terminate quietly so that only one instance
  557. // of the service is allowed.
  558. //
  559. if(hServerStopEvent && GetLastError() == ERROR_ALREADY_EXISTS) {
  560. CloseHandle(hServerStopEvent);
  561. hServerStopEvent = NULL;
  562. }
  563. if(hServerStopEvent == NULL) {
  564. dwLastError = GetLastError();
  565. goto cleanup;
  566. }
  567. //
  568. // report the status to the service control manager.
  569. // (service start still pending).
  570. //
  571. if (!ReportStatusToSCMgr(
  572. SERVICE_START_PENDING, // service state
  573. NO_ERROR, // exit code
  574. 3000 // wait hint
  575. )) {
  576. dwLastError = GetLastError();
  577. goto cleanup;
  578. }
  579. dwLastError = StartKeyService();
  580. if(ERROR_SUCCESS != dwLastError)
  581. {
  582. dwLastError = GetLastError();
  583. goto cleanup;
  584. }
  585. if (!_CatDBServiceInit(FALSE))
  586. {
  587. dwLastError = GetLastError();
  588. goto cleanup;
  589. }
  590. //
  591. // Initialize the RPC interfaces for
  592. // Key Service, ICertProt, etc.
  593. RPC_STATUS status;
  594. status = RpcServerUseProtseqEpW(KEYSVC_DEFAULT_PROT_SEQ,
  595. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  596. KEYSVC_DEFAULT_ENDPOINT,
  597. NULL); //Security Descriptor
  598. if(RPC_S_DUPLICATE_ENDPOINT == status)
  599. {
  600. status = RPC_S_OK;
  601. }
  602. if (status)
  603. {
  604. dwLastError = status;
  605. goto cleanup;
  606. }
  607. status = RpcServerUseProtseqEpW(KEYSVC_LOCAL_PROT_SEQ, //ncalrpc
  608. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  609. KEYSVC_LOCAL_ENDPOINT, //keysvc
  610. NULL); //Security Descriptor
  611. if(RPC_S_DUPLICATE_ENDPOINT == status)
  612. {
  613. status = RPC_S_OK;
  614. }
  615. if (status)
  616. {
  617. dwLastError = status;
  618. goto cleanup;
  619. }
  620. status = RpcServerRegisterIfEx(s_IKeySvc_v1_0_s_ifspec,
  621. NULL,
  622. NULL,
  623. RPC_IF_AUTOLISTEN | RPC_IF_ALLOW_SECURE_ONLY,
  624. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  625. KeySvcSecurityCallback); // require admin and LRPC
  626. if (status)
  627. {
  628. dwLastError = status;
  629. goto cleanup;
  630. }
  631. status = RpcServerRegisterIfEx(s_IKeySvcR_v1_0_s_ifspec,
  632. NULL,
  633. NULL,
  634. RPC_IF_AUTOLISTEN | RPC_IF_ALLOW_SECURE_ONLY,
  635. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  636. RKeySvcSecurityCallback); // require admin, LRPC not required
  637. if (status)
  638. {
  639. dwLastError = status;
  640. goto cleanup;
  641. }
  642. status = RpcServerRegisterIfEx(s_ICertProtectFunctions_v1_0_s_ifspec,
  643. NULL,
  644. NULL,
  645. RPC_IF_AUTOLISTEN,
  646. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  647. CryptSvcSecurityCallback);
  648. if (status)
  649. {
  650. dwLastError = status;
  651. goto cleanup;
  652. }
  653. status = RpcServerRegisterIfEx(s_ICatDBSvc_v1_0_s_ifspec,
  654. NULL,
  655. NULL,
  656. RPC_IF_AUTOLISTEN,
  657. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  658. CryptSvcSecurityCallback);
  659. if (status)
  660. {
  661. dwLastError = status;
  662. goto cleanup;
  663. }
  664. //
  665. // report the status to the service control manager.
  666. //
  667. if (!ReportStatusToSCMgr(
  668. SERVICE_RUNNING, // service state
  669. NO_ERROR, // exit code
  670. 0 // wait hint
  671. )) {
  672. dwLastError = GetLastError();
  673. goto cleanup;
  674. }
  675. // allow clients to make authenticated requests
  676. status = RpcServerInqDefaultPrincName(RPC_C_AUTHN_GSS_NEGOTIATE, &pwszServerPrincipalName);
  677. if (RPC_S_OK != status)
  678. {
  679. // Shouldn't prevent service from startin just because auth failed.
  680. // Just log an event here.
  681. MyLogErrorMessage(status, MSG_RKEYSVC_COULDNT_INIT_SECURITY);
  682. }
  683. else
  684. {
  685. status = RpcServerRegisterAuthInfo
  686. (pwszServerPrincipalName,
  687. RPC_C_AUTHN_GSS_NEGOTIATE,
  688. NULL, // Use default key acquisiting function
  689. NULL // Use default creds
  690. );
  691. if (RPC_S_OK != status)
  692. {
  693. // Shouldn't prevent service from startin just because auth failed.
  694. // Just log an event here.
  695. MyLogErrorMessage(status, MSG_RKEYSVC_COULDNT_INIT_SECURITY);
  696. }
  697. }
  698. //
  699. // on WinNT5, ask services.exe to notify us when the service is shutting
  700. // down, and return this thread to the work item queue.
  701. //
  702. if(!RegisterWaitForSingleObject(
  703. &hRegisteredWait,
  704. hServerStopEvent, // wait handle
  705. TerminationNotify, // callback fcn
  706. NULL, // parameter
  707. INFINITE, // timeout
  708. WT_EXECUTELONGFUNCTION | WT_EXECUTEONLYONCE
  709. )) {
  710. hRegisteredWait = NULL;
  711. dwLastError = GetLastError();
  712. }
  713. if (NULL != pwszServerPrincipalName) { RpcStringFreeW(&pwszServerPrincipalName); }
  714. return dwLastError;
  715. cleanup:
  716. TeardownServer( dwLastError );
  717. if (NULL != pwszServerPrincipalName) { RpcStringFreeW(&pwszServerPrincipalName); }
  718. return dwLastError;
  719. }
  720. VOID
  721. NTAPI
  722. TerminationNotify(
  723. PVOID Context,
  724. BOOLEAN TimerOrWaitFired
  725. )
  726. /*++
  727. Routine Description:
  728. This function gets called by a services worker thread when the
  729. termination event gets signaled.
  730. Arguments:
  731. Return Value:
  732. --*/
  733. {
  734. //
  735. // per JSchwart:
  736. // safe to unregister during callback.
  737. //
  738. if( hRegisteredWait ) {
  739. UnregisterWaitEx( hRegisteredWait, NULL );
  740. hRegisteredWait = NULL;
  741. }
  742. TeardownServer( ERROR_SUCCESS );
  743. }
  744. VOID
  745. TeardownServer(
  746. DWORD dwLastError
  747. )
  748. {
  749. RPC_STATUS rpcStatus;
  750. DWORD dwErrToReport = dwLastError;
  751. //
  752. // Unregister RPC Interfaces
  753. rpcStatus = RpcServerUnregisterIf(s_IKeySvc_v1_0_s_ifspec, 0, 0);
  754. if ((rpcStatus != RPC_S_OK) && (dwErrToReport == ERROR_SUCCESS))
  755. {
  756. dwErrToReport = rpcStatus;
  757. }
  758. rpcStatus = RpcServerUnregisterIf(s_IKeySvcR_v1_0_s_ifspec, 0, 0);
  759. if ((rpcStatus != RPC_S_OK) && (dwErrToReport == ERROR_SUCCESS))
  760. {
  761. dwErrToReport = rpcStatus;
  762. }
  763. rpcStatus = RpcServerUnregisterIf(s_ICertProtectFunctions_v1_0_s_ifspec, 0, 0);
  764. if ((rpcStatus != RPC_S_OK) && (dwErrToReport == ERROR_SUCCESS))
  765. {
  766. dwErrToReport = rpcStatus;
  767. }
  768. rpcStatus = RpcServerUnregisterIf(s_ICatDBSvc_v1_0_s_ifspec, 0, 0);
  769. if ((rpcStatus != RPC_S_OK) && (dwErrToReport == ERROR_SUCCESS))
  770. {
  771. dwErrToReport = rpcStatus;
  772. }
  773. //
  774. // stop backup key server
  775. // Note: this function knows internally whether the backup key server
  776. // really started or not.
  777. //
  778. StopKeyService();
  779. _CatDBServiceInit(TRUE);
  780. if(hServerStopEvent) {
  781. SetEvent(hServerStopEvent); // make event signalled to release anyone waiting for termination
  782. CloseHandle(hServerStopEvent);
  783. hServerStopEvent = NULL;
  784. }
  785. ReportStatusToSCMgr(
  786. SERVICE_STOPPED,
  787. dwErrToReport,
  788. 0
  789. );
  790. }
  791. // FUNCTION: ServiceStop
  792. //
  793. // PURPOSE: Stops the service
  794. //
  795. // COMMENTS:
  796. // If a ServiceStop procedure is going to
  797. // take longer than 3 seconds to execute,
  798. // it should spawn a thread to execute the
  799. // stop code, and return. Otherwise, the
  800. // ServiceControlManager will believe that
  801. // the service has stopped responding.
  802. //
  803. VOID ServiceStop()
  804. {
  805. if(hServerStopEvent)
  806. {
  807. SetEvent(hServerStopEvent); // signal waiting threads and reset to non-signalled
  808. }
  809. }
  810. extern "C"
  811. {
  812. /*********************************************************************/
  813. /* MIDL allocate and free */
  814. /*********************************************************************/
  815. void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)
  816. {
  817. return(LocalAlloc(LMEM_ZEROINIT, len));
  818. }
  819. void __RPC_API midl_user_free(void __RPC_FAR * ptr)
  820. {
  821. //
  822. // sfield: zero memory before freeing it.
  823. // do this because RPC allocates alot on our behalf, and we want to
  824. // be as sanitary as possible with respect to not letting anything
  825. // sensitive go to pagefile.
  826. //
  827. ZeroMemory( ptr, LocalSize( ptr ) );
  828. LocalFree(ptr);
  829. }
  830. void __RPC_FAR * __RPC_API midl_user_reallocate(void __RPC_FAR * ptr, size_t len)
  831. {
  832. return(LocalReAlloc(ptr, len, LMEM_MOVEABLE | LMEM_ZEROINIT));
  833. }
  834. }