xref: /reactos/dll/win32/advapi32/service/sctrl.c (revision a6726659)
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 /* INCLUDES ******************************************************************/
13 
14 #include <advapi32.h>
15 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
16 
17 
18 /* TYPES *********************************************************************/
19 
20 typedef struct _SERVICE_THREAD_PARAMSA
21 {
22     LPSERVICE_MAIN_FUNCTIONA lpServiceMain;
23     DWORD dwArgCount;
24     LPSTR *lpArgVector;
25     DWORD dwServiceTag;
26 } SERVICE_THREAD_PARAMSA, *PSERVICE_THREAD_PARAMSA;
27 
28 
29 typedef struct _SERVICE_THREAD_PARAMSW
30 {
31     LPSERVICE_MAIN_FUNCTIONW lpServiceMain;
32     DWORD dwArgCount;
33     LPWSTR *lpArgVector;
34     DWORD dwServiceTag;
35 } SERVICE_THREAD_PARAMSW, *PSERVICE_THREAD_PARAMSW;
36 
37 
38 typedef struct _ACTIVE_SERVICE
39 {
40     SERVICE_STATUS_HANDLE hServiceStatus;
41     UNICODE_STRING ServiceName;
42     union
43     {
44         LPSERVICE_MAIN_FUNCTIONA A;
45         LPSERVICE_MAIN_FUNCTIONW W;
46     } ServiceMain;
47     LPHANDLER_FUNCTION HandlerFunction;
48     LPHANDLER_FUNCTION_EX HandlerFunctionEx;
49     LPVOID HandlerContext;
50     BOOL bUnicode;
51     BOOL bOwnProcess;
52     DWORD dwServiceTag;
53 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
54 
55 
56 /* GLOBALS *******************************************************************/
57 
58 static DWORD dwActiveServiceCount = 0;
59 static PACTIVE_SERVICE lpActiveServices = NULL;
60 static handle_t hStatusBinding = NULL;
61 
62 
63 /* FUNCTIONS *****************************************************************/
64 
65 handle_t __RPC_USER
66 RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus)
67 {
68     return hStatusBinding;
69 }
70 
71 
72 void __RPC_USER
73 RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus,
74                                  handle_t hBinding)
75 {
76 }
77 
78 
79 static RPC_STATUS
80 ScCreateStatusBinding(VOID)
81 {
82     LPWSTR pszStringBinding;
83     RPC_STATUS status;
84 
85     TRACE("ScCreateStatusBinding()\n");
86 
87     status = RpcStringBindingComposeW(NULL,
88                                       L"ncacn_np",
89                                       NULL,
90                                       L"\\pipe\\ntsvcs",
91                                       NULL,
92                                       &pszStringBinding);
93     if (status != RPC_S_OK)
94     {
95         ERR("RpcStringBindingCompose returned 0x%x\n", status);
96         return status;
97     }
98 
99     /* Set the binding handle that will be used to bind to the server. */
100     status = RpcBindingFromStringBindingW(pszStringBinding,
101                                           &hStatusBinding);
102     if (status != RPC_S_OK)
103     {
104         ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
105     }
106 
107     status = RpcStringFreeW(&pszStringBinding);
108     if (status != RPC_S_OK)
109     {
110         ERR("RpcStringFree returned 0x%x\n", status);
111     }
112 
113     return status;
114 }
115 
116 
117 static RPC_STATUS
118 ScDestroyStatusBinding(VOID)
119 {
120     RPC_STATUS status;
121 
122     TRACE("ScDestroyStatusBinding()\n");
123 
124     if (hStatusBinding == NULL)
125         return RPC_S_OK;
126 
127     status = RpcBindingFree(&hStatusBinding);
128     if (status != RPC_S_OK)
129     {
130         ERR("RpcBindingFree returned 0x%x\n", status);
131     }
132     else
133     {
134         hStatusBinding = NULL;
135     }
136 
137     return status;
138 }
139 
140 
141 static PACTIVE_SERVICE
142 ScLookupServiceByServiceName(LPCWSTR lpServiceName)
143 {
144     DWORD i;
145 
146     TRACE("ScLookupServiceByServiceName(%S)\n",
147           lpServiceName);
148 
149     if (lpActiveServices[0].bOwnProcess)
150         return &lpActiveServices[0];
151 
152     for (i = 0; i < dwActiveServiceCount; i++)
153     {
154         TRACE("Checking %S\n", lpActiveServices[i].ServiceName.Buffer);
155         if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
156         {
157             TRACE("Found!\n");
158             return &lpActiveServices[i];
159         }
160     }
161 
162     TRACE("No service found!\n");
163     return NULL;
164 }
165 
166 
167 static DWORD WINAPI
168 ScServiceMainStubA(LPVOID Context)
169 {
170     PTEB Teb;
171     PSERVICE_THREAD_PARAMSA ThreadParams = Context;
172 
173     TRACE("ScServiceMainStubA(%p)\n", Context);
174 
175     /* Set service tag */
176     Teb = NtCurrentTeb();
177     Teb->SubProcessTag = UlongToPtr(ThreadParams->dwServiceTag);
178 
179     /* Call the main service routine and free the arguments vector */
180     (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount,
181                                   ThreadParams->lpArgVector);
182 
183     /* Reset service tag */
184     Teb->SubProcessTag = 0;
185 
186     if (ThreadParams->lpArgVector != NULL)
187     {
188         HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector);
189     }
190     HeapFree(GetProcessHeap(), 0, ThreadParams);
191 
192     return ERROR_SUCCESS;
193 }
194 
195 
196 static DWORD WINAPI
197 ScServiceMainStubW(LPVOID Context)
198 {
199     PTEB Teb;
200     PSERVICE_THREAD_PARAMSW ThreadParams = Context;
201 
202     TRACE("ScServiceMainStubW(%p)\n", Context);
203 
204     /* Set service tag */
205     Teb = NtCurrentTeb();
206     Teb->SubProcessTag = UlongToPtr(ThreadParams->dwServiceTag);
207 
208     /* Call the main service routine and free the arguments vector */
209     (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount,
210                                   ThreadParams->lpArgVector);
211 
212     /* Reset service tag */
213     Teb->SubProcessTag = 0;
214 
215     if (ThreadParams->lpArgVector != NULL)
216     {
217         HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector);
218     }
219     HeapFree(GetProcessHeap(), 0, ThreadParams);
220 
221     return ERROR_SUCCESS;
222 }
223 
224 
225 static DWORD
226 ScConnectControlPipe(HANDLE *hPipe)
227 {
228     DWORD dwBytesWritten;
229     DWORD dwState;
230     DWORD dwServiceCurrent = 0;
231     NTSTATUS Status;
232     WCHAR NtControlPipeName[MAX_PATH + 1];
233     RTL_QUERY_REGISTRY_TABLE QueryTable[2];
234     DWORD dwProcessId;
235 
236     TRACE("ScConnectControlPipe(%p)\n",
237           hPipe);
238 
239     /* Get the service number and create the named pipe */
240     RtlZeroMemory(&QueryTable,
241                   sizeof(QueryTable));
242 
243     QueryTable[0].Name = L"";
244     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
245     QueryTable[0].EntryContext = &dwServiceCurrent;
246 
247     Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
248                                     L"ServiceCurrent",
249                                     QueryTable,
250                                     NULL,
251                                     NULL);
252     if (!NT_SUCCESS(Status))
253     {
254         ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
255         return RtlNtStatusToDosError(Status);
256     }
257 
258     swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent);
259 
260     if (!WaitNamedPipeW(NtControlPipeName, 30000))
261     {
262         ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError());
263         return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
264     }
265 
266     *hPipe = CreateFileW(NtControlPipeName,
267                          GENERIC_READ | GENERIC_WRITE,
268                          FILE_SHARE_READ | FILE_SHARE_WRITE,
269                          NULL,
270                          OPEN_EXISTING,
271                          FILE_ATTRIBUTE_NORMAL,
272                          NULL);
273     if (*hPipe == INVALID_HANDLE_VALUE)
274     {
275         ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName, GetLastError());
276         return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
277     }
278 
279     dwState = PIPE_READMODE_MESSAGE;
280     if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
281     {
282         CloseHandle(*hPipe);
283         *hPipe = INVALID_HANDLE_VALUE;
284         return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
285     }
286 
287     /* Pass the ProcessId to the SCM */
288     dwProcessId = GetCurrentProcessId();
289     WriteFile(*hPipe,
290               &dwProcessId,
291               sizeof(dwProcessId),
292               &dwBytesWritten,
293               NULL);
294 
295     TRACE("Sent Process ID %lu\n", dwProcessId);
296 
297     return ERROR_SUCCESS;
298 }
299 
300 
301 /*
302  * Ansi/Unicode argument layout of the vector passed to a service at startup,
303  * depending on the different versions of Windows considered:
304  *
305  * - XP/2003:
306  *   [argv array of pointers][parameter 1][parameter 2]...[service name]
307  *
308  * - Vista:
309  *   [argv array of pointers][align to 8 bytes]
310  *   [parameter 1][parameter 2]...[service name]
311  *
312  * - Win7/8:
313  *   [argv array of pointers][service name]
314  *   [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]...
315  *
316  * Space for parameters and service name is always enough to store
317  * both the Ansi and the Unicode versions including NULL terminator.
318  */
319 
320 static DWORD
321 ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket,
322                          LPDWORD lpArgCount,
323                          LPWSTR **lpArgVector)
324 {
325     PWSTR *lpVector;
326     PWSTR pszServiceName;
327     DWORD cbServiceName;
328     DWORD cbArguments;
329     DWORD cbTotal;
330     DWORD i;
331 
332     if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
333         return ERROR_INVALID_PARAMETER;
334 
335     *lpArgCount  = 0;
336     *lpArgVector = NULL;
337 
338     /* Retrieve and count the start command line (NULL-terminated) */
339     pszServiceName = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
340     cbServiceName  = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
341 
342     /*
343      * The total size of the argument vector is equal to the entry for
344      * the service name, plus the size of the original argument vector.
345      */
346     cbTotal = sizeof(PWSTR) + cbServiceName;
347     if (ControlPacket->dwArgumentsCount > 0)
348         cbArguments = ControlPacket->dwSize - ControlPacket->dwArgumentsOffset;
349     else
350         cbArguments = 0;
351     cbTotal += cbArguments;
352 
353     /* Allocate the new argument vector */
354     lpVector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTotal);
355     if (lpVector == NULL)
356         return ERROR_NOT_ENOUGH_MEMORY;
357 
358     /*
359      * The first argument is reserved for the service name, which
360      * will be appended to the end of the argument string list.
361      */
362 
363     /* Copy the remaining arguments */
364     if (ControlPacket->dwArgumentsCount > 0)
365     {
366         memcpy(&lpVector[1],
367                (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwArgumentsOffset),
368                cbArguments);
369 
370         for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
371         {
372             lpVector[i + 1] = (PWSTR)((ULONG_PTR)&lpVector[1] + (ULONG_PTR)lpVector[i + 1]);
373             TRACE("Unicode lpVector[%lu] = '%ls'\n", i + 1, lpVector[i + 1]);
374         }
375     }
376 
377     /* Now copy the service name */
378     lpVector[0] = (PWSTR)((ULONG_PTR)&lpVector[1] + cbArguments);
379     memcpy(lpVector[0], pszServiceName, cbServiceName);
380     TRACE("Unicode lpVector[%lu] = '%ls'\n", 0, lpVector[0]);
381 
382     *lpArgCount  = ControlPacket->dwArgumentsCount + 1;
383     *lpArgVector = lpVector;
384 
385     return ERROR_SUCCESS;
386 }
387 
388 
389 static DWORD
390 ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket,
391                       LPDWORD lpArgCount,
392                       LPSTR **lpArgVector)
393 {
394     DWORD dwError;
395     NTSTATUS Status;
396     DWORD ArgCount, i;
397     PWSTR *lpVectorW;
398     PSTR  *lpVectorA;
399     UNICODE_STRING UnicodeString;
400     ANSI_STRING AnsiString;
401 
402     if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
403         return ERROR_INVALID_PARAMETER;
404 
405     *lpArgCount  = 0;
406     *lpArgVector = NULL;
407 
408     /* Build the UNICODE arguments vector */
409     dwError = ScBuildUnicodeArgsVector(ControlPacket, &ArgCount, &lpVectorW);
410     if (dwError != ERROR_SUCCESS)
411         return dwError;
412 
413     /* Convert the vector to ANSI in place */
414     lpVectorA = (PSTR*)lpVectorW;
415     for (i = 0; i < ArgCount; i++)
416     {
417         RtlInitUnicodeString(&UnicodeString, lpVectorW[i]);
418         RtlInitEmptyAnsiString(&AnsiString, lpVectorA[i], UnicodeString.MaximumLength);
419         Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
420         if (!NT_SUCCESS(Status))
421         {
422             /* Failed to convert to ANSI; free the allocated vector and return */
423             dwError = RtlNtStatusToDosError(Status);
424             HeapFree(GetProcessHeap(), 0, lpVectorW);
425             return dwError;
426         }
427 
428         /* NULL-terminate the string */
429         AnsiString.Buffer[AnsiString.Length / sizeof(CHAR)] = ANSI_NULL;
430 
431         TRACE("Ansi lpVector[%lu] = '%s'\n", i, lpVectorA[i]);
432     }
433 
434     *lpArgCount  = ArgCount;
435     *lpArgVector = lpVectorA;
436 
437     return ERROR_SUCCESS;
438 }
439 
440 
441 static DWORD
442 ScStartService(PACTIVE_SERVICE lpService,
443                PSCM_CONTROL_PACKET ControlPacket)
444 {
445     HANDLE ThreadHandle;
446     DWORD ThreadId;
447     DWORD dwError;
448     PSERVICE_THREAD_PARAMSA ThreadParamsA;
449     PSERVICE_THREAD_PARAMSW ThreadParamsW;
450 
451     TRACE("ScStartService(%p %p)\n",
452           lpService, ControlPacket);
453 
454     if (lpService == NULL || ControlPacket == NULL)
455         return ERROR_INVALID_PARAMETER;
456 
457     TRACE("Size: %lu\n", ControlPacket->dwSize);
458     TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset));
459 
460     /* Set the service status handle */
461     lpService->hServiceStatus = ControlPacket->hServiceStatus;
462     /* Set the service tag */
463     lpService->dwServiceTag = ControlPacket->dwServiceTag;
464 
465     /* Build the arguments vector */
466     if (lpService->bUnicode != FALSE)
467     {
468         ThreadParamsW = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsW));
469         if (ThreadParamsW == NULL)
470             return ERROR_NOT_ENOUGH_MEMORY;
471         dwError = ScBuildUnicodeArgsVector(ControlPacket,
472                                            &ThreadParamsW->dwArgCount,
473                                            &ThreadParamsW->lpArgVector);
474         if (dwError != ERROR_SUCCESS)
475         {
476             HeapFree(GetProcessHeap(), 0, ThreadParamsW);
477             return dwError;
478         }
479         ThreadParamsW->lpServiceMain = lpService->ServiceMain.W;
480         ThreadParamsW->dwServiceTag = ControlPacket->dwServiceTag;
481         ThreadHandle = CreateThread(NULL,
482                                     0,
483                                     ScServiceMainStubW,
484                                     ThreadParamsW,
485                                     0,
486                                     &ThreadId);
487         if (ThreadHandle == NULL)
488         {
489             if (ThreadParamsW->lpArgVector != NULL)
490             {
491                 HeapFree(GetProcessHeap(), 0, ThreadParamsW->lpArgVector);
492             }
493             HeapFree(GetProcessHeap(), 0, ThreadParamsW);
494 
495             return ERROR_SERVICE_NO_THREAD;
496         }
497 
498         CloseHandle(ThreadHandle);
499     }
500     else
501     {
502         ThreadParamsA = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA));
503         if (ThreadParamsA == NULL)
504             return ERROR_NOT_ENOUGH_MEMORY;
505         dwError = ScBuildAnsiArgsVector(ControlPacket,
506                                         &ThreadParamsA->dwArgCount,
507                                         &ThreadParamsA->lpArgVector);
508         if (dwError != ERROR_SUCCESS)
509         {
510             HeapFree(GetProcessHeap(), 0, ThreadParamsA);
511             return dwError;
512         }
513         ThreadParamsA->lpServiceMain = lpService->ServiceMain.A;
514         ThreadParamsA->dwServiceTag = ControlPacket->dwServiceTag;
515         ThreadHandle = CreateThread(NULL,
516                                     0,
517                                     ScServiceMainStubA,
518                                     ThreadParamsA,
519                                     0,
520                                     &ThreadId);
521         if (ThreadHandle == NULL)
522         {
523             if (ThreadParamsA->lpArgVector != NULL)
524             {
525                 HeapFree(GetProcessHeap(), 0, ThreadParamsA->lpArgVector);
526             }
527             HeapFree(GetProcessHeap(), 0, ThreadParamsA);
528 
529             return ERROR_SERVICE_NO_THREAD;
530         }
531 
532         CloseHandle(ThreadHandle);
533     }
534 
535     return ERROR_SUCCESS;
536 }
537 
538 
539 static DWORD
540 ScControlService(PACTIVE_SERVICE lpService,
541                  PSCM_CONTROL_PACKET ControlPacket)
542 {
543     DWORD dwError = ERROR_SUCCESS;
544 
545     TRACE("ScControlService(%p %p)\n",
546           lpService, ControlPacket);
547 
548     if (lpService == NULL || ControlPacket == NULL)
549         return ERROR_INVALID_PARAMETER;
550 
551     TRACE("Size: %lu\n", ControlPacket->dwSize);
552     TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset));
553 
554     /* Set service tag */
555     NtCurrentTeb()->SubProcessTag = UlongToPtr(lpService->dwServiceTag);
556 
557     if (lpService->HandlerFunction)
558     {
559         _SEH2_TRY
560         {
561             (lpService->HandlerFunction)(ControlPacket->dwControl);
562         }
563         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
564         {
565             dwError = ERROR_EXCEPTION_IN_SERVICE;
566         }
567         _SEH2_END;
568     }
569     else if (lpService->HandlerFunctionEx)
570     {
571         _SEH2_TRY
572         {
573             /* FIXME: Send correct 2nd and 3rd parameters */
574             (lpService->HandlerFunctionEx)(ControlPacket->dwControl,
575                                            0, NULL,
576                                            lpService->HandlerContext);
577         }
578         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
579         {
580             dwError = ERROR_EXCEPTION_IN_SERVICE;
581         }
582         _SEH2_END;
583     }
584     else
585     {
586         dwError = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
587     }
588 
589     /* Reset service tag */
590     NtCurrentTeb()->SubProcessTag = 0;
591 
592     TRACE("ScControlService() done (Error %lu)\n", dwError);
593 
594     return dwError;
595 }
596 
597 
598 static BOOL
599 ScServiceDispatcher(HANDLE hPipe,
600                     PSCM_CONTROL_PACKET ControlPacket,
601                     DWORD dwBufferSize)
602 {
603     DWORD Count;
604     BOOL bResult;
605     BOOL bRunning = TRUE;
606     LPWSTR lpServiceName;
607     PACTIVE_SERVICE lpService;
608     SCM_REPLY_PACKET ReplyPacket;
609     DWORD dwError;
610 
611     TRACE("ScServiceDispatcher(%p %p %lu)\n",
612           hPipe, ControlPacket, dwBufferSize);
613 
614     if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
615         return FALSE;
616 
617     while (bRunning)
618     {
619         /* Read command from the control pipe */
620         bResult = ReadFile(hPipe,
621                            ControlPacket,
622                            dwBufferSize,
623                            &Count,
624                            NULL);
625         if (bResult == FALSE)
626         {
627             ERR("Pipe read failed (Error: %lu)\n", GetLastError());
628             return FALSE;
629         }
630 
631         lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
632         TRACE("Service: %S\n", lpServiceName);
633 
634         if ((ControlPacket->dwControl == SERVICE_CONTROL_STOP) &&
635             (lpServiceName[0] == UNICODE_NULL))
636         {
637             TRACE("Stop dispatcher thread\n");
638             bRunning = FALSE;
639             dwError = ERROR_SUCCESS;
640         }
641         else
642         {
643             if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
644                 lpActiveServices[0].bOwnProcess = TRUE;
645 
646             lpService = ScLookupServiceByServiceName(lpServiceName);
647             if (lpService != NULL)
648             {
649                 /* Execute command */
650                 switch (ControlPacket->dwControl)
651                 {
652                     case SERVICE_CONTROL_START_SHARE:
653                     case SERVICE_CONTROL_START_OWN:
654                         TRACE("Start command - received SERVICE_CONTROL_START\n");
655                         dwError = ScStartService(lpService, ControlPacket);
656                         break;
657 
658                     case SERVICE_CONTROL_STOP:
659                         TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
660                         dwError = ScControlService(lpService, ControlPacket);
661                         break;
662 
663                     default:
664                         TRACE("Command %lu received", ControlPacket->dwControl);
665                         dwError = ScControlService(lpService, ControlPacket);
666                         break;
667                 }
668             }
669             else
670             {
671                 dwError = ERROR_SERVICE_NOT_IN_EXE;
672             }
673         }
674 
675         ReplyPacket.dwError = dwError;
676 
677         /* Send the reply packet */
678         bResult = WriteFile(hPipe,
679                             &ReplyPacket,
680                             sizeof(ReplyPacket),
681                             &Count,
682                             NULL);
683         if (bResult == FALSE)
684         {
685             ERR("Pipe write failed (Error: %lu)\n", GetLastError());
686             return FALSE;
687         }
688     }
689 
690     return TRUE;
691 }
692 
693 
694 /**********************************************************************
695  *  RegisterServiceCtrlHandlerA
696  *
697  * @implemented
698  */
699 SERVICE_STATUS_HANDLE WINAPI
700 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
701                             LPHANDLER_FUNCTION lpHandlerProc)
702 {
703     ANSI_STRING ServiceNameA;
704     UNICODE_STRING ServiceNameU;
705     SERVICE_STATUS_HANDLE hServiceStatus;
706 
707     TRACE("RegisterServiceCtrlHandlerA(%s %p)\n",
708           debugstr_a(lpServiceName), lpHandlerProc);
709 
710     RtlInitAnsiString(&ServiceNameA, lpServiceName);
711     if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
712     {
713         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
714         return NULL;
715     }
716 
717     hServiceStatus = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
718                                                  lpHandlerProc);
719 
720     RtlFreeUnicodeString(&ServiceNameU);
721 
722     return hServiceStatus;
723 }
724 
725 
726 /**********************************************************************
727  *  RegisterServiceCtrlHandlerW
728  *
729  * @implemented
730  */
731 SERVICE_STATUS_HANDLE WINAPI
732 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
733                             LPHANDLER_FUNCTION lpHandlerProc)
734 {
735     PACTIVE_SERVICE Service;
736 
737     TRACE("RegisterServiceCtrlHandlerW(%s %p)\n",
738           debugstr_w(lpServiceName), lpHandlerProc);
739 
740     Service = ScLookupServiceByServiceName(lpServiceName);
741     if (Service == NULL)
742     {
743         SetLastError(ERROR_SERVICE_NOT_IN_EXE);
744         return NULL;
745     }
746 
747     if (!lpHandlerProc)
748     {
749         SetLastError(ERROR_INVALID_PARAMETER);
750         return NULL;
751     }
752 
753     Service->HandlerFunction = lpHandlerProc;
754     Service->HandlerFunctionEx = NULL;
755 
756     TRACE("RegisterServiceCtrlHandler returning %p\n", Service->hServiceStatus);
757 
758     return Service->hServiceStatus;
759 }
760 
761 
762 /**********************************************************************
763  *  RegisterServiceCtrlHandlerExA
764  *
765  * @implemented
766  */
767 SERVICE_STATUS_HANDLE WINAPI
768 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
769                               LPHANDLER_FUNCTION_EX lpHandlerProc,
770                               LPVOID lpContext)
771 {
772     ANSI_STRING ServiceNameA;
773     UNICODE_STRING ServiceNameU;
774     SERVICE_STATUS_HANDLE hServiceStatus;
775 
776     TRACE("RegisterServiceCtrlHandlerExA(%s %p %p)\n",
777           debugstr_a(lpServiceName), lpHandlerProc, lpContext);
778 
779     RtlInitAnsiString(&ServiceNameA, lpServiceName);
780     if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
781     {
782         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
783         return NULL;
784     }
785 
786     hServiceStatus = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
787                                                    lpHandlerProc,
788                                                    lpContext);
789 
790     RtlFreeUnicodeString(&ServiceNameU);
791 
792     return hServiceStatus;
793 }
794 
795 
796 /**********************************************************************
797  *  RegisterServiceCtrlHandlerExW
798  *
799  * @implemented
800  */
801 SERVICE_STATUS_HANDLE WINAPI
802 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
803                               LPHANDLER_FUNCTION_EX lpHandlerProc,
804                               LPVOID lpContext)
805 {
806     PACTIVE_SERVICE Service;
807 
808     TRACE("RegisterServiceCtrlHandlerExW(%s %p %p)\n",
809           debugstr_w(lpServiceName), lpHandlerProc, lpContext);
810 
811     Service = ScLookupServiceByServiceName(lpServiceName);
812     if (Service == NULL)
813     {
814         SetLastError(ERROR_SERVICE_NOT_IN_EXE);
815         return NULL;
816     }
817 
818     if (!lpHandlerProc)
819     {
820         SetLastError(ERROR_INVALID_PARAMETER);
821         return NULL;
822     }
823 
824     Service->HandlerFunction = NULL;
825     Service->HandlerFunctionEx = lpHandlerProc;
826     Service->HandlerContext = lpContext;
827 
828     TRACE("RegisterServiceCtrlHandlerEx returning %p\n", Service->hServiceStatus);
829 
830     return Service->hServiceStatus;
831 }
832 
833 
834 /**********************************************************************
835  *  I_ScIsSecurityProcess
836  *
837  * Undocumented
838  *
839  * @unimplemented
840  */
841 VOID
842 WINAPI
843 I_ScIsSecurityProcess(VOID)
844 {
845     FIXME("I_ScIsSecurityProcess()\n");
846 }
847 
848 
849 /**********************************************************************
850  *  I_ScPnPGetServiceName
851  *
852  * Undocumented
853  *
854  * @implemented
855  */
856 DWORD
857 WINAPI
858 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus,
859                       OUT LPWSTR lpServiceName,
860                       IN DWORD cchServiceName)
861 {
862     DWORD i;
863 
864     TRACE("I_ScPnPGetServiceName(%lu %p %lu)\n",
865           hServiceStatus, lpServiceName, cchServiceName);
866 
867     for (i = 0; i < dwActiveServiceCount; i++)
868     {
869         if (lpActiveServices[i].hServiceStatus == hServiceStatus)
870         {
871             wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer);
872             return ERROR_SUCCESS;
873         }
874     }
875 
876     return ERROR_SERVICE_NOT_IN_EXE;
877 }
878 
879 
880 /**********************************************************************
881  *  I_ScSetServiceBitsA
882  *
883  * Undocumented
884  *
885  * @implemented
886  */
887 BOOL WINAPI
888 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
889                     DWORD dwServiceBits,
890                     BOOL bSetBitsOn,
891                     BOOL bUpdateImmediately,
892                     LPSTR lpString)
893 {
894     BOOL bResult;
895 
896     TRACE("I_ScSetServiceBitsA(%lu %lx %u %u %s)\n",
897           hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately,
898           debugstr_a(lpString));
899 
900     RpcTryExcept
901     {
902         bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
903                                        dwServiceBits,
904                                        bSetBitsOn,
905                                        bUpdateImmediately,
906                                        lpString);
907     }
908     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
909     {
910         SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
911         bResult = FALSE;
912     }
913     RpcEndExcept;
914 
915     return bResult;
916 }
917 
918 
919 /**********************************************************************
920  *  I_ScSetServiceBitsW
921  *
922  * Undocumented
923  *
924  * @implemented
925  */
926 BOOL WINAPI
927 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
928                     DWORD dwServiceBits,
929                     BOOL bSetBitsOn,
930                     BOOL bUpdateImmediately,
931                     LPWSTR lpString)
932 {
933     BOOL bResult;
934 
935     TRACE("I_ScSetServiceBitsW(%lu %lx %u %u %s)\n",
936           hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately,
937           debugstr_w(lpString));
938 
939     RpcTryExcept
940     {
941         bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
942                                        dwServiceBits,
943                                        bSetBitsOn,
944                                        bUpdateImmediately,
945                                        lpString);
946     }
947     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
948     {
949         SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
950         bResult = FALSE;
951     }
952     RpcEndExcept;
953 
954     return bResult;
955 }
956 
957 
958 /**********************************************************************
959  *  SetServiceBits
960  *
961  * @implemented
962  */
963 BOOL WINAPI
964 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
965                DWORD dwServiceBits,
966                BOOL bSetBitsOn,
967                BOOL bUpdateImmediately)
968 {
969     TRACE("SetServiceBits(%lu %lx %u %u)\n",
970           hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately);
971 
972     return I_ScSetServiceBitsW(hServiceStatus,
973                                dwServiceBits,
974                                bSetBitsOn,
975                                bUpdateImmediately,
976                                NULL);
977 }
978 
979 
980 /**********************************************************************
981  *  SetServiceStatus
982  *
983  * @implemented
984  */
985 BOOL WINAPI
986 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
987                  LPSERVICE_STATUS lpServiceStatus)
988 {
989     DWORD dwError;
990 
991     TRACE("SetServiceStatus(%lu %p)\n",
992           hServiceStatus, lpServiceStatus);
993 
994     RpcTryExcept
995     {
996         dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
997                                     lpServiceStatus);
998     }
999     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1000     {
1001         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1002     }
1003     RpcEndExcept;
1004 
1005     if (dwError != ERROR_SUCCESS)
1006     {
1007         ERR("RSetServiceStatus() failed (Error %lu)\n", dwError);
1008         SetLastError(dwError);
1009         return FALSE;
1010     }
1011 
1012     TRACE("SetServiceStatus() done\n");
1013 
1014     return TRUE;
1015 }
1016 
1017 
1018 /**********************************************************************
1019  *  StartServiceCtrlDispatcherA
1020  *
1021  * @implemented
1022  */
1023 BOOL WINAPI
1024 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
1025 {
1026     ULONG i;
1027     HANDLE hPipe;
1028     DWORD dwError;
1029     PSCM_CONTROL_PACKET ControlPacket;
1030     DWORD dwBufSize;
1031     BOOL bRet = TRUE;
1032 
1033     TRACE("StartServiceCtrlDispatcherA(%p)\n",
1034           lpServiceStartTable);
1035 
1036     i = 0;
1037     while (lpServiceStartTable[i].lpServiceProc != NULL)
1038     {
1039         i++;
1040     }
1041 
1042     dwActiveServiceCount = i;
1043 
1044     /* Allocate the service table */
1045     lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
1046                                        HEAP_ZERO_MEMORY,
1047                                        dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
1048     if (lpActiveServices == NULL)
1049     {
1050         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1051         return FALSE;
1052     }
1053 
1054     /* Copy service names and start procedure */
1055     for (i = 0; i < dwActiveServiceCount; i++)
1056     {
1057         RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
1058                                          lpServiceStartTable[i].lpServiceName);
1059         lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc;
1060         lpActiveServices[i].hServiceStatus = NULL;
1061         lpActiveServices[i].bUnicode = FALSE;
1062         lpActiveServices[i].bOwnProcess = FALSE;
1063     }
1064 
1065     /* Connect to the SCM */
1066     dwError = ScConnectControlPipe(&hPipe);
1067     if (dwError != ERROR_SUCCESS)
1068     {
1069         bRet = FALSE;
1070         goto done;
1071     }
1072 
1073     dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1074                 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1075 
1076     ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1077                                     HEAP_ZERO_MEMORY,
1078                                     dwBufSize);
1079     if (ControlPacket == NULL)
1080     {
1081         dwError = ERROR_NOT_ENOUGH_MEMORY;
1082         bRet = FALSE;
1083         goto done;
1084     }
1085 
1086     ScCreateStatusBinding();
1087 
1088     /* Call the dispatcher loop */
1089     ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1090 
1091 
1092     ScDestroyStatusBinding();
1093 
1094     /* Close the connection */
1095     CloseHandle(hPipe);
1096 
1097     /* Free the control packet */
1098     RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1099 
1100 done:
1101     /* Free the service table */
1102     for (i = 0; i < dwActiveServiceCount; i++)
1103     {
1104         RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1105     }
1106     RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1107     lpActiveServices = NULL;
1108     dwActiveServiceCount = 0;
1109 
1110     if (!bRet)
1111         SetLastError(dwError);
1112 
1113     return bRet;
1114 }
1115 
1116 
1117 /**********************************************************************
1118  *  StartServiceCtrlDispatcherW
1119  *
1120  * @implemented
1121  */
1122 BOOL WINAPI
1123 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
1124 {
1125     ULONG i;
1126     HANDLE hPipe;
1127     DWORD dwError;
1128     PSCM_CONTROL_PACKET ControlPacket;
1129     DWORD dwBufSize;
1130     BOOL bRet = TRUE;
1131 
1132     TRACE("StartServiceCtrlDispatcherW(%p)\n",
1133           lpServiceStartTable);
1134 
1135     i = 0;
1136     while (lpServiceStartTable[i].lpServiceProc != NULL)
1137     {
1138         i++;
1139     }
1140 
1141     dwActiveServiceCount = i;
1142 
1143     /* Allocate the service table */
1144     lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
1145                                        HEAP_ZERO_MEMORY,
1146                                        dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
1147     if (lpActiveServices == NULL)
1148     {
1149         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1150         return FALSE;
1151     }
1152 
1153     /* Copy service names and start procedure */
1154     for (i = 0; i < dwActiveServiceCount; i++)
1155     {
1156         RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
1157                                lpServiceStartTable[i].lpServiceName);
1158         lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc;
1159         lpActiveServices[i].hServiceStatus = NULL;
1160         lpActiveServices[i].bUnicode = TRUE;
1161         lpActiveServices[i].bOwnProcess = FALSE;
1162     }
1163 
1164     /* Connect to the SCM */
1165     dwError = ScConnectControlPipe(&hPipe);
1166     if (dwError != ERROR_SUCCESS)
1167     {
1168         bRet = FALSE;
1169         goto done;
1170     }
1171 
1172     dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1173                 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1174 
1175     ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1176                                     HEAP_ZERO_MEMORY,
1177                                     dwBufSize);
1178     if (ControlPacket == NULL)
1179     {
1180         dwError = ERROR_NOT_ENOUGH_MEMORY;
1181         bRet = FALSE;
1182         goto done;
1183     }
1184 
1185     ScCreateStatusBinding();
1186 
1187     /* Call the dispatcher loop */
1188     ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1189 
1190     ScDestroyStatusBinding();
1191 
1192     /* Close the connection */
1193     CloseHandle(hPipe);
1194 
1195     /* Free the control packet */
1196     RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1197 
1198 done:
1199     /* Free the service table */
1200     for (i = 0; i < dwActiveServiceCount; i++)
1201     {
1202         RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1203     }
1204     RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1205     lpActiveServices = NULL;
1206     dwActiveServiceCount = 0;
1207 
1208     if (!bRet)
1209         SetLastError(dwError);
1210 
1211     return bRet;
1212 }
1213 
1214 /* EOF */
1215