- Rewrote the code that reads the service configuration from the registry because...
[reactos.git] / reactos / subsys / system / services / services.c
1 /*
2 * service control manager
3 *
4 * ReactOS Operating System
5 *
6 * --------------------------------------------------------------------
7 *
8 * This software is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This software is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this software; see the file COPYING.LIB. If not, write
20 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
21 * MA 02139, USA.
22 *
23 */
24
25 /* NOTE:
26 * - Services.exe is NOT a native application, it is a GUI app.
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include "services.h"
32
33 #define NDEBUG
34 #include <debug.h>
35
36 int WINAPI RegisterServicesProcess(DWORD ServicesProcessId);
37
38 /* GLOBALS ******************************************************************/
39
40 #define PIPE_BUFSIZE 1024
41 #define PIPE_TIMEOUT 1000
42
43 BOOL ScmShutdown = FALSE;
44
45
46 /* FUNCTIONS *****************************************************************/
47
48 VOID
49 PrintString(LPCSTR fmt, ...)
50 {
51 #ifdef DBG
52 CHAR buffer[512];
53 va_list ap;
54
55 va_start(ap, fmt);
56 vsprintf(buffer, fmt, ap);
57 va_end(ap);
58
59 OutputDebugStringA(buffer);
60 #endif
61 }
62
63
64 BOOL
65 ScmCreateStartEvent(PHANDLE StartEvent)
66 {
67 HANDLE hEvent;
68
69 hEvent = CreateEvent(NULL,
70 TRUE,
71 FALSE,
72 TEXT("SvcctrlStartEvent_A3725DX"));
73 if (hEvent == NULL)
74 {
75 if (GetLastError() == ERROR_ALREADY_EXISTS)
76 {
77 hEvent = OpenEvent(EVENT_ALL_ACCESS,
78 FALSE,
79 TEXT("SvcctrlStartEvent_A3725DX"));
80 if (hEvent == NULL)
81 {
82 return FALSE;
83 }
84 }
85 else
86 {
87 return FALSE;
88 }
89 }
90
91 *StartEvent = hEvent;
92
93 return TRUE;
94 }
95
96
97 BOOL
98 ScmNamedPipeHandleRequest(PVOID Request,
99 DWORD RequestSize,
100 PVOID Reply,
101 LPDWORD ReplySize)
102 {
103 DbgPrint("SCM READ: %s\n", Request);
104
105 *ReplySize = 0;
106 return FALSE;
107 }
108
109
110 DWORD WINAPI
111 ScmNamedPipeThread(LPVOID Context)
112 {
113 CHAR chRequest[PIPE_BUFSIZE];
114 CHAR chReply[PIPE_BUFSIZE];
115 DWORD cbReplyBytes;
116 DWORD cbBytesRead;
117 DWORD cbWritten;
118 BOOL bSuccess;
119 HANDLE hPipe;
120
121 hPipe = (HANDLE)Context;
122
123 DPRINT("ScmNamedPipeThread(%x) - Accepting SCM commands through named pipe\n", hPipe);
124
125 for (;;)
126 {
127 bSuccess = ReadFile(hPipe,
128 &chRequest,
129 PIPE_BUFSIZE,
130 &cbBytesRead,
131 NULL);
132 if (!bSuccess || cbBytesRead == 0)
133 {
134 break;
135 }
136
137 if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes))
138 {
139 bSuccess = WriteFile(hPipe,
140 &chReply,
141 cbReplyBytes,
142 &cbWritten,
143 NULL);
144 if (!bSuccess || cbReplyBytes != cbWritten)
145 {
146 break;
147 }
148 }
149 }
150
151 DPRINT("ScmNamedPipeThread(%x) - Disconnecting named pipe connection\n", hPipe);
152
153 FlushFileBuffers(hPipe);
154 DisconnectNamedPipe(hPipe);
155 CloseHandle(hPipe);
156
157 DPRINT("ScmNamedPipeThread(%x) - Done.\n", hPipe);
158
159 return ERROR_SUCCESS;
160 }
161
162
163 BOOL
164 ScmCreateNamedPipe(VOID)
165 {
166 DWORD dwThreadId;
167 BOOL bConnected;
168 HANDLE hThread;
169 HANDLE hPipe;
170
171 DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
172
173 hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Ntsvcs"),
174 PIPE_ACCESS_DUPLEX,
175 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
176 PIPE_UNLIMITED_INSTANCES,
177 PIPE_BUFSIZE,
178 PIPE_BUFSIZE,
179 PIPE_TIMEOUT,
180 NULL);
181 if (hPipe == INVALID_HANDLE_VALUE)
182 {
183 DPRINT("CreateNamedPipe() failed (%d)\n", GetLastError());
184 return FALSE;
185 }
186
187 DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%x)\n", hPipe);
188 bConnected = ConnectNamedPipe(hPipe,
189 NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
190 DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", bConnected);
191
192 if (bConnected)
193 {
194 DPRINT("Pipe connected\n");
195 hThread = CreateThread(NULL,
196 0,
197 ScmNamedPipeThread,
198 (LPVOID)hPipe,
199 0,
200 &dwThreadId);
201 if (!hThread)
202 {
203 DPRINT("Could not create thread (%d)\n", GetLastError());
204 DisconnectNamedPipe(hPipe);
205 CloseHandle(hPipe);
206 DPRINT("CreateNamedPipe() - returning FALSE\n");
207 return FALSE;
208 }
209 }
210 else
211 {
212 DPRINT("Pipe not connected\n");
213 CloseHandle(hPipe);
214 DPRINT("CreateNamedPipe() - returning FALSE\n");
215 return FALSE;
216 }
217 DPRINT("CreateNamedPipe() - returning TRUE\n");
218 return TRUE;
219 }
220
221
222 DWORD WINAPI
223 ScmNamedPipeListenerThread(LPVOID Context)
224 {
225 // HANDLE hPipe;
226 DPRINT("ScmNamedPipeListenerThread(%x) - aka SCM.\n", Context);
227
228 // hPipe = (HANDLE)Context;
229 for (;;)
230 {
231 DPRINT("SCM: Waiting for new connection on named pipe...\n");
232 /* Create named pipe */
233 if (!ScmCreateNamedPipe())
234 {
235 DPRINT1("\nSCM: Failed to create named pipe\n");
236 break;
237 //ExitThread(0);
238 }
239 DPRINT("\nSCM: named pipe session created.\n");
240 Sleep(10);
241 }
242 DPRINT("\n\nWARNING: ScmNamedPipeListenerThread(%x) - Aborted.\n\n", Context);
243 return ERROR_SUCCESS;
244 }
245
246
247 BOOL
248 StartScmNamedPipeThreadListener(VOID)
249 {
250 DWORD dwThreadId;
251 HANDLE hThread;
252
253 hThread = CreateThread(NULL,
254 0,
255 ScmNamedPipeListenerThread,
256 NULL, /*(LPVOID)hPipe,*/
257 0,
258 &dwThreadId);
259 if (!hThread)
260 {
261 DPRINT1("SERVICES: Could not create thread (Status %lx)\n", GetLastError());
262 return FALSE;
263 }
264
265 return TRUE;
266 }
267
268
269 VOID FASTCALL
270 AcquireLoadDriverPrivilege(VOID)
271 {
272 HANDLE hToken;
273 TOKEN_PRIVILEGES tkp;
274
275 /* Get a token for this process */
276 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
277 {
278 /* Get the LUID for the debug privilege */
279 LookupPrivilegeValue(NULL, SE_LOAD_DRIVER_NAME, &tkp.Privileges[0].Luid);
280
281 /* One privilege to set */
282 tkp.PrivilegeCount = 1;
283 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
284
285 /* Get the debug privilege for this process */
286 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
287 }
288 }
289
290
291 BOOL WINAPI
292 ShutdownHandlerRoutine(DWORD dwCtrlType)
293 {
294 DPRINT1("ShutdownHandlerRoutine() called\n");
295
296 if (dwCtrlType == CTRL_SHUTDOWN_EVENT)
297 {
298 DPRINT1("Shutdown event received!\n");
299 ScmShutdown = TRUE;
300
301 /* FIXME: Shut all services down */
302 }
303
304 return TRUE;
305 }
306
307
308 int STDCALL
309 WinMain(HINSTANCE hInstance,
310 HINSTANCE hPrevInstance,
311 LPSTR lpCmdLine,
312 int nShowCmd)
313 {
314 HANDLE hScmStartEvent;
315 HANDLE hEvent;
316 DWORD dwError;
317
318 DPRINT("SERVICES: Service Control Manager\n");
319
320 /* Acquire privileges to load drivers */
321 AcquireLoadDriverPrivilege();
322
323 /* Create start event */
324 if (!ScmCreateStartEvent(&hScmStartEvent))
325 {
326 DPRINT1("SERVICES: Failed to create start event\n");
327 ExitThread(0);
328 }
329
330 DPRINT("SERVICES: created start event with handle %x.\n", hScmStartEvent);
331
332 // ScmInitThreadManager();
333
334 /* FIXME: more initialization */
335
336
337 /* Create the service database */
338 dwError = ScmCreateServiceDatabase();
339 if (dwError != ERROR_SUCCESS)
340 {
341 DPRINT1("SERVICES: failed to create SCM database (Error %lu)\n", dwError);
342 ExitThread(0);
343 }
344
345 /* Update service database */
346 ScmGetBootAndSystemDriverState();
347
348 /* Start the RPC server */
349 ScmStartRpcServer();
350
351 /* Register service process with CSRSS */
352 RegisterServicesProcess(GetCurrentProcessId());
353
354 DPRINT("SERVICES: Initialized.\n");
355
356 /* Signal start event */
357 SetEvent(hScmStartEvent);
358
359 /* Register event handler (used for system shutdown) */
360 SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
361
362 /* Start auto-start services */
363 ScmAutoStartServices();
364
365 /* FIXME: more to do ? */
366
367
368 DPRINT("SERVICES: Running.\n");
369
370 #if 1
371 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
372 WaitForSingleObject(hEvent, INFINITE);
373 #else
374 for (;;)
375 {
376 NtYieldExecution();
377 }
378 #endif
379
380 DPRINT("SERVICES: Finished.\n");
381
382 ExitThread(0);
383
384 return 0;
385 }
386
387 /* EOF */