Big merge: thanks alex and greatlord. Not a complete merge but most
[reactos.git] / reactos / dll / win32 / advapi32 / service / sctrl.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/advapi32/service/sctrl.c
6 * PURPOSE: Service control manager functions
7 * PROGRAMMER: Emanuele Aliberti
8 * UPDATE HISTORY:
9 * 19990413 EA created
10 * 19990515 EA
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <advapi32.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20
21 /* TYPES *********************************************************************/
22
23 typedef struct _ACTIVE_SERVICE
24 {
25 DWORD ThreadId;
26 UNICODE_STRING ServiceName;
27 union
28 {
29 LPSERVICE_MAIN_FUNCTIONA lpFuncA;
30 LPSERVICE_MAIN_FUNCTIONW lpFuncW;
31 } Main;
32 LPHANDLER_FUNCTION HandlerFunction;
33 LPHANDLER_FUNCTION_EX HandlerFunctionEx;
34 LPVOID HandlerContext;
35 SERVICE_STATUS ServiceStatus;
36 BOOL bUnicode;
37 LPWSTR Arguments;
38 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
39
40
41 /* GLOBALS *******************************************************************/
42
43 static DWORD dwActiveServiceCount = 0;
44 static PACTIVE_SERVICE lpActiveServices = NULL;
45
46
47 /* FUNCTIONS *****************************************************************/
48
49 static PACTIVE_SERVICE
50 ScLookupServiceByServiceName(LPWSTR lpServiceName)
51 {
52 DWORD i;
53
54 for (i = 0; i < dwActiveServiceCount; i++)
55 {
56 if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
57 {
58 return &lpActiveServices[i];
59 }
60 }
61
62 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
63
64 return NULL;
65 }
66
67
68 static PACTIVE_SERVICE
69 ScLookupServiceByThreadId(DWORD ThreadId)
70 {
71 DWORD i;
72
73 for (i = 0; i < dwActiveServiceCount; i++)
74 {
75 if (lpActiveServices[i].ThreadId == ThreadId)
76 {
77 return &lpActiveServices[i];
78 }
79 }
80
81 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
82
83 return NULL;
84 }
85
86
87 static DWORD WINAPI
88 ScServiceMainStub(LPVOID Context)
89 {
90 PACTIVE_SERVICE lpService;
91 DWORD dwArgCount = 0;
92 DWORD dwLength = 0;
93
94 lpService = (PACTIVE_SERVICE)Context;
95
96 DPRINT("ScServiceMainStub() called\n");
97
98 /* Count arguments */
99 while (lpService->Arguments[dwLength])
100 {
101 dwLength += wcslen(&lpService->Arguments[dwLength]) + 1;
102 dwArgCount++;
103 }
104
105 /* Build the argument vector and call the main service routine */
106 if (lpService->bUnicode)
107 {
108 LPWSTR *lpArgVector;
109 LPWSTR Ptr;
110
111 lpArgVector = HeapAlloc(GetProcessHeap(),
112 HEAP_ZERO_MEMORY,
113 (dwArgCount + 1) * sizeof(LPWSTR));
114 if (lpArgVector == NULL)
115 return ERROR_OUTOFMEMORY;
116
117 dwArgCount = 0;
118 Ptr = lpService->Arguments;
119 while (*Ptr)
120 {
121 lpArgVector[dwArgCount] = Ptr;
122
123 dwArgCount++;
124 Ptr += (wcslen(Ptr) + 1);
125 }
126 lpArgVector[dwArgCount] = NULL;
127
128 (lpService->Main.lpFuncW)(dwArgCount, lpArgVector);
129
130 HeapFree(GetProcessHeap(),
131 0,
132 lpArgVector);
133 }
134 else
135 {
136 LPSTR *lpArgVector;
137 LPSTR Ptr;
138 LPSTR AnsiString;
139 DWORD AnsiLength;
140
141 AnsiLength = WideCharToMultiByte(CP_ACP,
142 0,
143 lpService->Arguments,
144 dwLength,
145 NULL,
146 0,
147 NULL,
148 NULL);
149 AnsiString = HeapAlloc(GetProcessHeap(),
150 0,
151 AnsiLength);
152 WideCharToMultiByte(CP_ACP,
153 0,
154 lpService->Arguments,
155 dwLength,
156 AnsiString,
157 AnsiLength,
158 NULL,
159 NULL);
160
161 lpArgVector = HeapAlloc(GetProcessHeap(),
162 0,
163 (dwArgCount + 1) * sizeof(LPSTR));
164
165 dwArgCount = 0;
166 Ptr = AnsiString;
167 while (*Ptr)
168 {
169 lpArgVector[dwArgCount] = Ptr;
170
171 dwArgCount++;
172 Ptr += (strlen(Ptr) + 1);
173 }
174 lpArgVector[dwArgCount] = NULL;
175
176 (lpService->Main.lpFuncA)(dwArgCount, lpArgVector);
177
178 HeapFree(GetProcessHeap(),
179 0,
180 lpArgVector);
181 HeapFree(GetProcessHeap(),
182 0,
183 AnsiString);
184 }
185
186 return ERROR_SUCCESS;
187 }
188
189
190 static DWORD
191 ScConnectControlPipe(HANDLE *hPipe)
192 {
193 DWORD dwBytesWritten;
194 DWORD dwProcessId;
195 DWORD dwState;
196
197 if (!WaitNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe", 15000))
198 {
199 DPRINT1("WaitNamedPipe() failed (Error %lu)\n", GetLastError());
200 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
201 }
202
203 *hPipe = CreateFileW(L"\\\\.\\pipe\\net\\NtControlPipe",
204 GENERIC_READ | GENERIC_WRITE,
205 0,
206 NULL,
207 OPEN_EXISTING,
208 FILE_ATTRIBUTE_NORMAL,
209 NULL);
210 if (*hPipe == INVALID_HANDLE_VALUE)
211 {
212 DPRINT1("CreateFileW() failed (Error %lu)\n", GetLastError());
213 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
214 }
215
216 dwState = PIPE_READMODE_MESSAGE;
217 if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
218 {
219 CloseHandle(hPipe);
220 *hPipe = INVALID_HANDLE_VALUE;
221 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
222 }
223
224 dwProcessId = GetCurrentProcessId();
225 WriteFile(*hPipe,
226 &dwProcessId,
227 sizeof(DWORD),
228 &dwBytesWritten,
229 NULL);
230
231 DPRINT("Sent process id %lu\n", dwProcessId);
232
233 return ERROR_SUCCESS;
234 }
235
236
237
238 static DWORD
239 ScStartService(PSCM_START_PACKET StartPacket)
240 {
241 PACTIVE_SERVICE lpService;
242 HANDLE ThreadHandle;
243
244 DPRINT("Size: %lu\n", StartPacket->Size);
245 DPRINT("Service: %S\n", &StartPacket->Arguments[0]);
246
247 lpService = ScLookupServiceByServiceName(&StartPacket->Arguments[0]);
248 if (lpService == NULL)
249 return ERROR_SERVICE_DOES_NOT_EXIST;
250
251 lpService->Arguments = HeapAlloc(GetProcessHeap(),
252 HEAP_ZERO_MEMORY,
253 StartPacket->Size * sizeof(WCHAR));
254 if (lpService->Arguments == NULL)
255 return ERROR_OUTOFMEMORY;
256
257 memcpy(lpService->Arguments,
258 StartPacket->Arguments,
259 StartPacket->Size * sizeof(WCHAR));
260
261 ThreadHandle = CreateThread(NULL,
262 0,
263 ScServiceMainStub,
264 lpService,
265 CREATE_SUSPENDED,
266 &lpService->ThreadId);
267 if (ThreadHandle == NULL)
268 return ERROR_SERVICE_NO_THREAD;
269
270 ResumeThread(ThreadHandle);
271 CloseHandle(ThreadHandle);
272
273 return ERROR_SUCCESS;
274 }
275
276
277 static BOOL
278 ScServiceDispatcher(HANDLE hPipe,
279 PUCHAR lpBuffer,
280 DWORD dwBufferSize)
281 {
282 LPDWORD Buffer;
283 DWORD Count;
284 BOOL bResult;
285
286 DPRINT("ScDispatcherLoop() called\n");
287
288 Buffer = HeapAlloc(GetProcessHeap(),
289 HEAP_ZERO_MEMORY,
290 1024);
291 if (Buffer == NULL)
292 return FALSE;
293
294 while (TRUE)
295 {
296 /* Read command from the control pipe */
297 bResult = ReadFile(hPipe,
298 Buffer,
299 1024,
300 &Count,
301 NULL);
302 if (bResult == FALSE)
303 {
304 DPRINT1("Pipe read failed (Error: %lu)\n", GetLastError());
305 return FALSE;
306 }
307
308 /* Execute command */
309 switch (Buffer[0])
310 {
311 case SCM_START_COMMAND:
312 DPRINT("Start command\n");
313 ScStartService((PSCM_START_PACKET)Buffer);
314 break;
315
316 default:
317 DPRINT1("Unknown command %lu", Buffer[0]);
318 break;
319 }
320 }
321
322 HeapFree(GetProcessHeap(),
323 0,
324 Buffer);
325
326 return TRUE;
327 }
328
329
330 /**********************************************************************
331 * RegisterServiceCtrlHandlerA
332 *
333 * @implemented
334 */
335 SERVICE_STATUS_HANDLE STDCALL
336 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
337 LPHANDLER_FUNCTION lpHandlerProc)
338 {
339 ANSI_STRING ServiceNameA;
340 UNICODE_STRING ServiceNameU;
341 SERVICE_STATUS_HANDLE SHandle;
342
343 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
344 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
345 {
346 SetLastError(ERROR_OUTOFMEMORY);
347 return (SERVICE_STATUS_HANDLE)0;
348 }
349
350 SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
351 lpHandlerProc);
352
353 RtlFreeUnicodeString(&ServiceNameU);
354
355 return SHandle;
356 }
357
358
359 /**********************************************************************
360 * RegisterServiceCtrlHandlerW
361 *
362 * @implemented
363 */
364 SERVICE_STATUS_HANDLE STDCALL
365 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
366 LPHANDLER_FUNCTION lpHandlerProc)
367 {
368 PACTIVE_SERVICE Service;
369
370 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
371 if (Service == NULL)
372 {
373 return (SERVICE_STATUS_HANDLE)NULL;
374 }
375
376 Service->HandlerFunction = lpHandlerProc;
377 Service->HandlerFunctionEx = NULL;
378
379 return (SERVICE_STATUS_HANDLE)Service->ThreadId;
380 }
381
382
383 /**********************************************************************
384 * RegisterServiceCtrlHandlerExA
385 *
386 * @implemented
387 */
388 SERVICE_STATUS_HANDLE STDCALL
389 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
390 LPHANDLER_FUNCTION_EX lpHandlerProc,
391 LPVOID lpContext)
392 {
393 ANSI_STRING ServiceNameA;
394 UNICODE_STRING ServiceNameU;
395 SERVICE_STATUS_HANDLE SHandle;
396
397 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
398 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
399 {
400 SetLastError(ERROR_OUTOFMEMORY);
401 return (SERVICE_STATUS_HANDLE)0;
402 }
403
404 SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
405 lpHandlerProc,
406 lpContext);
407
408 RtlFreeUnicodeString(&ServiceNameU);
409
410 return SHandle;
411 }
412
413
414 /**********************************************************************
415 * RegisterServiceCtrlHandlerExW
416 *
417 * @implemented
418 */
419 SERVICE_STATUS_HANDLE STDCALL
420 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
421 LPHANDLER_FUNCTION_EX lpHandlerProc,
422 LPVOID lpContext)
423 {
424 PACTIVE_SERVICE Service;
425
426 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
427 if (Service == NULL)
428 {
429 return (SERVICE_STATUS_HANDLE)NULL;
430 }
431
432 Service->HandlerFunction = NULL;
433 Service->HandlerFunctionEx = lpHandlerProc;
434 Service->HandlerContext = lpContext;
435
436 return (SERVICE_STATUS_HANDLE)Service->ThreadId;
437 }
438
439
440 /**********************************************************************
441 * SetServiceBits
442 *
443 * @unimplemented
444 */
445 BOOL STDCALL
446 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
447 DWORD dwServiceBits,
448 BOOL bSetBitsOn,
449 BOOL bUpdateImmediately)
450 {
451 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
452 return FALSE;
453 }
454
455
456 /**********************************************************************
457 * SetServiceStatus
458 *
459 * @implemented
460 */
461 BOOL STDCALL
462 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
463 LPSERVICE_STATUS lpServiceStatus)
464 {
465 PACTIVE_SERVICE Service;
466
467 Service = ScLookupServiceByThreadId((DWORD)hServiceStatus);
468 if (!Service)
469 {
470 SetLastError(ERROR_INVALID_HANDLE);
471 return FALSE;
472 }
473
474 RtlCopyMemory(&Service->ServiceStatus,
475 lpServiceStatus,
476 sizeof(SERVICE_STATUS));
477
478 return TRUE;
479 }
480
481
482 /**********************************************************************
483 * StartServiceCtrlDispatcherA
484 *
485 * @unimplemented
486 */
487 BOOL STDCALL
488 StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
489 {
490 ULONG i;
491 HANDLE hPipe;
492 DWORD dwError;
493 PUCHAR lpMessageBuffer;
494
495 DPRINT("StartServiceCtrlDispatcherA() called\n");
496
497 i = 0;
498 while (lpServiceStartTable[i].lpServiceProc != NULL)
499 {
500 i++;
501 }
502
503 dwActiveServiceCount = i;
504 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
505 HEAP_ZERO_MEMORY,
506 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
507 if (lpActiveServices == NULL)
508 {
509 return FALSE;
510 }
511
512 /* Copy service names and start procedure */
513 for (i = 0; i < dwActiveServiceCount; i++)
514 {
515 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
516 lpServiceStartTable[i].lpServiceName);
517 lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
518 lpActiveServices[i].bUnicode = FALSE;
519 }
520
521 dwError = ScConnectControlPipe(&hPipe);
522 if (dwError != ERROR_SUCCESS)
523 {
524 /* Free the service table */
525 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
526 lpActiveServices = NULL;
527 dwActiveServiceCount = 0;
528 return FALSE;
529 }
530
531 lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
532 HEAP_ZERO_MEMORY,
533 256);
534 if (lpMessageBuffer == NULL)
535 {
536 /* Free the service table */
537 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
538 lpActiveServices = NULL;
539 dwActiveServiceCount = 0;
540 CloseHandle(hPipe);
541 return FALSE;
542 }
543
544 ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
545 CloseHandle(hPipe);
546
547 /* Free the message buffer */
548 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
549
550 /* Free the service table */
551 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
552 lpActiveServices = NULL;
553 dwActiveServiceCount = 0;
554
555 return TRUE;
556 }
557
558
559 /**********************************************************************
560 * StartServiceCtrlDispatcherW
561 *
562 * @unimplemented
563 */
564 BOOL STDCALL
565 StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
566 {
567 ULONG i;
568 HANDLE hPipe;
569 DWORD dwError;
570 PUCHAR lpMessageBuffer;
571
572 DPRINT("StartServiceCtrlDispatcherW() called\n");
573
574 i = 0;
575 while (lpServiceStartTable[i].lpServiceProc != NULL)
576 {
577 i++;
578 }
579
580 dwActiveServiceCount = i;
581 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
582 HEAP_ZERO_MEMORY,
583 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
584 if (lpActiveServices == NULL)
585 {
586 return FALSE;
587 }
588
589 /* Copy service names and start procedure */
590 for (i = 0; i < dwActiveServiceCount; i++)
591 {
592 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
593 lpServiceStartTable[i].lpServiceName);
594 lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
595 lpActiveServices[i].bUnicode = TRUE;
596 }
597
598 dwError = ScConnectControlPipe(&hPipe);
599 if (dwError != ERROR_SUCCESS)
600 {
601 /* Free the service table */
602 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
603 lpActiveServices = NULL;
604 dwActiveServiceCount = 0;
605 return FALSE;
606 }
607
608 lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
609 HEAP_ZERO_MEMORY,
610 256);
611 if (lpMessageBuffer == NULL)
612 {
613 /* Free the service table */
614 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
615 lpActiveServices = NULL;
616 dwActiveServiceCount = 0;
617 CloseHandle(hPipe);
618 return FALSE;
619 }
620
621 ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
622 CloseHandle(hPipe);
623
624 /* Free the message buffer */
625 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
626
627 /* Free the service table */
628 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
629 lpActiveServices = NULL;
630 dwActiveServiceCount = 0;
631
632 return TRUE;
633 }
634
635 /* EOF */