[SERVICES]
[reactos.git] / reactos / base / system / services / services.c
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 /* NOTE:
12 * - Services.exe is NOT a native application, it is a GUI app.
13 */
14
15 /* INCLUDES *****************************************************************/
16
17 #include "services.h"
18
19 #define NDEBUG
20 #include <debug.h>
21
22 int WINAPI RegisterServicesProcess(DWORD ServicesProcessId);
23
24 /* GLOBALS ******************************************************************/
25
26 #define PIPE_BUFSIZE 1024
27 #define PIPE_TIMEOUT 1000
28
29 BOOL ScmShutdown = FALSE;
30 static HANDLE hScmShutdownEvent = NULL;
31
32
33 /* FUNCTIONS *****************************************************************/
34
35 VOID
36 PrintString(LPCSTR fmt, ...)
37 {
38 #if DBG
39 CHAR buffer[512];
40 va_list ap;
41
42 va_start(ap, fmt);
43 vsprintf(buffer, fmt, ap);
44 va_end(ap);
45
46 OutputDebugStringA(buffer);
47 #endif
48 }
49
50
51 VOID
52 ScmLogError(DWORD dwEventId,
53 WORD wStrings,
54 LPCWSTR *lpStrings)
55 {
56 HANDLE hLog;
57
58 hLog = RegisterEventSourceW(NULL,
59 L"Service Control Manager");
60 if (hLog == NULL)
61 {
62 DPRINT1("ScmLogEvent: RegisterEventSourceW failed %d\n", GetLastError());
63 return;
64 }
65
66 if (!ReportEventW(hLog,
67 EVENTLOG_ERROR_TYPE,
68 0,
69 dwEventId,
70 NULL, // Sid,
71 wStrings,
72 0,
73 lpStrings,
74 NULL))
75 {
76 DPRINT1("ScmLogEvent: ReportEventW failed %d\n", GetLastError());
77 }
78
79 DeregisterEventSource(hLog);
80 }
81
82
83 BOOL
84 ScmCreateStartEvent(PHANDLE StartEvent)
85 {
86 HANDLE hEvent;
87
88 hEvent = CreateEventW(NULL,
89 TRUE,
90 FALSE,
91 L"SvcctrlStartEvent_A3752DX");
92 if (hEvent == NULL)
93 {
94 if (GetLastError() == ERROR_ALREADY_EXISTS)
95 {
96 hEvent = OpenEventW(EVENT_ALL_ACCESS,
97 FALSE,
98 L"SvcctrlStartEvent_A3752DX");
99 if (hEvent == NULL)
100 {
101 return FALSE;
102 }
103 }
104 else
105 {
106 return FALSE;
107 }
108 }
109
110 *StartEvent = hEvent;
111
112 return TRUE;
113 }
114
115
116 VOID
117 ScmWaitForLsa(VOID)
118 {
119 HANDLE hEvent;
120 DWORD dwError;
121
122 hEvent = CreateEventW(NULL,
123 TRUE,
124 FALSE,
125 L"LSA_RPC_SERVER_ACTIVE");
126 if (hEvent == NULL)
127 {
128 dwError = GetLastError();
129 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError);
130
131 if (dwError == ERROR_ALREADY_EXISTS)
132 {
133 hEvent = OpenEventW(SYNCHRONIZE,
134 FALSE,
135 L"LSA_RPC_SERVER_ACTIVE");
136 if (hEvent == NULL)
137 {
138 DPRINT1("Could not open the notification event (Error %lu)\n", GetLastError());
139 return;
140 }
141 }
142 }
143
144 DPRINT("Wait for the LSA server!\n");
145 WaitForSingleObject(hEvent, INFINITE);
146 DPRINT("LSA server running!\n");
147
148 CloseHandle(hEvent);
149
150 DPRINT("ScmWaitForLsa() done\n");
151 }
152
153
154 BOOL
155 ScmNamedPipeHandleRequest(PVOID Request,
156 DWORD RequestSize,
157 PVOID Reply,
158 LPDWORD ReplySize)
159 {
160 DbgPrint("SCM READ: %s\n", Request);
161
162 *ReplySize = 0;
163 return FALSE;
164 }
165
166
167 DWORD WINAPI
168 ScmNamedPipeThread(LPVOID Context)
169 {
170 CHAR chRequest[PIPE_BUFSIZE];
171 CHAR chReply[PIPE_BUFSIZE];
172 DWORD cbReplyBytes;
173 DWORD cbBytesRead;
174 DWORD cbWritten;
175 BOOL bSuccess;
176 HANDLE hPipe;
177
178 hPipe = (HANDLE)Context;
179
180 DPRINT("ScmNamedPipeThread(%x) - Accepting SCM commands through named pipe\n", hPipe);
181
182 for (;;)
183 {
184 bSuccess = ReadFile(hPipe,
185 &chRequest,
186 PIPE_BUFSIZE,
187 &cbBytesRead,
188 NULL);
189 if (!bSuccess || cbBytesRead == 0)
190 {
191 break;
192 }
193
194 if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes))
195 {
196 bSuccess = WriteFile(hPipe,
197 &chReply,
198 cbReplyBytes,
199 &cbWritten,
200 NULL);
201 if (!bSuccess || cbReplyBytes != cbWritten)
202 {
203 break;
204 }
205 }
206 }
207
208 DPRINT("ScmNamedPipeThread(%x) - Disconnecting named pipe connection\n", hPipe);
209
210 FlushFileBuffers(hPipe);
211 DisconnectNamedPipe(hPipe);
212 CloseHandle(hPipe);
213
214 DPRINT("ScmNamedPipeThread(%x) - Done.\n", hPipe);
215
216 return ERROR_SUCCESS;
217 }
218
219
220 BOOL
221 ScmCreateNamedPipe(VOID)
222 {
223 DWORD dwThreadId;
224 BOOL bConnected;
225 HANDLE hThread;
226 HANDLE hPipe;
227
228 DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
229
230 hPipe = CreateNamedPipeW(L"\\\\.\\pipe\\Ntsvcs",
231 PIPE_ACCESS_DUPLEX,
232 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
233 PIPE_UNLIMITED_INSTANCES,
234 PIPE_BUFSIZE,
235 PIPE_BUFSIZE,
236 PIPE_TIMEOUT,
237 NULL);
238 if (hPipe == INVALID_HANDLE_VALUE)
239 {
240 DPRINT("CreateNamedPipe() failed (%d)\n", GetLastError());
241 return FALSE;
242 }
243
244 DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%x)\n", hPipe);
245 bConnected = ConnectNamedPipe(hPipe,
246 NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
247 DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", bConnected);
248
249 if (bConnected)
250 {
251 DPRINT("Pipe connected\n");
252 hThread = CreateThread(NULL,
253 0,
254 ScmNamedPipeThread,
255 (LPVOID)hPipe,
256 0,
257 &dwThreadId);
258 if (!hThread)
259 {
260 DPRINT("Could not create thread (%d)\n", GetLastError());
261 DisconnectNamedPipe(hPipe);
262 CloseHandle(hPipe);
263 DPRINT("CreateNamedPipe() - returning FALSE\n");
264 return FALSE;
265 }
266
267 CloseHandle(hThread);
268 }
269 else
270 {
271 DPRINT("Pipe not connected\n");
272 CloseHandle(hPipe);
273 DPRINT("CreateNamedPipe() - returning FALSE\n");
274 return FALSE;
275 }
276 DPRINT("CreateNamedPipe() - returning TRUE\n");
277 return TRUE;
278 }
279
280
281 DWORD WINAPI
282 ScmNamedPipeListenerThread(LPVOID Context)
283 {
284 // HANDLE hPipe;
285 DPRINT("ScmNamedPipeListenerThread(%x) - aka SCM.\n", Context);
286
287 // hPipe = (HANDLE)Context;
288 for (;;)
289 {
290 DPRINT("SCM: Waiting for new connection on named pipe...\n");
291 /* Create named pipe */
292 if (!ScmCreateNamedPipe())
293 {
294 DPRINT1("\nSCM: Failed to create named pipe\n");
295 break;
296 //ExitThread(0);
297 }
298 DPRINT("\nSCM: named pipe session created.\n");
299 Sleep(10);
300 }
301 DPRINT("\n\nWARNING: ScmNamedPipeListenerThread(%x) - Aborted.\n\n", Context);
302 return ERROR_SUCCESS;
303 }
304
305
306 BOOL
307 StartScmNamedPipeThreadListener(VOID)
308 {
309 DWORD dwThreadId;
310 HANDLE hThread;
311
312 hThread = CreateThread(NULL,
313 0,
314 ScmNamedPipeListenerThread,
315 NULL, /*(LPVOID)hPipe,*/
316 0,
317 &dwThreadId);
318 if (!hThread)
319 {
320 DPRINT1("SERVICES: Could not create thread (Status %lx)\n", GetLastError());
321 return FALSE;
322 }
323
324 CloseHandle(hThread);
325
326 return TRUE;
327 }
328
329
330 VOID FASTCALL
331 AcquireLoadDriverPrivilege(VOID)
332 {
333 HANDLE hToken;
334 TOKEN_PRIVILEGES tkp;
335
336 /* Get a token for this process */
337 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
338 {
339 /* Get the LUID for the debug privilege */
340 LookupPrivilegeValue(NULL, SE_LOAD_DRIVER_NAME, &tkp.Privileges[0].Luid);
341
342 /* One privilege to set */
343 tkp.PrivilegeCount = 1;
344 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
345
346 /* Get the debug privilege for this process */
347 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
348 }
349 }
350
351
352 BOOL WINAPI
353 ShutdownHandlerRoutine(DWORD dwCtrlType)
354 {
355 DPRINT1("ShutdownHandlerRoutine() called\n");
356
357 if (dwCtrlType & (CTRL_SHUTDOWN_EVENT | CTRL_LOGOFF_EVENT))
358 {
359 DPRINT1("Shutdown event received!\n");
360 ScmShutdown = TRUE;
361
362 ScmAutoShutdownServices();
363 ScmShutdownServiceDatabase();
364
365 /* Set the shutdwon event */
366 SetEvent(hScmShutdownEvent);
367 }
368
369 return TRUE;
370 }
371
372
373 int WINAPI
374 wWinMain(HINSTANCE hInstance,
375 HINSTANCE hPrevInstance,
376 LPWSTR lpCmdLine,
377 int nShowCmd)
378 {
379 HANDLE hScmStartEvent = NULL;
380 SC_RPC_LOCK Lock = NULL;
381 DWORD dwError;
382
383 DPRINT("SERVICES: Service Control Manager\n");
384
385 /* Create start event */
386 if (!ScmCreateStartEvent(&hScmStartEvent))
387 {
388 DPRINT1("SERVICES: Failed to create start event\n");
389 goto done;
390 }
391
392 DPRINT("SERVICES: created start event with handle %p.\n", hScmStartEvent);
393
394 /* Create the shutdown event */
395 hScmShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
396 if (hScmShutdownEvent == NULL)
397 {
398 DPRINT1("SERVICES: Failed to create shutdown event\n");
399 goto done;
400 }
401
402 // ScmInitThreadManager();
403
404 /* FIXME: more initialization */
405
406 /* Create the service database */
407 dwError = ScmCreateServiceDatabase();
408 if (dwError != ERROR_SUCCESS)
409 {
410 DPRINT1("SERVICES: failed to create SCM database (Error %lu)\n", dwError);
411 goto done;
412 }
413
414 /* Update service database */
415 ScmGetBootAndSystemDriverState();
416
417 /* Start the RPC server */
418 ScmStartRpcServer();
419
420 /* Register service process with CSRSS */
421 RegisterServicesProcess(GetCurrentProcessId());
422
423 DPRINT("SERVICES: Initialized.\n");
424
425 /* Signal start event */
426 SetEvent(hScmStartEvent);
427
428 /* Register event handler (used for system shutdown) */
429 SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
430
431 /* Wait for the LSA server */
432 ScmWaitForLsa();
433
434 /* Acquire privileges to load drivers */
435 AcquireLoadDriverPrivilege();
436
437 ScmInitNamedPipeCriticalSection();
438
439 /* Acquire the service start lock until autostart services have been started */
440 dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
441 if (dwError != ERROR_SUCCESS)
442 {
443 DPRINT1("SERVICES: failed to acquire the service start lock (Error %lu)\n", dwError);
444 goto done;
445 }
446
447 /* Start auto-start services */
448 ScmAutoStartServices();
449
450 /* FIXME: more to do ? */
451
452 /* Release the service start lock */
453 ScmReleaseServiceStartLock(&Lock);
454
455 DPRINT("SERVICES: Running.\n");
456
457 /* Wait until the shutdown event gets signaled */
458 WaitForSingleObject(hScmShutdownEvent, INFINITE);
459
460 done:
461 ScmDeleteNamedPipeCriticalSection();
462
463 /* Close the shutdown event */
464 if (hScmShutdownEvent != NULL)
465 CloseHandle(hScmShutdownEvent);
466
467 /* Close the start event */
468 if (hScmStartEvent != NULL)
469 CloseHandle(hScmStartEvent);
470
471 DPRINT("SERVICES: Finished.\n");
472
473 ExitThread(0);
474
475 return 0;
476 }
477
478 /* EOF */