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.

382 lines
11 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: service.cpp
  7. //
  8. // Contents: Cert Server service processing
  9. //
  10. //---------------------------------------------------------------------------
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. #include "resource.h"
  14. #define __dwFILE__ __dwFILE_CERTSRV_SERVICE_CPP__
  15. SERVICE_STATUS g_ssStatus;
  16. SERVICE_STATUS_HANDLE g_sshStatusHandle;
  17. HANDLE g_hServiceStoppingEvent = NULL;
  18. HANDLE g_hServiceStoppedEvent = NULL;
  19. DWORD g_dwCurrentServiceState = SERVICE_STOPPED;
  20. BOOL
  21. ServiceReportStatusToSCMgrEx(
  22. IN DWORD dwCurrentState,
  23. IN DWORD dwWin32ExitCode,
  24. IN DWORD dwCheckPoint,
  25. IN DWORD dwWaitHint,
  26. IN BOOL fInitialized)
  27. {
  28. BOOL fResult;
  29. HRESULT hr;
  30. // dwWin32ExitCode can only be set to a Win32 error code (not an HRESULT).
  31. g_ssStatus.dwServiceSpecificExitCode = myHError(dwWin32ExitCode);
  32. g_ssStatus.dwWin32ExitCode = HRESULT_CODE(dwWin32ExitCode);
  33. if ((ULONG) HRESULT_FROM_WIN32(g_ssStatus.dwWin32ExitCode) ==
  34. g_ssStatus.dwServiceSpecificExitCode)
  35. {
  36. // If dwWin32ExitCode is a Win32 error, clear dwServiceSpecificExitCode
  37. g_ssStatus.dwServiceSpecificExitCode = S_OK;
  38. }
  39. else
  40. {
  41. // Else dwServiceSpecificExitCode is an HRESULT that cannot be
  42. // translated to a Win32 error, set dwWin32ExitCode to indicate so.
  43. g_ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  44. }
  45. // save this as global state for interrogation
  46. g_dwCurrentServiceState = dwCurrentState;
  47. g_ssStatus.dwControlsAccepted = (SERVICE_START_PENDING == dwCurrentState) ? 0 : SERVICE_ACCEPT_STOP;
  48. // don't say we'll accept PAUSE until we're really going
  49. if (fInitialized)
  50. g_ssStatus.dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
  51. g_ssStatus.dwCurrentState = dwCurrentState;
  52. g_ssStatus.dwCheckPoint = dwCheckPoint;
  53. g_ssStatus.dwWaitHint = dwWaitHint;
  54. fResult = SetServiceStatus(g_sshStatusHandle, &g_ssStatus);
  55. if (!fResult)
  56. {
  57. hr = GetLastError();
  58. _JumpError(hr, error, "SetServiceStatus");
  59. }
  60. DBGPRINT((
  61. DBG_SS_CERTSRVI,
  62. "ServiceReportStatusToSCMgr(state=%x, err=%x(%d), hr=%x(%d), ckpt=%x, wait=%x)\n",
  63. dwCurrentState,
  64. g_ssStatus.dwWin32ExitCode,
  65. g_ssStatus.dwWin32ExitCode,
  66. g_ssStatus.dwServiceSpecificExitCode,
  67. g_ssStatus.dwServiceSpecificExitCode,
  68. dwCheckPoint,
  69. dwWaitHint));
  70. error:
  71. return(fResult);
  72. }
  73. BOOL
  74. ServiceReportStatusToSCMgr(
  75. IN DWORD dwCurrentState,
  76. IN DWORD dwWin32ExitCode,
  77. IN DWORD dwCheckPoint,
  78. IN DWORD dwWaitHint)
  79. {
  80. // most callers don't care about initialized/uninitialized distinction
  81. return ServiceReportStatusToSCMgrEx(
  82. dwCurrentState,
  83. dwWin32ExitCode,
  84. dwCheckPoint,
  85. dwWaitHint,
  86. TRUE);
  87. }
  88. VOID
  89. serviceControlHandler(
  90. IN DWORD dwCtrlCode)
  91. {
  92. switch (dwCtrlCode)
  93. {
  94. case SERVICE_CONTROL_PAUSE:
  95. if (SERVICE_RUNNING == g_ssStatus.dwCurrentState)
  96. {
  97. g_dwCurrentServiceState = SERVICE_PAUSED;
  98. }
  99. break;
  100. case SERVICE_CONTROL_CONTINUE:
  101. if (SERVICE_PAUSED == g_ssStatus.dwCurrentState)
  102. {
  103. g_dwCurrentServiceState = SERVICE_RUNNING;
  104. }
  105. break;
  106. case SERVICE_CONTROL_STOP:
  107. {
  108. HRESULT hr;
  109. DWORD State = 0;
  110. // put us in "stop pending" mode
  111. g_dwCurrentServiceState = SERVICE_STOP_PENDING;
  112. // post STOP message to msgloop and bail
  113. // message loop handles all other shutdown work
  114. // WM_STOPSERVER signals events that trigger thread synchronization, etc.
  115. hr = CertSrvLockServer(&State);
  116. _PrintIfError(hr, "CertSrvLockServer");
  117. PostMessage(g_hwndMain, WM_STOPSERVER, 0, 0);
  118. break;
  119. }
  120. case SERVICE_CONTROL_INTERROGATE:
  121. break;
  122. }
  123. ServiceReportStatusToSCMgr(g_dwCurrentServiceState, NO_ERROR, 0, 0);
  124. }
  125. //+--------------------------------------------------------------------------
  126. // Service Main
  127. // Anatomy for start/stop cert Service
  128. //
  129. // How we go here:
  130. // wWinMain created a thread which called StartServiceCtrlDispatcher, then went
  131. // into a message loop. StartServiceCtrlDispatcher calls us through the SCM and
  132. // blocks until we return. We hang here until we're completely done.
  133. //
  134. // Service Start
  135. // Create the service start thread. When it is done with init, the thread will
  136. // exit. We hang on the thread, pinging the SCM with START_PENDING and watch
  137. // for the thread exit code. When we see it, we know if the start was a
  138. // success or not. If success, then hang on "stop initiated" event. If
  139. // failure, report failure to SCM and exit service main.
  140. //
  141. // Service Stop
  142. // Events that we need for stop synchronization were created during startup.
  143. // When we get notified fo "stop initiated" event, we begin pinging SCM
  144. // with "STOP_PENDING". When we get "stop complete" event, we are done and need
  145. // to exit service main. The message loop thread is still active -- we'll tell
  146. // it we're shutting down -- it will detect when the StartServiceCtrlDispatcher
  147. // thread it created exits.
  148. //+--------------------------------------------------------------------------
  149. VOID
  150. ServiceMain(
  151. IN DWORD, // dwArgc
  152. IN LPWSTR * /* lpszArgv */ )
  153. {
  154. HRESULT hr = S_OK;
  155. int iStartPendingCtr;
  156. DWORD dwThreadId, dwWaitObj;
  157. HANDLE hServiceThread = NULL;
  158. __try
  159. {
  160. g_ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  161. g_ssStatus.dwServiceSpecificExitCode = 0;
  162. g_sshStatusHandle = RegisterServiceCtrlHandler(
  163. g_wszCertSrvServiceName,
  164. serviceControlHandler);
  165. if (NULL == g_sshStatusHandle)
  166. {
  167. hr = myHLastError();
  168. _LeaveError(hr, "RegisterServiceCtrlHandler");
  169. }
  170. if (0 != g_dwDelay2)
  171. {
  172. DBGPRINT((
  173. DBG_SS_CERTSRV,
  174. "ServiceMain: sleeping %u seconds\n",
  175. g_dwDelay2));
  176. iStartPendingCtr = 0;
  177. for (;;)
  178. {
  179. ServiceReportStatusToSCMgr(
  180. SERVICE_START_PENDING,
  181. hr,
  182. iStartPendingCtr++,
  183. 2000);
  184. Sleep(1000); // sleep 1 sec
  185. if (iStartPendingCtr >= (int)g_dwDelay2)
  186. break;
  187. }
  188. }
  189. // NOTE: strange event
  190. // We're starting yet another thread, calling CertSrvStartServerThread.
  191. // Here, CertSrvStartServerThread actually blocks on server initialization
  192. hServiceThread = CreateThread(
  193. NULL,
  194. 0,
  195. CertSrvStartServerThread,
  196. 0,
  197. 0,
  198. &dwThreadId);
  199. if (NULL == hServiceThread)
  200. {
  201. hr = myHLastError();
  202. _LeaveError(hr, "CreateThread");
  203. }
  204. // don't wait on startup thread to return, report "started" but give initialization hint
  205. ServiceReportStatusToSCMgrEx(SERVICE_RUNNING, hr, 0, 0, FALSE /*fInitialized*/);
  206. // wait on the startup thread to terminate before we continue
  207. dwWaitObj = WaitForSingleObject(hServiceThread, INFINITE);
  208. if (dwWaitObj != WAIT_OBJECT_0)
  209. {
  210. hr = myHLastError();
  211. _LeaveError(hr, "WaitForSingleObject");
  212. }
  213. if (!GetExitCodeThread(hServiceThread, (DWORD *) &hr))
  214. {
  215. hr = HRESULT_FROM_WIN32(ERROR_SERVICE_NO_THREAD);
  216. _LeaveError(hr, "GetExitCodeThread");
  217. }
  218. _LeaveIfError(hr, "CertSrvStartServer"); // error during CertSrvStartServerThread gets reported here
  219. // now give trigger "we're really ready!"
  220. ServiceReportStatusToSCMgrEx(SERVICE_RUNNING, hr, 0, 0, TRUE/*fInitialized*/);
  221. /////////////////////////////////////////////////////////////
  222. // Work to be done during certsrv operation: CRL
  223. CertSrvBlockThreadUntilStop();
  224. /////////////////////////////////////////////////////////////
  225. iStartPendingCtr = 0;
  226. for (;;)
  227. {
  228. // wait for 1 sec, ping Service ctl
  229. if (WAIT_OBJECT_0 == WaitForSingleObject(g_hServiceStoppedEvent, 1000))
  230. break;
  231. ServiceReportStatusToSCMgr(
  232. SERVICE_STOP_PENDING,
  233. S_OK,
  234. iStartPendingCtr++,
  235. 2000);
  236. }
  237. DBGPRINT((DBG_SS_CERTSRV, "ServiceMain: Service reported stopped\n"));
  238. hr = S_OK;
  239. }
  240. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  241. {
  242. _PrintError(hr, "Exception");
  243. }
  244. //error:
  245. __try
  246. {
  247. ServiceReportStatusToSCMgr(SERVICE_STOPPED, hr, 0, 0);
  248. if (NULL != hServiceThread)
  249. {
  250. CloseHandle(hServiceThread);
  251. }
  252. DBGPRINT((DBG_SS_CERTSRV, "ServiceMain: Exit: %x\n", hr));
  253. // pass return code to msg loop, tell it to watch for
  254. // StartServiceCtrlDispatcher to exit
  255. if (!PostMessage(g_hwndMain, WM_SYNC_CLOSING_THREADS, 0, hr))
  256. {
  257. hr = myHLastError();
  258. _PrintIfError(hr, "PostMessage WM_SYNC_CLOSING_THREADS");
  259. }
  260. }
  261. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  262. {
  263. _PrintError(hr, "Exception");
  264. }
  265. }
  266. HRESULT
  267. ServiceQueryInteractiveFlag(
  268. OUT BOOL *pfSilent)
  269. {
  270. HRESULT hr;
  271. SC_HANDLE hSCManager = NULL;
  272. SC_HANDLE hSCCertsvc = NULL;
  273. QUERY_SERVICE_CONFIG *pServiceConfig = NULL;
  274. DWORD cb;
  275. *pfSilent = FALSE;
  276. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  277. if (NULL == hSCManager)
  278. {
  279. hr = myHLastError();
  280. _JumpError(hr, error, "OpenSCManager");
  281. }
  282. hSCCertsvc = OpenService(hSCManager, wszSERVICE_NAME, SERVICE_QUERY_CONFIG);
  283. if (NULL == hSCCertsvc)
  284. {
  285. hr = myHLastError();
  286. _JumpError(hr, error, "OpenService");
  287. }
  288. if (!QueryServiceConfig(hSCCertsvc, NULL, 0, &cb))
  289. {
  290. hr = myHLastError();
  291. if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) != hr)
  292. {
  293. _JumpError(hr, error, "QueryServiceConfig");
  294. }
  295. }
  296. pServiceConfig = (QUERY_SERVICE_CONFIG *) LocalAlloc(LMEM_FIXED, cb);
  297. if (NULL == pServiceConfig)
  298. {
  299. hr = E_OUTOFMEMORY;
  300. _JumpError(hr, error, "LocalAlloc");
  301. }
  302. if (!QueryServiceConfig(hSCCertsvc, pServiceConfig, cb, &cb))
  303. {
  304. hr = myHLastError();
  305. _JumpError(hr, error, "QueryServiceConfig");
  306. }
  307. if (0 == (SERVICE_INTERACTIVE_PROCESS & pServiceConfig->dwServiceType))
  308. {
  309. *pfSilent = TRUE;
  310. }
  311. hr = S_OK;
  312. error:
  313. if (NULL != pServiceConfig)
  314. {
  315. LocalFree(pServiceConfig);
  316. }
  317. if (NULL != hSCCertsvc)
  318. {
  319. CloseServiceHandle(hSCCertsvc);
  320. }
  321. if (NULL != hSCManager)
  322. {
  323. CloseServiceHandle(hSCManager);
  324. }
  325. return(hr);
  326. }