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