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.

385 lines
10 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: wiatsvc.cpp
  8. //
  9. // Contents: wait for service to start
  10. //
  11. // History: 19-Jun-00 reidk created
  12. //
  13. //--------------------------------------------------------------------------
  14. #include <windows.h>
  15. #include "unicode.h"
  16. #include "errlog.h"
  17. #include "waitsvc.h"
  18. #define WAITSVC_LOGERR_LASTERR(x) if (x) \
  19. { \
  20. ErrLog_LogError(NULL, \
  21. ERRLOG_CLIENT_ID_WAITSVC, \
  22. __LINE__, \
  23. 0, \
  24. FALSE, \
  25. FALSE); \
  26. }
  27. BOOL
  28. WaitForCryptService(
  29. IN LPWSTR pwszService,
  30. IN BOOL *pfDone,
  31. IN BOOL fLogErrors
  32. )
  33. /*++
  34. This routine determines if the protected storage service is
  35. pending start. If the service is pending start, this routine
  36. waits until the service is running before returning to the
  37. caller.
  38. If the Service is running when this routine returns, the
  39. return value is TRUE.
  40. If the service is not running, or an error occurred, the
  41. return value is FALSE.
  42. When the return value is FALSE, the value is only advisory, and may not
  43. indicate the current state of the service. The reasoning here is that
  44. if the service did not start the first time this call is made, is will
  45. not likely be running the next time around, and hence we avoid checking
  46. on subsequent calls.
  47. For current situations, the caller should ignore the return value; when
  48. the return value is FALSE, the caller should just try making the call
  49. into the service. If the service is still down, the call into it will fail
  50. appropriately.
  51. --*/
  52. {
  53. SC_HANDLE schSCM;
  54. SC_HANDLE schService = NULL;
  55. DWORD dwStopCount = 0;
  56. static BOOL fSuccess = FALSE;
  57. BOOL fCheckDisabled = TRUE;
  58. HANDLE hToken = NULL;
  59. BOOL fSystemAccount = FALSE;
  60. BOOL fStartServiceCalled = FALSE;
  61. DWORD dwErr = ERROR_SUCCESS;
  62. if( !FIsWinNT() )
  63. return TRUE;
  64. if( *pfDone )
  65. return fSuccess;
  66. schSCM = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
  67. if(schSCM == NULL)
  68. {
  69. WAITSVC_LOGERR_LASTERR(fLogErrors)
  70. return FALSE;
  71. }
  72. //
  73. // open the protected storage service so we can query it's
  74. // current state.
  75. //
  76. schService = OpenServiceW(schSCM, pwszService, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
  77. if(schService == NULL)
  78. {
  79. WAITSVC_LOGERR_LASTERR(fLogErrors)
  80. fCheckDisabled = FALSE;
  81. schService = OpenServiceW(schSCM, pwszService, SERVICE_QUERY_STATUS);
  82. }
  83. if(schService == NULL)
  84. {
  85. WAITSVC_LOGERR_LASTERR(fLogErrors)
  86. goto cleanup;
  87. }
  88. //
  89. // check if calling process is SYSTEM account.
  90. // if it is, use a larger timeout value.
  91. //
  92. if( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) ) {
  93. do {
  94. BYTE FastBuffer[ 256 ];
  95. PTOKEN_USER TokenInformation;
  96. DWORD cbTokenInformation;
  97. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  98. PSID psidLocalSystem;
  99. TokenInformation = (PTOKEN_USER)FastBuffer;
  100. cbTokenInformation = sizeof(FastBuffer);
  101. if(!GetTokenInformation(
  102. hToken,
  103. TokenUser,
  104. TokenInformation,
  105. cbTokenInformation,
  106. &cbTokenInformation
  107. ))
  108. {
  109. WAITSVC_LOGERR_LASTERR(fLogErrors)
  110. break;
  111. }
  112. if(!AllocateAndInitializeSid(
  113. &sia,
  114. 1,
  115. SECURITY_LOCAL_SYSTEM_RID,
  116. 0, 0, 0, 0, 0, 0, 0,
  117. &psidLocalSystem
  118. ))
  119. {
  120. WAITSVC_LOGERR_LASTERR(fLogErrors)
  121. break;
  122. }
  123. fSystemAccount = EqualSid(
  124. psidLocalSystem,
  125. TokenInformation->User.Sid
  126. );
  127. FreeSid( psidLocalSystem );
  128. } while (FALSE);
  129. CloseHandle( hToken );
  130. }
  131. //
  132. // number of seconds to Sleep per loop interation.
  133. //
  134. #define SLEEP_SECONDS (5)
  135. if( fSystemAccount ) {
  136. //
  137. // 15 minutes for SYSTEM account.
  138. //
  139. dwStopCount = 900 / SLEEP_SECONDS;
  140. } else {
  141. //
  142. //
  143. // loop checking the service status every 5 seconds, for up to 2 minutes
  144. // total (120 seconds, 5*24=120)
  145. //
  146. dwStopCount = 120 / SLEEP_SECONDS;
  147. }
  148. for( ; dwStopCount != 0 ; dwStopCount--, Sleep(SLEEP_SECONDS*1000) ) {
  149. SERVICE_STATUS sServiceStatus;
  150. DWORD dwWaitForStatus = 0;
  151. //
  152. // check if the service is disabled. If it is, bailout.
  153. //
  154. if( fCheckDisabled ) {
  155. LPQUERY_SERVICE_CONFIG pServiceConfig;
  156. BYTE TempBuffer[ 1024 ];
  157. DWORD cbServiceConfig;
  158. pServiceConfig = (LPQUERY_SERVICE_CONFIG)TempBuffer;
  159. cbServiceConfig = sizeof(TempBuffer);
  160. if(QueryServiceConfig( schService, pServiceConfig, cbServiceConfig, &cbServiceConfig )) {
  161. if( pServiceConfig->dwStartType == SERVICE_DISABLED )
  162. {
  163. WAITSVC_LOGERR_LASTERR(fLogErrors)
  164. goto cleanup;
  165. }
  166. }
  167. }
  168. //
  169. // find out current service status
  170. //
  171. if(!QueryServiceStatus( schService, &sServiceStatus ))
  172. {
  173. WAITSVC_LOGERR_LASTERR(fLogErrors)
  174. break;
  175. }
  176. //
  177. // if service is running, indicate success
  178. //
  179. if( sServiceStatus.dwCurrentState == SERVICE_RUNNING ) {
  180. if (fStartServiceCalled)
  181. {
  182. ErrLog_LogString(
  183. NULL,
  184. L"WAITSVC: Service is running: ",
  185. pwszService,
  186. TRUE);
  187. }
  188. fSuccess = TRUE;
  189. break;
  190. }
  191. if( sServiceStatus.dwCurrentState == SERVICE_STOP_PENDING )
  192. {
  193. WAITSVC_LOGERR_LASTERR(fLogErrors)
  194. // Wait until stopped
  195. continue;
  196. }
  197. if( sServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING )
  198. {
  199. WAITSVC_LOGERR_LASTERR(fLogErrors)
  200. // Wait until paused
  201. continue;
  202. }
  203. //
  204. // if start pending, wait and re-query.
  205. //
  206. if( sServiceStatus.dwCurrentState == SERVICE_START_PENDING )
  207. {
  208. // Wait until started
  209. continue;
  210. }
  211. if(SERVICE_STOPPED == sServiceStatus.dwCurrentState)
  212. {
  213. // Attempt to start the service
  214. SC_HANDLE schManualStartService = NULL;
  215. DWORD dwError = ERROR_SUCCESS;
  216. // The service is manual start
  217. // so attempt to start it.
  218. schManualStartService = OpenServiceW(schSCM,
  219. pwszService,
  220. SERVICE_START);
  221. if(NULL == schManualStartService)
  222. {
  223. WAITSVC_LOGERR_LASTERR(fLogErrors)
  224. goto cleanup;
  225. }
  226. ErrLog_LogString(
  227. NULL,
  228. L"WAITSVC: Calling StartService(): ",
  229. pwszService,
  230. TRUE);
  231. fStartServiceCalled = TRUE;
  232. if(!StartService(schManualStartService, 0, NULL))
  233. {
  234. dwError = GetLastError();
  235. }
  236. if(ERROR_SERVICE_ALREADY_RUNNING == dwError)
  237. {
  238. dwError = ERROR_SUCCESS;
  239. }
  240. CloseServiceHandle(schManualStartService);
  241. if(ERROR_SUCCESS != dwError)
  242. {
  243. SetLastError(dwError);
  244. WAITSVC_LOGERR_LASTERR(fLogErrors)
  245. goto cleanup;
  246. }
  247. continue;
  248. }
  249. if(SERVICE_PAUSED == sServiceStatus.dwCurrentState)
  250. {
  251. // Attempt to start the service
  252. SC_HANDLE schManualStartService = NULL;
  253. DWORD dwError = ERROR_SUCCESS;
  254. // The service is manual start
  255. // so attempt to start it.
  256. schManualStartService = OpenServiceW(schSCM,
  257. pwszService,
  258. SERVICE_PAUSE_CONTINUE);
  259. if(NULL == schManualStartService)
  260. {
  261. WAITSVC_LOGERR_LASTERR(fLogErrors)
  262. goto cleanup;
  263. }
  264. if(!ControlService(schManualStartService, SERVICE_CONTROL_CONTINUE, &sServiceStatus))
  265. {
  266. dwError = GetLastError();
  267. }
  268. if(ERROR_SERVICE_ALREADY_RUNNING == dwError)
  269. {
  270. dwError = ERROR_SUCCESS;
  271. }
  272. CloseServiceHandle(schManualStartService);
  273. if(ERROR_SUCCESS != dwError)
  274. {
  275. SetLastError(dwError);
  276. WAITSVC_LOGERR_LASTERR(fLogErrors)
  277. goto cleanup;
  278. }
  279. continue;
  280. }
  281. //
  282. // bail out on any other dwCurrentState
  283. // eg: service stopped, error condition, etc.
  284. //
  285. break;
  286. }
  287. *pfDone = TRUE;
  288. cleanup:
  289. dwErr = GetLastError();
  290. if(schService)
  291. CloseServiceHandle(schService);
  292. CloseServiceHandle(schSCM);
  293. SetLastError(dwErr);
  294. return fSuccess;
  295. }