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