68ec2a6ac63d62c971b5e1eb5a0b74b053f03c45
[reactos.git] / 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 /* 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 */