Bring back ext2 code from branch
[reactos.git] / reactos / dll / win32 / advapi32 / service / sctrl.c
1 /*
2 * PROJECT: ReactOS advapi32
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/advapi32/service/sctrl.c
5 * PURPOSE: Service control manager functions
6 * COPYRIGHT: Copyright 1999 Emanuele Aliberti
7 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
8 * Gregor Brunmar <gregor.brunmar@home.se>
9 *
10 */
11
12
13 /* INCLUDES ******************************************************************/
14
15 #include <advapi32.h>
16 #include "wine/debug.h"
17
18 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
19
20
21 /* TYPES *********************************************************************/
22
23 VOID HandleBind(VOID);
24
25 typedef struct _ACTIVE_SERVICE
26 {
27 CLIENT_HANDLE hService;
28 UNICODE_STRING ServiceName;
29 union
30 {
31 LPSERVICE_MAIN_FUNCTIONA lpFuncA;
32 LPSERVICE_MAIN_FUNCTIONW lpFuncW;
33 } Main;
34 LPHANDLER_FUNCTION HandlerFunction;
35 LPHANDLER_FUNCTION_EX HandlerFunctionEx;
36 LPVOID HandlerContext;
37 SERVICE_STATUS ServiceStatus;
38 BOOL bUnicode;
39 LPWSTR Arguments;
40 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
41
42
43 /* GLOBALS *******************************************************************/
44
45 extern handle_t BindingHandle;
46 static DWORD dwActiveServiceCount = 0;
47 static PACTIVE_SERVICE lpActiveServices = NULL;
48
49
50 /* FUNCTIONS *****************************************************************/
51
52 static PACTIVE_SERVICE
53 ScLookupServiceByServiceName(LPCWSTR lpServiceName)
54 {
55 DWORD i;
56
57 for (i = 0; i < dwActiveServiceCount; i++)
58 {
59 if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
60 {
61 return &lpActiveServices[i];
62 }
63 }
64
65 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
66
67 return NULL;
68 }
69
70
71 static DWORD WINAPI
72 ScServiceMainStub(LPVOID Context)
73 {
74 PACTIVE_SERVICE lpService;
75 DWORD dwArgCount = 0;
76 DWORD dwLength = 0;
77 DWORD dwLen;
78 LPWSTR lpPtr;
79
80 lpService = (PACTIVE_SERVICE)Context;
81
82 TRACE("ScServiceMainStub() called\n");
83
84 /* Count arguments */
85 lpPtr = lpService->Arguments;
86 while (*lpPtr)
87 {
88 TRACE("arg: %S\n", lpPtr);
89 dwLen = wcslen(lpPtr) + 1;
90 dwArgCount++;
91 dwLength += dwLen;
92 lpPtr += dwLen;
93 }
94 TRACE("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount, dwLength);
95
96 /* Build the argument vector and call the main service routine */
97 if (lpService->bUnicode)
98 {
99 LPWSTR *lpArgVector;
100 LPWSTR Ptr;
101
102 lpArgVector = HeapAlloc(GetProcessHeap(),
103 HEAP_ZERO_MEMORY,
104 (dwArgCount + 1) * sizeof(LPWSTR));
105 if (lpArgVector == NULL)
106 return ERROR_OUTOFMEMORY;
107
108 dwArgCount = 0;
109 Ptr = lpService->Arguments;
110 while (*Ptr)
111 {
112 lpArgVector[dwArgCount] = Ptr;
113
114 dwArgCount++;
115 Ptr += (wcslen(Ptr) + 1);
116 }
117 lpArgVector[dwArgCount] = NULL;
118
119 (lpService->Main.lpFuncW)(dwArgCount, lpArgVector);
120
121 HeapFree(GetProcessHeap(),
122 0,
123 lpArgVector);
124 }
125 else
126 {
127 LPSTR *lpArgVector;
128 LPSTR Ptr;
129 LPSTR AnsiString;
130 DWORD AnsiLength;
131
132 AnsiLength = WideCharToMultiByte(CP_ACP,
133 0,
134 lpService->Arguments,
135 dwLength,
136 NULL,
137 0,
138 NULL,
139 NULL);
140 if (AnsiLength == 0)
141 return ERROR_INVALID_PARAMETER; /* ? */
142
143 AnsiString = HeapAlloc(GetProcessHeap(),
144 0,
145 AnsiLength + 1);
146 if (AnsiString == NULL)
147 return ERROR_OUTOFMEMORY;
148
149 WideCharToMultiByte(CP_ACP,
150 0,
151 lpService->Arguments,
152 dwLength,
153 AnsiString,
154 AnsiLength,
155 NULL,
156 NULL);
157
158 AnsiString[AnsiLength] = ANSI_NULL;
159
160 lpArgVector = HeapAlloc(GetProcessHeap(),
161 0,
162 (dwArgCount + 1) * sizeof(LPSTR));
163 if (lpArgVector == NULL)
164 {
165 HeapFree(GetProcessHeap(),
166 0,
167 AnsiString);
168 return ERROR_OUTOFMEMORY;
169 }
170
171 dwArgCount = 0;
172 Ptr = AnsiString;
173 while (*Ptr)
174 {
175 lpArgVector[dwArgCount] = Ptr;
176
177 dwArgCount++;
178 Ptr += (strlen(Ptr) + 1);
179 }
180 lpArgVector[dwArgCount] = NULL;
181
182 (lpService->Main.lpFuncA)(dwArgCount, lpArgVector);
183
184 HeapFree(GetProcessHeap(),
185 0,
186 lpArgVector);
187 HeapFree(GetProcessHeap(),
188 0,
189 AnsiString);
190 }
191
192 return ERROR_SUCCESS;
193 }
194
195
196 static DWORD
197 ScConnectControlPipe(HANDLE *hPipe)
198 {
199 DWORD dwBytesWritten;
200 DWORD dwState;
201 DWORD dwServiceCurrent = 0;
202 NTSTATUS Status;
203 WCHAR NtControlPipeName[MAX_PATH + 1];
204 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
205
206 /* Get the service number and create the named pipe */
207 RtlZeroMemory(&QueryTable,
208 sizeof(QueryTable));
209
210 QueryTable[0].Name = L"";
211 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
212 QueryTable[0].EntryContext = &dwServiceCurrent;
213
214 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
215 L"ServiceCurrent",
216 QueryTable,
217 NULL,
218 NULL);
219
220 if (!NT_SUCCESS(Status))
221 {
222 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
223 return RtlNtStatusToDosError(Status);
224 }
225
226 swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent);
227
228 if (!WaitNamedPipeW(NtControlPipeName, 15000))
229 {
230 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError());
231 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
232 }
233
234 *hPipe = CreateFileW(NtControlPipeName,
235 GENERIC_READ | GENERIC_WRITE,
236 0,
237 NULL,
238 OPEN_EXISTING,
239 FILE_ATTRIBUTE_NORMAL,
240 NULL);
241 if (*hPipe == INVALID_HANDLE_VALUE)
242 {
243 ERR("CreateFileW() failed (Error %lu)\n", GetLastError());
244 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
245 }
246
247 dwState = PIPE_READMODE_MESSAGE;
248 if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
249 {
250 CloseHandle(*hPipe);
251 *hPipe = INVALID_HANDLE_VALUE;
252 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
253 }
254
255 /* Share the SERVICE_HANDLE handle with the SCM */
256 WriteFile(*hPipe,
257 (DWORD *)&lpActiveServices->hService,
258 sizeof(CLIENT_HANDLE),
259 &dwBytesWritten,
260 NULL);
261
262 TRACE("Sent SERVICE_HANDLE %lu\n", lpActiveServices->hService);
263
264 return ERROR_SUCCESS;
265 }
266
267
268 static DWORD
269 ScStartService(PSCM_CONTROL_PACKET ControlPacket)
270 {
271 PACTIVE_SERVICE lpService;
272 HANDLE ThreadHandle;
273 DWORD ThreadId;
274
275 TRACE("ScStartService() called\n");
276 TRACE("client handle: %lu\n", ControlPacket->hClient);
277 TRACE("Size: %lu\n", ControlPacket->dwSize);
278 TRACE("Service: %S\n", &ControlPacket->szArguments[0]);
279
280 lpService = (PACTIVE_SERVICE)ControlPacket->hClient;
281 if (lpService == NULL)
282 {
283 TRACE("Service not found\n");
284 return ERROR_SERVICE_DOES_NOT_EXIST;
285 }
286
287 lpService->Arguments = HeapAlloc(GetProcessHeap(),
288 HEAP_ZERO_MEMORY,
289 ControlPacket->dwSize * sizeof(WCHAR));
290 if (lpService->Arguments == NULL)
291 return ERROR_OUTOFMEMORY;
292
293 memcpy(lpService->Arguments,
294 ControlPacket->szArguments,
295 ControlPacket->dwSize * sizeof(WCHAR));
296
297 /* invoke the services entry point and implement the command loop */
298 ThreadHandle = CreateThread(NULL,
299 0,
300 ScServiceMainStub,
301 lpService,
302 CREATE_SUSPENDED,
303 &ThreadId);
304 if (ThreadHandle == NULL)
305 return ERROR_SERVICE_NO_THREAD;
306
307 ResumeThread(ThreadHandle);
308 CloseHandle(ThreadHandle);
309
310 return ERROR_SUCCESS;
311 }
312
313
314 static DWORD
315 ScControlService(PSCM_CONTROL_PACKET ControlPacket)
316 {
317 PACTIVE_SERVICE lpService;
318
319 TRACE("ScControlService() called\n");
320 TRACE("Size: %lu\n", ControlPacket->dwSize);
321 TRACE("Service: %S\n", &ControlPacket->szArguments[0]);
322
323 lpService = (PACTIVE_SERVICE)ControlPacket->hClient;
324 if (lpService == NULL)
325 {
326 TRACE("Service not found\n");
327 return ERROR_SERVICE_DOES_NOT_EXIST;
328 }
329
330 if (lpService->HandlerFunction)
331 {
332 (lpService->HandlerFunction)(ControlPacket->dwControl);
333 }
334 else if (lpService->HandlerFunctionEx)
335 {
336 /* FIXME: send correct params */
337 (lpService->HandlerFunctionEx)(ControlPacket->dwControl, 0, NULL, NULL);
338 }
339
340 if (ControlPacket->dwControl == SERVICE_CONTROL_STOP)
341 {
342 HeapFree(GetProcessHeap(),
343 0,
344 lpService->Arguments);
345 }
346
347 TRACE("ScControlService() done\n");
348
349 return ERROR_SUCCESS;
350 }
351
352
353 static BOOL
354 ScServiceDispatcher(HANDLE hPipe,
355 PUCHAR lpBuffer,
356 DWORD dwBufferSize)
357 {
358 PSCM_CONTROL_PACKET ControlPacket;
359 DWORD Count;
360 BOOL bResult;
361 DWORD dwRunningServices = 0;
362
363 TRACE("ScDispatcherLoop() called\n");
364
365 ControlPacket = HeapAlloc(GetProcessHeap(),
366 HEAP_ZERO_MEMORY,
367 1024);
368 if (ControlPacket == NULL)
369 return FALSE;
370
371 while (TRUE)
372 {
373 /* Read command from the control pipe */
374 bResult = ReadFile(hPipe,
375 ControlPacket,
376 1024,
377 &Count,
378 NULL);
379 if (bResult == FALSE)
380 {
381 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
382 return FALSE;
383 }
384
385 /* Execute command */
386 switch (ControlPacket->dwControl)
387 {
388 case SERVICE_CONTROL_START:
389 TRACE("Start command - recieved SERVICE_CONTROL_START\n");
390 if (ScStartService(ControlPacket) == ERROR_SUCCESS)
391 dwRunningServices++;
392 break;
393
394 case SERVICE_CONTROL_STOP:
395 TRACE("Stop command - recieved SERVICE_CONTROL_STOP\n");
396 if (ScControlService(ControlPacket) == ERROR_SUCCESS)
397 dwRunningServices--;
398 break;
399
400 default:
401 TRACE("Unknown command %lu", ControlPacket->dwControl);
402 continue;
403 }
404
405 if (dwRunningServices == 0)
406 break;
407 }
408
409 HeapFree(GetProcessHeap(),
410 0,
411 ControlPacket);
412
413 return TRUE;
414 }
415
416
417 /**********************************************************************
418 * RegisterServiceCtrlHandlerA
419 *
420 * @implemented
421 */
422 SERVICE_STATUS_HANDLE STDCALL
423 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
424 LPHANDLER_FUNCTION lpHandlerProc)
425 {
426 ANSI_STRING ServiceNameA;
427 UNICODE_STRING ServiceNameU;
428 SERVICE_STATUS_HANDLE SHandle;
429
430 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
431 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
432 {
433 SetLastError(ERROR_OUTOFMEMORY);
434 return (SERVICE_STATUS_HANDLE)0;
435 }
436
437 SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
438 lpHandlerProc);
439
440 RtlFreeUnicodeString(&ServiceNameU);
441
442 return SHandle;
443 }
444
445
446 /**********************************************************************
447 * RegisterServiceCtrlHandlerW
448 *
449 * @implemented
450 */
451 SERVICE_STATUS_HANDLE STDCALL
452 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
453 LPHANDLER_FUNCTION lpHandlerProc)
454 {
455 PACTIVE_SERVICE Service;
456
457 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
458 if (Service == NULL)
459 {
460 return (SERVICE_STATUS_HANDLE)NULL;
461 }
462
463 Service->HandlerFunction = lpHandlerProc;
464 Service->HandlerFunctionEx = NULL;
465
466 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service->hService);
467
468 return (SERVICE_STATUS_HANDLE)Service->hService;
469 }
470
471
472 /**********************************************************************
473 * RegisterServiceCtrlHandlerExA
474 *
475 * @implemented
476 */
477 SERVICE_STATUS_HANDLE STDCALL
478 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
479 LPHANDLER_FUNCTION_EX lpHandlerProc,
480 LPVOID lpContext)
481 {
482 ANSI_STRING ServiceNameA;
483 UNICODE_STRING ServiceNameU;
484 SERVICE_STATUS_HANDLE SHandle;
485
486 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
487 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
488 {
489 SetLastError(ERROR_OUTOFMEMORY);
490 return (SERVICE_STATUS_HANDLE)0;
491 }
492
493 SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
494 lpHandlerProc,
495 lpContext);
496
497 RtlFreeUnicodeString(&ServiceNameU);
498
499 return SHandle;
500 }
501
502
503 /**********************************************************************
504 * RegisterServiceCtrlHandlerExW
505 *
506 * @implemented
507 */
508 SERVICE_STATUS_HANDLE STDCALL
509 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
510 LPHANDLER_FUNCTION_EX lpHandlerProc,
511 LPVOID lpContext)
512 {
513 PACTIVE_SERVICE Service;
514
515 Service = ScLookupServiceByServiceName(lpServiceName);
516 if (Service == NULL)
517 {
518 return (SERVICE_STATUS_HANDLE)NULL;
519 }
520
521 Service->HandlerFunction = NULL;
522 Service->HandlerFunctionEx = lpHandlerProc;
523 Service->HandlerContext = lpContext;
524
525 TRACE("RegisterServiceCtrlHandlerEx returning %lu", Service->hService);
526
527 return (SERVICE_STATUS_HANDLE)Service->hService;
528 }
529
530
531 /**********************************************************************
532 * SetServiceBits
533 *
534 * @unimplemented
535 */
536 BOOL STDCALL
537 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
538 DWORD dwServiceBits,
539 BOOL bSetBitsOn,
540 BOOL bUpdateImmediately)
541 {
542 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
543 return FALSE;
544 }
545
546
547 /**********************************************************************
548 * SetServiceStatus
549 *
550 * @implemented
551 */
552 BOOL STDCALL
553 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
554 LPSERVICE_STATUS lpServiceStatus)
555 {
556 DWORD dwError;
557
558 TRACE("SetServiceStatus() called\n");
559 TRACE("hServiceStatus %lu\n", hServiceStatus);
560
561 HandleBind();
562
563 /* Call to services.exe using RPC */
564 dwError = ScmrSetServiceStatus(BindingHandle,
565 (unsigned long)hServiceStatus,
566 lpServiceStatus);
567 if (dwError != ERROR_SUCCESS)
568 {
569 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError);
570 SetLastError(dwError);
571 return FALSE;
572 }
573
574 TRACE("SetServiceStatus() done (ret %lu)\n", dwError);
575
576 return TRUE;
577 }
578
579
580 /**********************************************************************
581 * StartServiceCtrlDispatcherA
582 *
583 * @implemented
584 */
585 BOOL STDCALL
586 StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
587 {
588 ULONG i;
589 HANDLE hPipe;
590 DWORD dwError;
591 PUCHAR lpMessageBuffer;
592
593 TRACE("StartServiceCtrlDispatcherA() called\n");
594
595 i = 0;
596 while (lpServiceStartTable[i].lpServiceProc != NULL)
597 {
598 i++;
599 }
600
601 dwActiveServiceCount = i;
602 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
603 HEAP_ZERO_MEMORY,
604 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
605 if (lpActiveServices == NULL)
606 {
607 return FALSE;
608 }
609
610 /* Copy service names and start procedure */
611 for (i = 0; i < dwActiveServiceCount; i++)
612 {
613 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
614 lpServiceStartTable[i].lpServiceName);
615 lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
616 lpActiveServices[i].hService = (CLIENT_HANDLE)&lpActiveServices[i];
617 lpActiveServices[i].bUnicode = FALSE;
618 }
619
620 dwError = ScConnectControlPipe(&hPipe);
621 if (dwError != ERROR_SUCCESS)
622 {
623 /* Free the service table */
624 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
625 lpActiveServices = NULL;
626 dwActiveServiceCount = 0;
627 return FALSE;
628 }
629
630 lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
631 HEAP_ZERO_MEMORY,
632 256);
633 if (lpMessageBuffer == NULL)
634 {
635 /* Free the service table */
636 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
637 lpActiveServices = NULL;
638 dwActiveServiceCount = 0;
639 CloseHandle(hPipe);
640 return FALSE;
641 }
642
643 ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
644 CloseHandle(hPipe);
645
646 /* Free the message buffer */
647 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
648
649 /* Free the service table */
650 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
651 lpActiveServices = NULL;
652 dwActiveServiceCount = 0;
653
654 return TRUE;
655 }
656
657
658 /**********************************************************************
659 * StartServiceCtrlDispatcherW
660 *
661 * @implemented
662 */
663 BOOL STDCALL
664 StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
665 {
666 ULONG i;
667 HANDLE hPipe;
668 DWORD dwError;
669 PUCHAR lpMessageBuffer;
670
671 TRACE("StartServiceCtrlDispatcherW() called\n");
672
673 i = 0;
674 while (lpServiceStartTable[i].lpServiceProc != NULL)
675 {
676 i++;
677 }
678
679 dwActiveServiceCount = i;
680 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
681 HEAP_ZERO_MEMORY,
682 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
683 if (lpActiveServices == NULL)
684 {
685 return FALSE;
686 }
687
688 /* Copy service names and start procedure */
689 for (i = 0; i < dwActiveServiceCount; i++)
690 {
691 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
692 lpServiceStartTable[i].lpServiceName);
693 lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
694 lpActiveServices[i].hService = (CLIENT_HANDLE)&lpActiveServices[i];
695 lpActiveServices[i].bUnicode = TRUE;
696 }
697
698 dwError = ScConnectControlPipe(&hPipe);
699 if (dwError != ERROR_SUCCESS)
700 {
701 /* Free the service table */
702 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
703 lpActiveServices = NULL;
704 dwActiveServiceCount = 0;
705 return FALSE;
706 }
707
708 lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
709 HEAP_ZERO_MEMORY,
710 256);
711 if (lpMessageBuffer == NULL)
712 {
713 /* Free the service table */
714 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
715 lpActiveServices = NULL;
716 dwActiveServiceCount = 0;
717 CloseHandle(hPipe);
718 return FALSE;
719 }
720
721 ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
722 CloseHandle(hPipe);
723
724 /* Free the message buffer */
725 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
726
727 /* Free the service table */
728 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
729 lpActiveServices = NULL;
730 dwActiveServiceCount = 0;
731
732 return TRUE;
733 }
734
735 /* EOF */