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