Wait for the SCM to be fully initialized before calling allowing a call to OpenSCManager
[reactos.git] / reactos / base / system / services / services.c
1 /*
2 * service control manager
3 *
4 * ReactOS Operating System
5 *
6 * --------------------------------------------------------------------
7 *
8 * This software is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This software is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this software; see the file COPYING.LIB. If not, write
20 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
21 * MA 02139, USA.
22 *
23 */
24
25 /* NOTE:
26 * - Services.exe is NOT a native application, it is a GUI app.
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include "services.h"
32
33 #define NDEBUG
34 #include <debug.h>
35
36 int WINAPI RegisterServicesProcess(DWORD ServicesProcessId);
37
38 /* GLOBALS ******************************************************************/
39
40 #define PIPE_BUFSIZE 1024
41 #define PIPE_TIMEOUT 1000
42
43 BOOL ScmShutdown = FALSE;
44
45
46 /* FUNCTIONS *****************************************************************/
47
48 VOID
49 PrintString(LPCSTR fmt, ...)
50 {
51 #ifdef DBG
52 CHAR buffer[512];
53 va_list ap;
54
55 va_start(ap, fmt);
56 vsprintf(buffer, fmt, ap);
57 va_end(ap);
58
59 OutputDebugStringA(buffer);
60 #endif
61 }
62
63
64 BOOL
65 ScmCreateStartEvent(PHANDLE StartEvent)
66 {
67 HANDLE hEvent;
68
69 hEvent = CreateEvent(NULL,
70 TRUE,
71 FALSE,
72 TEXT("SvcctrlStartEvent_A3752DX"));
73 if (hEvent == NULL)
74 {
75 if (GetLastError() == ERROR_ALREADY_EXISTS)
76 {
77 hEvent = OpenEvent(EVENT_ALL_ACCESS,
78 FALSE,
79 TEXT("SvcctrlStartEvent_A3752DX"));
80 if (hEvent == NULL)
81 {
82 return FALSE;
83 }
84 }
85 else
86 {
87 return FALSE;
88 }
89 }
90
91 *StartEvent = hEvent;
92
93 return TRUE;
94 }
95
96
97 BOOL ScmWaitForEvent()
98 {
99 HANDLE hEvent;
100
101 hEvent = OpenEvent(EVENT_ALL_ACCESS,
102 FALSE,
103 TEXT("SvcctrlStartEvent_A3752DX"));
104
105 if (hEvent)
106 {
107 DWORD ret = WaitForSingleObject(hEvent,
108 INFINITE);
109
110 if (ret == WAIT_OBJECT_0)
111 return TRUE;
112 }
113
114 return FALSE;
115 }
116
117
118 BOOL
119 ScmNamedPipeHandleRequest(PVOID Request,
120 DWORD RequestSize,
121 PVOID Reply,
122 LPDWORD ReplySize)
123 {
124 DbgPrint("SCM READ: %s\n", Request);
125
126 *ReplySize = 0;
127 return FALSE;
128 }
129
130
131 DWORD WINAPI
132 ScmNamedPipeThread(LPVOID Context)
133 {
134 CHAR chRequest[PIPE_BUFSIZE];
135 CHAR chReply[PIPE_BUFSIZE];
136 DWORD cbReplyBytes;
137 DWORD cbBytesRead;
138 DWORD cbWritten;
139 BOOL bSuccess;
140 HANDLE hPipe;
141
142 hPipe = (HANDLE)Context;
143
144 DPRINT("ScmNamedPipeThread(%x) - Accepting SCM commands through named pipe\n", hPipe);
145
146 for (;;)
147 {
148 bSuccess = ReadFile(hPipe,
149 &chRequest,
150 PIPE_BUFSIZE,
151 &cbBytesRead,
152 NULL);
153 if (!bSuccess || cbBytesRead == 0)
154 {
155 break;
156 }
157
158 if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes))
159 {
160 bSuccess = WriteFile(hPipe,
161 &chReply,
162 cbReplyBytes,
163 &cbWritten,
164 NULL);
165 if (!bSuccess || cbReplyBytes != cbWritten)
166 {
167 break;
168 }
169 }
170 }
171
172 DPRINT("ScmNamedPipeThread(%x) - Disconnecting named pipe connection\n", hPipe);
173
174 FlushFileBuffers(hPipe);
175 DisconnectNamedPipe(hPipe);
176 CloseHandle(hPipe);
177
178 DPRINT("ScmNamedPipeThread(%x) - Done.\n", hPipe);
179
180 return ERROR_SUCCESS;
181 }
182
183
184 BOOL
185 ScmCreateNamedPipe(VOID)
186 {
187 DWORD dwThreadId;
188 BOOL bConnected;
189 HANDLE hThread;
190 HANDLE hPipe;
191
192 DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
193
194 hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Ntsvcs"),
195 PIPE_ACCESS_DUPLEX,
196 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
197 PIPE_UNLIMITED_INSTANCES,
198 PIPE_BUFSIZE,
199 PIPE_BUFSIZE,
200 PIPE_TIMEOUT,
201 NULL);
202 if (hPipe == INVALID_HANDLE_VALUE)
203 {
204 DPRINT("CreateNamedPipe() failed (%d)\n", GetLastError());
205 return FALSE;
206 }
207
208 DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%x)\n", hPipe);
209 bConnected = ConnectNamedPipe(hPipe,
210 NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
211 DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", bConnected);
212
213 if (bConnected)
214 {
215 DPRINT("Pipe connected\n");
216 hThread = CreateThread(NULL,
217 0,
218 ScmNamedPipeThread,
219 (LPVOID)hPipe,
220 0,
221 &dwThreadId);
222 if (!hThread)
223 {
224 DPRINT("Could not create thread (%d)\n", GetLastError());
225 DisconnectNamedPipe(hPipe);
226 CloseHandle(hPipe);
227 DPRINT("CreateNamedPipe() - returning FALSE\n");
228 return FALSE;
229 }
230 }
231 else
232 {
233 DPRINT("Pipe not connected\n");
234 CloseHandle(hPipe);
235 DPRINT("CreateNamedPipe() - returning FALSE\n");
236 return FALSE;
237 }
238 DPRINT("CreateNamedPipe() - returning TRUE\n");
239 return TRUE;
240 }
241
242
243 DWORD WINAPI
244 ScmNamedPipeListenerThread(LPVOID Context)
245 {
246 // HANDLE hPipe;
247 DPRINT("ScmNamedPipeListenerThread(%x) - aka SCM.\n", Context);
248
249 // hPipe = (HANDLE)Context;
250 for (;;)
251 {
252 DPRINT("SCM: Waiting for new connection on named pipe...\n");
253 /* Create named pipe */
254 if (!ScmCreateNamedPipe())
255 {
256 DPRINT1("\nSCM: Failed to create named pipe\n");
257 break;
258 //ExitThread(0);
259 }
260 DPRINT("\nSCM: named pipe session created.\n");
261 Sleep(10);
262 }
263 DPRINT("\n\nWARNING: ScmNamedPipeListenerThread(%x) - Aborted.\n\n", Context);
264 return ERROR_SUCCESS;
265 }
266
267
268 BOOL
269 StartScmNamedPipeThreadListener(VOID)
270 {
271 DWORD dwThreadId;
272 HANDLE hThread;
273
274 hThread = CreateThread(NULL,
275 0,
276 ScmNamedPipeListenerThread,
277 NULL, /*(LPVOID)hPipe,*/
278 0,
279 &dwThreadId);
280 if (!hThread)
281 {
282 DPRINT1("SERVICES: Could not create thread (Status %lx)\n", GetLastError());
283 return FALSE;
284 }
285
286 return TRUE;
287 }
288
289
290 VOID FASTCALL
291 AcquireLoadDriverPrivilege(VOID)
292 {
293 HANDLE hToken;
294 TOKEN_PRIVILEGES tkp;
295
296 /* Get a token for this process */
297 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
298 {
299 /* Get the LUID for the debug privilege */
300 LookupPrivilegeValue(NULL, SE_LOAD_DRIVER_NAME, &tkp.Privileges[0].Luid);
301
302 /* One privilege to set */
303 tkp.PrivilegeCount = 1;
304 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
305
306 /* Get the debug privilege for this process */
307 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
308 }
309 }
310
311
312 BOOL WINAPI
313 ShutdownHandlerRoutine(DWORD dwCtrlType)
314 {
315 DPRINT1("ShutdownHandlerRoutine() called\n");
316
317 if (dwCtrlType == CTRL_SHUTDOWN_EVENT)
318 {
319 DPRINT1("Shutdown event received!\n");
320 ScmShutdown = TRUE;
321
322 /* FIXME: Shut all services down */
323 }
324
325 return TRUE;
326 }
327
328
329 int STDCALL
330 WinMain(HINSTANCE hInstance,
331 HINSTANCE hPrevInstance,
332 LPSTR lpCmdLine,
333 int nShowCmd)
334 {
335 HANDLE hScmStartEvent;
336 HANDLE hEvent;
337 DWORD dwError;
338
339 DPRINT("SERVICES: Service Control Manager\n");
340
341 /* Acquire privileges to load drivers */
342 AcquireLoadDriverPrivilege();
343
344 /* Create start event */
345 if (!ScmCreateStartEvent(&hScmStartEvent))
346 {
347 DPRINT1("SERVICES: Failed to create start event\n");
348 ExitThread(0);
349 }
350
351 DPRINT("SERVICES: created start event with handle %x.\n", hScmStartEvent);
352
353 // ScmInitThreadManager();
354
355 /* FIXME: more initialization */
356
357
358 /* Create the service database */
359 dwError = ScmCreateServiceDatabase();
360 if (dwError != ERROR_SUCCESS)
361 {
362 DPRINT1("SERVICES: failed to create SCM database (Error %lu)\n", dwError);
363 ExitThread(0);
364 }
365
366 /* Update service database */
367 ScmGetBootAndSystemDriverState();
368
369 /* Start the RPC server */
370 ScmStartRpcServer();
371
372 /* Register service process with CSRSS */
373 RegisterServicesProcess(GetCurrentProcessId());
374
375 DPRINT("SERVICES: Initialized.\n");
376
377 /* Signal start event */
378 SetEvent(hScmStartEvent);
379
380 /* Register event handler (used for system shutdown) */
381 SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
382
383 /* Start auto-start services */
384 ScmAutoStartServices();
385
386 /* FIXME: more to do ? */
387
388
389 DPRINT("SERVICES: Running.\n");
390
391 #if 1
392 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
393 if (hEvent)
394 WaitForSingleObject(hEvent, INFINITE);
395 #else
396 for (;;)
397 {
398 NtYieldExecution();
399 }
400 #endif
401
402 DPRINT("SERVICES: Finished.\n");
403
404 ExitThread(0);
405
406 return 0;
407 }
408
409 /* EOF */