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