8235c503718de160b9087611184ced8130914bd1
[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 <windows.h>
32 #define NTOS_MODE_USER
33 #include <ndk/ntndk.h>
34
35 #include "services.h"
36
37 #define NDEBUG
38 #include <debug.h>
39
40 int WINAPI RegisterServicesProcess(DWORD ServicesProcessId);
41
42 /* GLOBALS ******************************************************************/
43
44 #define PIPE_BUFSIZE 1024
45 #define PIPE_TIMEOUT 1000
46
47
48 /* FUNCTIONS *****************************************************************/
49
50 VOID
51 PrintString(LPCSTR fmt, ...)
52 {
53 #ifdef DBG
54 CHAR buffer[512];
55 va_list ap;
56
57 va_start(ap, fmt);
58 vsprintf(buffer, fmt, ap);
59 va_end(ap);
60
61 OutputDebugStringA(buffer);
62 #endif
63 }
64
65
66 BOOL
67 ScmCreateStartEvent(PHANDLE StartEvent)
68 {
69 HANDLE hEvent;
70
71 hEvent = CreateEvent(NULL,
72 TRUE,
73 FALSE,
74 TEXT("SvcctrlStartEvent_A3725DX"));
75 if (hEvent == NULL)
76 {
77 if (GetLastError() == ERROR_ALREADY_EXISTS)
78 {
79 hEvent = OpenEvent(EVENT_ALL_ACCESS,
80 FALSE,
81 TEXT("SvcctrlStartEvent_A3725DX"));
82 if (hEvent == NULL)
83 {
84 return FALSE;
85 }
86 }
87 else
88 {
89 return FALSE;
90 }
91 }
92
93 *StartEvent = hEvent;
94
95 return TRUE;
96 }
97
98
99 BOOL
100 ScmNamedPipeHandleRequest(PVOID Request,
101 DWORD RequestSize,
102 PVOID Reply,
103 LPDWORD ReplySize)
104 {
105 DbgPrint("SCM READ: %s\n", Request);
106
107 *ReplySize = 0;
108 return FALSE;
109 }
110
111
112 DWORD WINAPI
113 ScmNamedPipeThread(LPVOID Context)
114 {
115 CHAR chRequest[PIPE_BUFSIZE];
116 CHAR chReply[PIPE_BUFSIZE];
117 DWORD cbReplyBytes;
118 DWORD cbBytesRead;
119 DWORD cbWritten;
120 BOOL fSuccess;
121 HANDLE hPipe;
122
123 hPipe = (HANDLE)Context;
124
125 DPRINT("ScmNamedPipeThread(%x) - Accepting SCM commands through named pipe\n", hPipe);
126
127 for (;;) {
128 fSuccess = ReadFile(hPipe,
129 &chRequest,
130 PIPE_BUFSIZE,
131 &cbBytesRead,
132 NULL);
133 if (!fSuccess || cbBytesRead == 0) {
134 break;
135 }
136 if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes)) {
137 fSuccess = WriteFile(hPipe,
138 &chReply,
139 cbReplyBytes,
140 &cbWritten,
141 NULL);
142 if (!fSuccess || cbReplyBytes != cbWritten) {
143 break;
144 }
145 }
146 }
147 DPRINT("ScmNamedPipeThread(%x) - Disconnecting named pipe connection\n", hPipe);
148 FlushFileBuffers(hPipe);
149 DisconnectNamedPipe(hPipe);
150 CloseHandle(hPipe);
151 DPRINT("ScmNamedPipeThread(%x) - Done.\n", hPipe);
152 return ERROR_SUCCESS;
153 }
154
155
156 BOOL
157 ScmCreateNamedPipe(VOID)
158 {
159 DWORD dwThreadId;
160 BOOL fConnected;
161 HANDLE hThread;
162 HANDLE hPipe;
163
164 DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
165
166 hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Ntsvcs"),
167 PIPE_ACCESS_DUPLEX,
168 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
169 PIPE_UNLIMITED_INSTANCES,
170 PIPE_BUFSIZE,
171 PIPE_BUFSIZE,
172 PIPE_TIMEOUT,
173 NULL);
174 if (hPipe == INVALID_HANDLE_VALUE) {
175 DPRINT("CreateNamedPipe() failed (%d)\n", GetLastError());
176 return FALSE;
177 }
178
179 DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%x)\n", hPipe);
180 fConnected = ConnectNamedPipe(hPipe,
181 NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
182 DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", fConnected);
183
184 if (fConnected) {
185 DPRINT("Pipe connected\n");
186 hThread = CreateThread(NULL,
187 0,
188 ScmNamedPipeThread,
189 (LPVOID)hPipe,
190 0,
191 &dwThreadId);
192 if (!hThread) {
193 DPRINT("Could not create thread (%d)\n", GetLastError());
194 DisconnectNamedPipe(hPipe);
195 CloseHandle(hPipe);
196 DPRINT("CreateNamedPipe() - returning FALSE\n");
197 return FALSE;
198 }
199 } else {
200 DPRINT("Pipe not connected\n");
201 CloseHandle(hPipe);
202 DPRINT("CreateNamedPipe() - returning FALSE\n");
203 return FALSE;
204 }
205 DPRINT("CreateNamedPipe() - returning TRUE\n");
206 return TRUE;
207 }
208
209
210 DWORD WINAPI
211 ScmNamedPipeListenerThread(LPVOID Context)
212 {
213 // HANDLE hPipe;
214 DPRINT("ScmNamedPipeListenerThread(%x) - aka SCM.\n", Context);
215
216 // hPipe = (HANDLE)Context;
217 for (;;) {
218 DPRINT("SCM: Waiting for new connection on named pipe...\n");
219 /* Create named pipe */
220 if (!ScmCreateNamedPipe()) {
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 int STDCALL
278 WinMain(HINSTANCE hInstance,
279 HINSTANCE hPrevInstance,
280 LPSTR lpCmdLine,
281 int nShowCmd)
282 {
283 HANDLE hScmStartEvent;
284 HANDLE hEvent;
285 NTSTATUS Status;
286
287 DPRINT("SERVICES: Service Control Manager\n");
288
289 /* Acquire privileges to load drivers */
290 AcquireLoadDriverPrivilege();
291
292 /* Create start event */
293 if (!ScmCreateStartEvent(&hScmStartEvent))
294 {
295 DPRINT1("SERVICES: Failed to create start event\n");
296 ExitThread(0);
297 }
298
299 DPRINT("SERVICES: created start event with handle %x.\n", hScmStartEvent);
300
301 // ScmInitThreadManager();
302
303 /* FIXME: more initialization */
304
305
306 /* Create the service database */
307 Status = ScmCreateServiceDataBase();
308 if (!NT_SUCCESS(Status))
309 {
310 DPRINT1("SERVICES: failed to create SCM database (Status %lx)\n", Status);
311 ExitThread(0);
312 }
313
314 /* Update service database */
315 ScmGetBootAndSystemDriverState();
316
317 /* Start the RPC server */
318 ScmStartRpcServer();
319
320 /* Register service process with CSRSS */
321 // RegisterServicesProcess(GetCurrentProcessId());
322
323 DPRINT("SERVICES: Initialized.\n");
324
325 /* Signal start event */
326 SetEvent(hScmStartEvent);
327
328 #if 0
329 /* FIXME: register event handler (used for system shutdown) */
330 SetConsoleCtrlHandler(...);
331 #endif
332
333 /* Start auto-start services */
334 ScmAutoStartServices();
335
336 /* FIXME: more to do ? */
337
338
339 DPRINT("SERVICES: Running.\n");
340
341 #if 1
342 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
343 WaitForSingleObject(hEvent, INFINITE);
344 #else
345 for (;;)
346 {
347 NtYieldExecution();
348 }
349 #endif
350
351 DPRINT("SERVICES: Finished.\n");
352
353 ExitThread(0);
354
355 return 0;
356 }
357
358 /* EOF */