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
RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus)69 RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus)
70 {
71 return hStatusBinding;
72 }
73
74
75 void __RPC_USER
RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus,handle_t hBinding)76 RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus,
77 handle_t hBinding)
78 {
79 }
80
81
82 static RPC_STATUS
ScCreateStatusBinding(VOID)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
ScDestroyStatusBinding(VOID)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
ScLookupServiceByServiceName(LPCWSTR lpServiceName)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
ScServiceMainStubA(LPVOID Context)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
ScServiceMainStubW(LPVOID Context)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
ScConnectControlPipe(HANDLE * hPipe)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
ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket,LPDWORD lpArgCount,LPWSTR ** lpArgVector)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
ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket,LPDWORD lpArgCount,LPSTR ** lpArgVector)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
ScStartService(PACTIVE_SERVICE lpService,PSCM_CONTROL_PACKET ControlPacket)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
ScControlService(PACTIVE_SERVICE lpService,PSCM_CONTROL_PACKET ControlPacket)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
ScServiceDispatcher(HANDLE hPipe,PSCM_CONTROL_PACKET ControlPacket,DWORD dwBufferSize)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
RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,LPHANDLER_FUNCTION lpHandlerProc)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
RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,LPHANDLER_FUNCTION lpHandlerProc)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
RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,LPHANDLER_FUNCTION_EX lpHandlerProc,LPVOID lpContext)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
RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,LPHANDLER_FUNCTION_EX lpHandlerProc,LPVOID lpContext)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
I_ScIsSecurityProcess(VOID)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
I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus,OUT LPWSTR lpServiceName,IN DWORD cchServiceName)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
I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,DWORD dwServiceBits,BOOL bSetBitsOn,BOOL bUpdateImmediately,LPSTR lpString)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
I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,DWORD dwServiceBits,BOOL bSetBitsOn,BOOL bUpdateImmediately,LPWSTR lpString)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
SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,DWORD dwServiceBits,BOOL bSetBitsOn,BOOL bUpdateImmediately)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
SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,LPSERVICE_STATUS lpServiceStatus)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
StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA * lpServiceStartTable)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
StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW * lpServiceStartTable)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