xref: /reactos/base/system/services/services.c (revision 1734f297)
1 /*
2  * PROJECT:     ReactOS Service Control Manager
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        base/system/services/services.c
5  * PURPOSE:     Main SCM controller
6  * COPYRIGHT:   Copyright 2001-2005 Eric Kohl
7  *              Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
8  *
9  */
10 
11 /* INCLUDES *****************************************************************/
12 
13 #include "services.h"
14 
15 #include <wincon.h>
16 
17 #define NDEBUG
18 #include <debug.h>
19 
20 int WINAPI RegisterServicesProcess(DWORD ServicesProcessId);
21 
22 /* GLOBALS ******************************************************************/
23 
24 /* Defined in include/reactos/services/services.h */
25 // #define SCM_START_EVENT             L"SvcctrlStartEvent_A3752DX"
26 #define SCM_AUTOSTARTCOMPLETE_EVENT L"SC_AutoStartComplete"
27 
28 BOOL ScmInitialize = FALSE;
29 BOOL ScmShutdown = FALSE;
30 BOOL ScmLiveSetup = FALSE;
31 BOOL ScmSetupInProgress = FALSE;
32 static HANDLE hScmShutdownEvent = NULL;
33 static HANDLE hScmSecurityServicesEvent = NULL;
34 
35 
36 /* FUNCTIONS *****************************************************************/
37 
38 VOID
39 PrintString(LPCSTR fmt, ...)
40 {
41 #if DBG
42     CHAR buffer[512];
43     va_list ap;
44 
45     va_start(ap, fmt);
46     vsprintf(buffer, fmt, ap);
47     va_end(ap);
48 
49     OutputDebugStringA(buffer);
50 #endif
51 }
52 
53 DWORD
54 CheckForLiveCD(VOID)
55 {
56     WCHAR CommandLine[MAX_PATH];
57     HKEY hSetupKey;
58     DWORD dwSetupType;
59     DWORD dwSetupInProgress;
60     DWORD dwType;
61     DWORD dwSize;
62     DWORD dwError;
63 
64     DPRINT1("CheckSetup()\n");
65 
66     /* Open the Setup key */
67     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
68                             L"SYSTEM\\Setup",
69                             0,
70                             KEY_QUERY_VALUE,
71                             &hSetupKey);
72     if (dwError != ERROR_SUCCESS)
73         return dwError;
74 
75     /* Read the SetupType value */
76     dwSize = sizeof(DWORD);
77     dwError = RegQueryValueExW(hSetupKey,
78                                L"SetupType",
79                                NULL,
80                                &dwType,
81                                (LPBYTE)&dwSetupType,
82                                &dwSize);
83 
84     if (dwError != ERROR_SUCCESS ||
85         dwType != REG_DWORD ||
86         dwSize != sizeof(DWORD) ||
87         dwSetupType == 0)
88         goto done;
89 
90     /* Read the CmdLine value */
91     dwSize = sizeof(CommandLine);
92     dwError = RegQueryValueExW(hSetupKey,
93                                L"CmdLine",
94                                NULL,
95                                &dwType,
96                                (LPBYTE)CommandLine,
97                                &dwSize);
98 
99     if (dwError != ERROR_SUCCESS ||
100         (dwType != REG_SZ &&
101          dwType != REG_EXPAND_SZ &&
102          dwType != REG_MULTI_SZ))
103         goto done;
104 
105     /* Check for the '-mini' option */
106     if (wcsstr(CommandLine, L" -mini") != NULL)
107     {
108         DPRINT1("Running on LiveCD\n");
109         ScmLiveSetup = TRUE;
110     }
111 
112     /* Read the SystemSetupInProgress value */
113     dwSize = sizeof(DWORD);
114     dwError = RegQueryValueExW(hSetupKey,
115                                L"SystemSetupInProgress",
116                                NULL,
117                                &dwType,
118                                (LPBYTE)&dwSetupInProgress,
119                                &dwSize);
120     if (dwError != ERROR_SUCCESS ||
121         dwType != REG_DWORD ||
122         dwSize != sizeof(DWORD) ||
123         dwSetupType == 0)
124     {
125         goto done;
126     }
127 
128     if (dwSetupInProgress == 1)
129     {
130         DPRINT1("ReactOS Setup currently in progress!\n");
131         ScmSetupInProgress = TRUE;
132     }
133 
134 done:
135     RegCloseKey(hSetupKey);
136 
137     return dwError;
138 }
139 
140 
141 DWORD
142 SetSecurityServicesEvent(VOID)
143 {
144     DWORD dwError;
145 
146     if (hScmSecurityServicesEvent != NULL)
147         return ERROR_SUCCESS;
148 
149     /* Create or open the SECURITY_SERVICES_STARTED event */
150     hScmSecurityServicesEvent = CreateEventW(NULL,
151                                              TRUE,
152                                              FALSE,
153                                              L"SECURITY_SERVICES_STARTED");
154     if (hScmSecurityServicesEvent == NULL)
155     {
156         dwError = GetLastError();
157         if (dwError != ERROR_ALREADY_EXISTS)
158             return dwError;
159 
160         hScmSecurityServicesEvent = OpenEventW(EVENT_MODIFY_STATE,
161                                                FALSE,
162                                                L"SECURITY_SERVICES_STARTED");
163         if (hScmSecurityServicesEvent == NULL)
164             return GetLastError();
165     }
166 
167     SetEvent(hScmSecurityServicesEvent);
168 
169     return ERROR_SUCCESS;
170 }
171 
172 
173 VOID
174 ScmLogEvent(DWORD dwEventId,
175             WORD wType,
176             WORD wStrings,
177             LPCWSTR *lpStrings)
178 {
179     HANDLE hLog;
180 
181     hLog = RegisterEventSourceW(NULL,
182                                 L"Service Control Manager");
183     if (hLog == NULL)
184     {
185         DPRINT1("ScmLogEvent: RegisterEventSourceW failed %lu\n", GetLastError());
186         return;
187     }
188 
189     if (!ReportEventW(hLog,
190                       wType,
191                       0,
192                       dwEventId,
193                       NULL,
194                       wStrings,
195                       0,
196                       lpStrings,
197                       NULL))
198     {
199         DPRINT1("ScmLogEvent: ReportEventW failed %lu\n", GetLastError());
200     }
201 
202     DeregisterEventSource(hLog);
203 }
204 
205 
206 VOID
207 ScmWaitForLsa(VOID)
208 {
209     HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, L"LSA_RPC_SERVER_ACTIVE");
210     if (hEvent == NULL)
211     {
212         DPRINT1("Failed to create or open the notification event (Error %lu)\n", GetLastError());
213     }
214     else
215     {
216         DPRINT("Wait for the LSA server\n");
217         WaitForSingleObject(hEvent, INFINITE);
218         DPRINT("LSA server running\n");
219         CloseHandle(hEvent);
220     }
221 
222     DPRINT("ScmWaitForLsa() done\n");
223 }
224 
225 
226 BOOL WINAPI
227 ShutdownHandlerRoutine(DWORD dwCtrlType)
228 {
229     DPRINT1("ShutdownHandlerRoutine() called\n");
230 
231     if (dwCtrlType & (CTRL_SHUTDOWN_EVENT | CTRL_LOGOFF_EVENT))
232     {
233         DPRINT1("Shutdown event received\n");
234         ScmShutdown = TRUE;
235 
236         ScmAutoShutdownServices();
237         ScmShutdownServiceDatabase();
238 
239         /* Set the shutdown event */
240         SetEvent(hScmShutdownEvent);
241     }
242 
243     return TRUE;
244 }
245 
246 
247 int WINAPI
248 wWinMain(HINSTANCE hInstance,
249          HINSTANCE hPrevInstance,
250          LPWSTR lpCmdLine,
251          int nShowCmd)
252 {
253     HANDLE hScmStartEvent = NULL;
254     HANDLE hScmAutoStartCompleteEvent = NULL;
255     SC_RPC_LOCK Lock = NULL;
256     BOOL bCanDeleteNamedPipeCriticalSection = FALSE;
257     DWORD dwError;
258 
259     DPRINT("SERVICES: Service Control Manager\n");
260 
261     dwError = CheckForLiveCD();
262     if (dwError != ERROR_SUCCESS)
263     {
264         DPRINT1("SERVICES: Failed to check for LiveCD (Error %lu)\n", dwError);
265         goto done;
266     }
267 
268     /* Make us critical */
269     RtlSetProcessIsCritical(TRUE, NULL, TRUE);
270 
271     /* We are initializing ourselves */
272     ScmInitialize = TRUE;
273 
274     /* Create the start event */
275     hScmStartEvent = CreateEventW(NULL, TRUE, FALSE, SCM_START_EVENT);
276     if (hScmStartEvent == NULL)
277     {
278         DPRINT1("SERVICES: Failed to create the start event\n");
279         goto done;
280     }
281     DPRINT("SERVICES: Created start event with handle %p\n", hScmStartEvent);
282 
283     /* Create the auto-start complete event */
284     hScmAutoStartCompleteEvent = CreateEventW(NULL, TRUE, FALSE, SCM_AUTOSTARTCOMPLETE_EVENT);
285     if (hScmAutoStartCompleteEvent == NULL)
286     {
287         DPRINT1("SERVICES: Failed to create the auto-start complete event\n");
288         goto done;
289     }
290     DPRINT("SERVICES: created auto-start complete event with handle %p\n", hScmAutoStartCompleteEvent);
291 
292     /* Create the shutdown event */
293     hScmShutdownEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
294     if (hScmShutdownEvent == NULL)
295     {
296         DPRINT1("SERVICES: Failed to create the shutdown event\n");
297         goto done;
298     }
299 
300     /* Initialize our communication named pipe's critical section */
301     ScmInitNamedPipeCriticalSection();
302     bCanDeleteNamedPipeCriticalSection = TRUE;
303 
304 //    ScmInitThreadManager();
305 
306     ScmInitializeSecurity();
307 
308     /* FIXME: more initialization */
309 
310     /* Create the 'Last Known Good' control set */
311     dwError = ScmCreateLastKnownGoodControlSet();
312     if (dwError != ERROR_SUCCESS)
313     {
314         DPRINT1("SERVICES: Failed to create the 'Last Known Good' control set (Error %lu)\n", dwError);
315         goto done;
316     }
317 
318     /* Create the services database */
319     dwError = ScmCreateServiceDatabase();
320     if (dwError != ERROR_SUCCESS)
321     {
322         DPRINT1("SERVICES: Failed to create SCM database (Error %lu)\n", dwError);
323         goto done;
324     }
325 
326     /* Update the services database */
327     ScmGetBootAndSystemDriverState();
328 
329     /* Register the Service Control Manager process with the ReactOS Subsystem */
330     if (!RegisterServicesProcess(GetCurrentProcessId()))
331     {
332         DPRINT1("SERVICES: Could not register SCM process\n");
333         goto done;
334     }
335 
336     /*
337      * Acquire the user service start lock until
338      * auto-start services have been started.
339      */
340     dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
341     if (dwError != ERROR_SUCCESS)
342     {
343         DPRINT1("SERVICES: Failed to acquire service start lock (Error %lu)\n", dwError);
344         goto done;
345     }
346 
347     /* Start the RPC server */
348     ScmStartRpcServer();
349 
350     /* Signal start event */
351     SetEvent(hScmStartEvent);
352 
353     DPRINT("SERVICES: Initialized\n");
354 
355     /* Register event handler (used for system shutdown) */
356     SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
357 
358     /*
359      * Set our shutdown parameters: we want to shutdown after the maintained
360      * services (that inherit the default shutdown level of 640).
361      */
362     SetProcessShutdownParameters(480, SHUTDOWN_NORETRY);
363 
364     /* Start auto-start services */
365     ScmAutoStartServices();
366 
367     /* Signal auto-start complete event */
368     SetEvent(hScmAutoStartCompleteEvent);
369 
370     /* FIXME: more to do ? */
371 
372     /* Release the service start lock */
373     ScmReleaseServiceStartLock(&Lock);
374 
375     /* Initialization finished */
376     ScmInitialize = FALSE;
377 
378     DPRINT("SERVICES: Running\n");
379 
380     /* Wait until the shutdown event gets signaled */
381     WaitForSingleObject(hScmShutdownEvent, INFINITE);
382 
383 done:
384     ScmShutdownSecurity();
385 
386     /* Delete our communication named pipe's critical section */
387     if (bCanDeleteNamedPipeCriticalSection != FALSE)
388         ScmDeleteNamedPipeCriticalSection();
389 
390     if (hScmSecurityServicesEvent != NULL)
391         CloseHandle(hScmSecurityServicesEvent);
392 
393     /* Close the shutdown event */
394     if (hScmShutdownEvent != NULL)
395         CloseHandle(hScmShutdownEvent);
396 
397     /* Close the auto-start complete event */
398     if (hScmAutoStartCompleteEvent != NULL)
399         CloseHandle(hScmAutoStartCompleteEvent);
400 
401     /* Close the start event */
402     if (hScmStartEvent != NULL)
403         CloseHandle(hScmStartEvent);
404 
405     DPRINT("SERVICES: Finished\n");
406 
407     ExitThread(0);
408     return 0;
409 }
410 
411 /* EOF */
412