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