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