[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 = CreateEvent(NULL,
89 TRUE,
90 FALSE,
91 TEXT("SvcctrlStartEvent_A3752DX"));
92 if (hEvent == NULL)
93 {
94 if (GetLastError() == ERROR_ALREADY_EXISTS)
95 {
96 hEvent = OpenEvent(EVENT_ALL_ACCESS,
97 FALSE,
98 TEXT("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 static VOID
117 ScmWaitForLsass(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 DPRINT("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
151
152 BOOL
153 ScmNamedPipeHandleRequest(PVOID Request,
154 DWORD RequestSize,
155 PVOID Reply,
156 LPDWORD ReplySize)
157 {
158 DbgPrint("SCM READ: %s\n", Request);
159
160 *ReplySize = 0;
161 return FALSE;
162 }
163
164
165 DWORD WINAPI
166 ScmNamedPipeThread(LPVOID Context)
167 {
168 CHAR chRequest[PIPE_BUFSIZE];
169 CHAR chReply[PIPE_BUFSIZE];
170 DWORD cbReplyBytes;
171 DWORD cbBytesRead;
172 DWORD cbWritten;
173 BOOL bSuccess;
174 HANDLE hPipe;
175
176 hPipe = (HANDLE)Context;
177
178 DPRINT("ScmNamedPipeThread(%x) - Accepting SCM commands through named pipe\n", hPipe);
179
180 for (;;)
181 {
182 bSuccess = ReadFile(hPipe,
183 &chRequest,
184 PIPE_BUFSIZE,
185 &cbBytesRead,
186 NULL);
187 if (!bSuccess || cbBytesRead == 0)
188 {
189 break;
190 }
191
192 if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes))
193 {
194 bSuccess = WriteFile(hPipe,
195 &chReply,
196 cbReplyBytes,
197 &cbWritten,
198 NULL);
199 if (!bSuccess || cbReplyBytes != cbWritten)
200 {
201 break;
202 }
203 }
204 }
205
206 DPRINT("ScmNamedPipeThread(%x) - Disconnecting named pipe connection\n", hPipe);
207
208 FlushFileBuffers(hPipe);
209 DisconnectNamedPipe(hPipe);
210 CloseHandle(hPipe);
211
212 DPRINT("ScmNamedPipeThread(%x) - Done.\n", hPipe);
213
214 return ERROR_SUCCESS;
215 }
216
217
218 BOOL
219 ScmCreateNamedPipe(VOID)
220 {
221 DWORD dwThreadId;
222 BOOL bConnected;
223 HANDLE hThread;
224 HANDLE hPipe;
225
226 DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
227
228 hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Ntsvcs"),
229 PIPE_ACCESS_DUPLEX,
230 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
231 PIPE_UNLIMITED_INSTANCES,
232 PIPE_BUFSIZE,
233 PIPE_BUFSIZE,
234 PIPE_TIMEOUT,
235 NULL);
236 if (hPipe == INVALID_HANDLE_VALUE)
237 {
238 DPRINT("CreateNamedPipe() failed (%d)\n", GetLastError());
239 return FALSE;
240 }
241
242 DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%x)\n", hPipe);
243 bConnected = ConnectNamedPipe(hPipe,
244 NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
245 DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", bConnected);
246
247 if (bConnected)
248 {
249 DPRINT("Pipe connected\n");
250 hThread = CreateThread(NULL,
251 0,
252 ScmNamedPipeThread,
253 (LPVOID)hPipe,
254 0,
255 &dwThreadId);
256 if (!hThread)
257 {
258 DPRINT("Could not create thread (%d)\n", GetLastError());
259 DisconnectNamedPipe(hPipe);
260 CloseHandle(hPipe);
261 DPRINT("CreateNamedPipe() - returning FALSE\n");
262 return FALSE;
263 }
264
265 CloseHandle(hThread);
266 }
267 else
268 {
269 DPRINT("Pipe not connected\n");
270 CloseHandle(hPipe);
271 DPRINT("CreateNamedPipe() - returning FALSE\n");
272 return FALSE;
273 }
274 DPRINT("CreateNamedPipe() - returning TRUE\n");
275 return TRUE;
276 }
277
278
279 DWORD WINAPI
280 ScmNamedPipeListenerThread(LPVOID Context)
281 {
282 // HANDLE hPipe;
283 DPRINT("ScmNamedPipeListenerThread(%x) - aka SCM.\n", Context);
284
285 // hPipe = (HANDLE)Context;
286 for (;;)
287 {
288 DPRINT("SCM: Waiting for new connection on named pipe...\n");
289 /* Create named pipe */
290 if (!ScmCreateNamedPipe())
291 {
292 DPRINT1("\nSCM: Failed to create named pipe\n");
293 break;
294 //ExitThread(0);
295 }
296 DPRINT("\nSCM: named pipe session created.\n");
297 Sleep(10);
298 }
299 DPRINT("\n\nWARNING: ScmNamedPipeListenerThread(%x) - Aborted.\n\n", Context);
300 return ERROR_SUCCESS;
301 }
302
303
304 BOOL
305 StartScmNamedPipeThreadListener(VOID)
306 {
307 DWORD dwThreadId;
308 HANDLE hThread;
309
310 hThread = CreateThread(NULL,
311 0,
312 ScmNamedPipeListenerThread,
313 NULL, /*(LPVOID)hPipe,*/
314 0,
315 &dwThreadId);
316 if (!hThread)
317 {
318 DPRINT1("SERVICES: Could not create thread (Status %lx)\n", GetLastError());
319 return FALSE;
320 }
321
322 CloseHandle(hThread);
323
324 return TRUE;
325 }
326
327
328 VOID FASTCALL
329 AcquireLoadDriverPrivilege(VOID)
330 {
331 HANDLE hToken;
332 TOKEN_PRIVILEGES tkp;
333
334 /* Get a token for this process */
335 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
336 {
337 /* Get the LUID for the debug privilege */
338 LookupPrivilegeValue(NULL, SE_LOAD_DRIVER_NAME, &tkp.Privileges[0].Luid);
339
340 /* One privilege to set */
341 tkp.PrivilegeCount = 1;
342 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
343
344 /* Get the debug privilege for this process */
345 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
346 }
347 }
348
349
350 BOOL WINAPI
351 ShutdownHandlerRoutine(DWORD dwCtrlType)
352 {
353 DPRINT1("ShutdownHandlerRoutine() called\n");
354
355 if (dwCtrlType & (CTRL_SHUTDOWN_EVENT | CTRL_LOGOFF_EVENT))
356 {
357 DPRINT1("Shutdown event received!\n");
358 ScmShutdown = TRUE;
359
360 ScmAutoShutdownServices();
361 ScmShutdownServiceDatabase();
362
363 /* Set the shutdwon event */
364 SetEvent(hScmShutdownEvent);
365 }
366
367 return TRUE;
368 }
369
370
371 int WINAPI
372 wWinMain(HINSTANCE hInstance,
373 HINSTANCE hPrevInstance,
374 LPWSTR lpCmdLine,
375 int nShowCmd)
376 {
377 HANDLE hScmStartEvent;
378 DWORD dwError;
379
380 DPRINT("SERVICES: Service Control Manager\n");
381
382 /* Create start event */
383 if (!ScmCreateStartEvent(&hScmStartEvent))
384 {
385 DPRINT1("SERVICES: Failed to create start event\n");
386 ExitThread(0);
387 }
388
389 DPRINT("SERVICES: created start event with handle %p.\n", hScmStartEvent);
390
391 // ScmInitThreadManager();
392
393 /* FIXME: more initialization */
394
395
396 /* Create the service database */
397 dwError = ScmCreateServiceDatabase();
398 if (dwError != ERROR_SUCCESS)
399 {
400 DPRINT1("SERVICES: failed to create SCM database (Error %lu)\n", dwError);
401 CloseHandle(hScmStartEvent);
402 ExitThread(0);
403 }
404
405 /* Update service database */
406 ScmGetBootAndSystemDriverState();
407
408 /* Start the RPC server */
409 ScmStartRpcServer();
410
411 /* Register service process with CSRSS */
412 RegisterServicesProcess(GetCurrentProcessId());
413
414 DPRINT("SERVICES: Initialized.\n");
415
416 /* Signal start event */
417 SetEvent(hScmStartEvent);
418
419 /* Register event handler (used for system shutdown) */
420 SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
421
422 /* Wait for the LSA server */
423 ScmWaitForLsass();
424
425 /* Acquire privileges to load drivers */
426 AcquireLoadDriverPrivilege();
427
428 ScmInitNamedPipeCriticalSection();
429
430 /* Start auto-start services */
431 ScmAutoStartServices();
432
433 /* FIXME: more to do ? */
434
435
436 DPRINT("SERVICES: Running.\n");
437
438 /* Create the shutdown event and wait until it gets set */
439 hScmShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
440 if (hScmShutdownEvent)
441 WaitForSingleObject(hScmShutdownEvent, INFINITE);
442
443 ScmDeleteNamedPipeCriticalSection();
444
445 /* Close the shutdown event */
446 CloseHandle(hScmShutdownEvent);
447
448 /* Close the start event */
449 CloseHandle(hScmStartEvent);
450
451 DPRINT("SERVICES: Finished.\n");
452
453 ExitThread(0);
454
455 return 0;
456 }
457
458 /* EOF */