ReactOS 0.4.16-dev-737-g3368adc
rpcserver.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/rpcserver.c
5 * PURPOSE: RPC server interface for the advapi32 calls
6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl
7 * Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 */
10
11/* INCLUDES ****************************************************************/
12
13#include "services.h"
14
15#include <winnls.h>
16#include <strsafe.h>
17
18#include <pseh/pseh2.h>
19
20#define NDEBUG
21#include <debug.h>
22
23/* GLOBALS *****************************************************************/
24
25#define MANAGER_TAG 0x72674D68 /* 'hMgr' */
26#define SERVICE_TAG 0x63765368 /* 'hSvc' */
27#define INVALID_TAG 0xAABBCCDD
28
29typedef struct _SCMGR_HANDLE
30{
34
35
36typedef struct _MANAGER_HANDLE
37{
41
42
43typedef struct _SERVICE_HANDLE
44{
48
49
50#define SC_MANAGER_READ \
51 (STANDARD_RIGHTS_READ | \
52 SC_MANAGER_QUERY_LOCK_STATUS | \
53 SC_MANAGER_ENUMERATE_SERVICE)
54
55#define SC_MANAGER_WRITE \
56 (STANDARD_RIGHTS_WRITE | \
57 SC_MANAGER_MODIFY_BOOT_CONFIG | \
58 SC_MANAGER_CREATE_SERVICE)
59
60#define SC_MANAGER_EXECUTE \
61 (STANDARD_RIGHTS_EXECUTE | \
62 SC_MANAGER_LOCK | \
63 SC_MANAGER_ENUMERATE_SERVICE | \
64 SC_MANAGER_CONNECT | \
65 SC_MANAGER_CREATE_SERVICE)
66
67
68#define SERVICE_READ \
69 (STANDARD_RIGHTS_READ | \
70 SERVICE_INTERROGATE | \
71 SERVICE_ENUMERATE_DEPENDENTS | \
72 SERVICE_QUERY_STATUS | \
73 SERVICE_QUERY_CONFIG)
74
75#define SERVICE_WRITE \
76 (STANDARD_RIGHTS_WRITE | \
77 SERVICE_CHANGE_CONFIG)
78
79#define SERVICE_EXECUTE \
80 (STANDARD_RIGHTS_EXECUTE | \
81 SERVICE_USER_DEFINED_CONTROL | \
82 SERVICE_PAUSE_CONTINUE | \
83 SERVICE_STOP | \
84 SERVICE_START)
85
86#define TAG_ARRAY_SIZE 32
87
88/* VARIABLES ***************************************************************/
89
90static GENERIC_MAPPING
95
96static GENERIC_MAPPING
101
103
104/* FUNCTIONS ***************************************************************/
105
106VOID
108{
110
111 DPRINT("ScmStartRpcServer() called\n");
112
113 Status = RpcServerUseProtseqEpW(L"ncacn_np",
114 10,
115 L"\\pipe\\ntsvcs",
116 NULL);
117 if (Status != RPC_S_OK)
118 {
119 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
120 return;
121 }
122
123 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
124 NULL,
125 NULL);
126 if (Status != RPC_S_OK)
127 {
128 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
129 return;
130 }
131
132 Status = RpcServerListen(1, 20, TRUE);
133 if (Status != RPC_S_OK)
134 {
135 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
136 return;
137 }
138
139 DPRINT("ScmStartRpcServer() done\n");
140}
141
142
143static DWORD
145 SC_HANDLE *Handle)
146{
148
149 if (lpDatabaseName == NULL)
150 lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
151
152 if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
153 {
154 DPRINT("Database %S, does not exist\n", lpDatabaseName);
156 }
157 else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
158 {
159 DPRINT("Invalid Database name %S\n", lpDatabaseName);
160 return ERROR_INVALID_NAME;
161 }
162
165 FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1]));
166 if (Ptr == NULL)
168
169 Ptr->Handle.Tag = MANAGER_TAG;
170
171 wcscpy(Ptr->DatabaseName, lpDatabaseName);
172
173 *Handle = (SC_HANDLE)Ptr;
174
175 return ERROR_SUCCESS;
176}
177
178
179static DWORD
181 SC_HANDLE *Handle)
182{
184
187 sizeof(SERVICE_HANDLE));
188 if (Ptr == NULL)
190
191 Ptr->Handle.Tag = SERVICE_TAG;
192
193 Ptr->ServiceEntry = lpServiceEntry;
194
195 *Handle = (SC_HANDLE)Ptr;
196
197 return ERROR_SUCCESS;
198}
199
200
201static PMANAGER_HANDLE
203{
204 PMANAGER_HANDLE pManager = NULL;
205
207 {
209 pManager = (PMANAGER_HANDLE)Handle;
210 }
212 {
213 DPRINT1("Exception: Invalid Service Manager handle\n");
214 }
215 _SEH2_END;
216
217 return pManager;
218}
219
220
221static PSERVICE_HANDLE
223{
224 PSERVICE_HANDLE pService = NULL;
225
227 {
229 pService = (PSERVICE_HANDLE)Handle;
230 }
232 {
233 DPRINT1("Exception: Invalid Service handle\n");
234 }
235 _SEH2_END;
236
237 return pService;
238}
239
240
241static DWORD
243 DWORD dwDesiredAccess)
244{
245 PMANAGER_HANDLE hMgr;
246
247 hMgr = (PMANAGER_HANDLE)Handle;
248 if (hMgr->Handle.Tag == MANAGER_TAG)
249 {
250 RtlMapGenericMask(&dwDesiredAccess,
252
253 hMgr->Handle.DesiredAccess = dwDesiredAccess;
254
255 return ERROR_SUCCESS;
256 }
257 else if (hMgr->Handle.Tag == SERVICE_TAG)
258 {
259 RtlMapGenericMask(&dwDesiredAccess,
261
262 hMgr->Handle.DesiredAccess = dwDesiredAccess;
263
264 return ERROR_SUCCESS;
265 }
266
268}
269
270
271DWORD
273{
274 HKEY hKey = NULL;
275 DWORD dwError;
276 DWORD dwGroupTagCount = 0;
277 PDWORD pdwGroupTags = NULL;
278 DWORD dwFreeTag = 0;
279 DWORD dwTagUsedBase = 1;
280 BOOLEAN TagUsed[TAG_ARRAY_SIZE];
281 INT nTagOffset;
282 DWORD i;
283 DWORD cbDataSize;
284 PLIST_ENTRY ServiceEntry;
285 PSERVICE CurrentService;
286
287 ASSERT(lpService != NULL);
288 ASSERT(lpService->lpGroup != NULL);
289
291 L"System\\CurrentControlSet\\Control\\GroupOrderList",
292 0,
293 KEY_READ,
294 &hKey);
295
296 if (dwError != ERROR_SUCCESS)
297 goto findFreeTag;
298
299 /* query value length */
300 cbDataSize = 0;
301 dwError = RegQueryValueExW(hKey,
302 lpService->lpGroup->szGroupName,
303 NULL,
304 NULL,
305 NULL,
306 &cbDataSize);
307
308 if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA)
309 goto findFreeTag;
310
311 pdwGroupTags = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDataSize);
312 if (!pdwGroupTags)
313 {
314 dwError = ERROR_NOT_ENOUGH_MEMORY;
315 goto cleanup;
316 }
317
318 dwError = RegQueryValueExW(hKey,
319 lpService->lpGroup->szGroupName,
320 NULL,
321 NULL,
322 (LPBYTE)pdwGroupTags,
323 &cbDataSize);
324
325 if (dwError != ERROR_SUCCESS)
326 goto findFreeTag;
327
328 if (cbDataSize < sizeof(pdwGroupTags[0]))
329 goto findFreeTag;
330
331 dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1);
332
333findFreeTag:
334 do
335 {
336 /* mark all tags as unused */
337 for (i = 0; i < TAG_ARRAY_SIZE; i++)
338 TagUsed[i] = FALSE;
339
340 /* mark tags in GroupOrderList as used */
341 for (i = 1; i <= dwGroupTagCount; i++)
342 {
343 nTagOffset = pdwGroupTags[i] - dwTagUsedBase;
344 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
345 TagUsed[nTagOffset] = TRUE;
346 }
347
348 /* mark tags in service list as used */
349 ServiceEntry = lpService->ServiceListEntry.Flink;
350 while (ServiceEntry != &lpService->ServiceListEntry)
351 {
352 ASSERT(ServiceEntry != NULL);
353 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
354 if (CurrentService->lpGroup == lpService->lpGroup)
355 {
356 nTagOffset = CurrentService->dwTag - dwTagUsedBase;
357 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
358 TagUsed[nTagOffset] = TRUE;
359 }
360
361 ServiceEntry = ServiceEntry->Flink;
362 }
363
364 /* find unused tag, if any */
365 for (i = 0; i < TAG_ARRAY_SIZE; i++)
366 {
367 if (!TagUsed[i])
368 {
369 dwFreeTag = dwTagUsedBase + i;
370 break;
371 }
372 }
373
374 dwTagUsedBase += TAG_ARRAY_SIZE;
375 } while (!dwFreeTag);
376
377cleanup:
378 if (pdwGroupTags)
379 HeapFree(GetProcessHeap(), 0, pdwGroupTags);
380
381 if (hKey)
383
384 if (dwFreeTag)
385 {
386 lpService->dwTag = dwFreeTag;
387 DPRINT("Assigning new tag %lu to service %S in group %S\n",
388 lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName);
389 dwError = ERROR_SUCCESS;
390 }
391 else
392 {
393 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
394 lpService->lpServiceName, dwError);
395 }
396
397 return dwError;
398}
399
400
401/* Create a path suitable for the bootloader out of the full path */
402DWORD
403ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
404{
405 SIZE_T ServiceNameLen, ExpandedLen;
407 WCHAR Dest;
408 WCHAR *Expanded;
412 HANDLE SymbolicLinkHandle;
413
414 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
415
416 if (!RelativeName)
418
419 *RelativeName = NULL;
420
421 ServiceNameLen = wcslen(CanonName);
422
423 /* First check, if it's already good */
424 if (ServiceNameLen > 12 &&
425 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
426 {
427 *RelativeName = HeapAlloc(GetProcessHeap(),
429 (ServiceNameLen + 1) * sizeof(WCHAR));
430 if (*RelativeName == NULL)
431 {
432 DPRINT("Error allocating memory for boot driver name\n");
434 }
435
436 /* Copy it */
437 wcscpy(*RelativeName, CanonName);
438
439 DPRINT("Bootdriver name %S\n", *RelativeName);
440 return ERROR_SUCCESS;
441 }
442
443 /* If it has %SystemRoot% prefix, substitute it to \System*/
444 if (ServiceNameLen > 13 &&
445 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
446 {
447 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
448 *RelativeName = HeapAlloc(GetProcessHeap(),
450 ServiceNameLen * sizeof(WCHAR));
451
452 if (*RelativeName == NULL)
453 {
454 DPRINT("Error allocating memory for boot driver name\n");
456 }
457
458 /* Copy it */
459 wcscpy(*RelativeName, L"\\SystemRoot\\");
460 wcscat(*RelativeName, CanonName + 13);
461
462 DPRINT("Bootdriver name %S\n", *RelativeName);
463 return ERROR_SUCCESS;
464 }
465
466 /* Get buffer size needed for expanding env strings */
467 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
468 if (BufferSize <= 1)
469 {
470 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
472 }
473
474 /* Allocate memory, since the size is known now */
475 Expanded = HeapAlloc(GetProcessHeap(),
477 (BufferSize + 1) * sizeof(WCHAR));
478 if (!Expanded)
479 {
480 DPRINT("Error allocating memory for boot driver name\n");
482 }
483
484 /* Expand it */
485 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
487 {
488 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
489 HeapFree(GetProcessHeap(), 0, Expanded);
491 }
492
493 /* Convert to NT-style path */
494 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
495 {
496 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
498 }
499
500 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
501
502 /* No need to keep the dos-path anymore */
503 HeapFree(GetProcessHeap(), 0, Expanded);
504
505 /* Copy it to the allocated place */
506 Expanded = HeapAlloc(GetProcessHeap(),
508 NtPathName.Length + sizeof(UNICODE_NULL));
509 if (!Expanded)
510 {
511 DPRINT("Error allocating memory for boot driver name\n");
512 RtlFreeUnicodeString(&NtPathName);
514 }
515
516 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
517 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
518 Expanded[ExpandedLen] = UNICODE_NULL;
519 RtlFreeUnicodeString(&NtPathName);
520
521 if (ServiceNameLen > ExpandedLen &&
522 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
523 {
524 HeapFree(GetProcessHeap(), 0, Expanded);
525
526 /* Only \SystemRoot\ is missing */
527 *RelativeName = HeapAlloc(GetProcessHeap(),
529 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
530 if (*RelativeName == NULL)
531 {
532 DPRINT("Error allocating memory for boot driver name\n");
534 }
535
536 wcscpy(*RelativeName, L"\\SystemRoot\\");
537 wcscat(*RelativeName, CanonName + ExpandedLen);
538
539 return ERROR_SUCCESS;
540 }
541
542 /* No longer need this */
543 HeapFree(GetProcessHeap(), 0, Expanded);
544
545 /* The most complex case starts here */
546 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
548 &SystemRoot,
550 NULL,
551 NULL);
552
553 /* Open this symlink */
555 if (NT_SUCCESS(Status))
556 {
557 DPRINT("Opened symbolic link object\n");
558
559 RtlInitEmptyUnicodeString(&LinkTarget, NULL, 0);
560 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
562 {
563 /* Check if required buffer size is sane */
565 {
566 DPRINT("Too large buffer required\n");
567
568 NtClose(SymbolicLinkHandle);
570 }
571
572 /* Alloc the string */
578 if (!LinkTarget.Buffer)
579 {
580 DPRINT("Unable to alloc buffer\n");
581 NtClose(SymbolicLinkHandle);
583 }
584
585 /* Do a real query now */
586 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
587 NtClose(SymbolicLinkHandle);
588 if (NT_SUCCESS(Status))
589 {
590 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
591
592 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
593 if ((ServiceNameLen > ExpandedLen) &&
594 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
595 {
596 *RelativeName = HeapAlloc(GetProcessHeap(),
598 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
599
600 if (*RelativeName == NULL)
601 {
602 DPRINT("Unable to alloc buffer\n");
604 }
605
606 /* Copy it over, substituting the first part
607 with SystemRoot */
608 wcscpy(*RelativeName, L"\\SystemRoot\\");
609 wcscat(*RelativeName, CanonName+ExpandedLen+1);
610
611 /* Return success */
612 return ERROR_SUCCESS;
613 }
614 else
615 {
617 }
618 }
619 else
620 {
621 DPRINT("Error, Status = %08X\n", Status);
623 }
624 }
625 else
626 {
627 DPRINT("Error, Status = %08X\n", Status);
628 NtClose(SymbolicLinkHandle);
630 }
631 }
632 else
633 {
634 /* Failure */
635 DPRINT("Error, Status = %08X\n", Status);
637 }
638}
639
640
641DWORD
643 const wchar_t *lpServiceName,
644 wchar_t **lpCanonName)
645{
647 SIZE_T ServiceNameLen;
648 UNICODE_STRING NtServiceName;
649 WCHAR *RelativeName;
650 const WCHAR *SourceName = lpServiceName;
651
652 /* Calculate the length of the service's name */
653 ServiceNameLen = wcslen(lpServiceName);
654
655 /* 12 is wcslen(L"\\SystemRoot\\") */
656 if (ServiceNameLen > 12 &&
657 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
658 {
659 /* SystemRoot prefix is already included */
660 *lpCanonName = HeapAlloc(GetProcessHeap(),
662 (ServiceNameLen + 1) * sizeof(WCHAR));
663
664 if (*lpCanonName == NULL)
665 {
666 DPRINT("Error allocating memory for canonized service name\n");
668 }
669
670 /* If it's a boot-time driver, it must be systemroot relative */
671 if (dwStartType == SERVICE_BOOT_START)
672 SourceName += 12;
673
674 /* Copy it */
675 wcscpy(*lpCanonName, SourceName);
676
677 DPRINT("Canonicalized name %S\n", *lpCanonName);
678 return NO_ERROR;
679 }
680
681 /* Check if it has %SystemRoot% (len=13) */
682 if (ServiceNameLen > 13 &&
683 !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
684 {
685 /* Substitute %SystemRoot% with \\SystemRoot\\ */
686 *lpCanonName = HeapAlloc(GetProcessHeap(),
688 (ServiceNameLen + 1) * sizeof(WCHAR));
689
690 if (*lpCanonName == NULL)
691 {
692 DPRINT("Error allocating memory for canonized service name\n");
694 }
695
696 /* If it's a boot-time driver, it must be systemroot relative */
697 if (dwStartType == SERVICE_BOOT_START)
698 wcscpy(*lpCanonName, L"\\SystemRoot\\");
699
700 wcscat(*lpCanonName, lpServiceName + 13);
701
702 DPRINT("Canonicalized name %S\n", *lpCanonName);
703 return NO_ERROR;
704 }
705
706 /* Check if it's a relative path name */
707 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
708 {
709 *lpCanonName = HeapAlloc(GetProcessHeap(),
711 (ServiceNameLen + 1) * sizeof(WCHAR));
712
713 if (*lpCanonName == NULL)
714 {
715 DPRINT("Error allocating memory for canonized service name\n");
717 }
718
719 /* Just copy it over without changing */
720 wcscpy(*lpCanonName, lpServiceName);
721
722 return NO_ERROR;
723 }
724
725 /* It seems to be a DOS path, convert it */
726 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
727 {
728 DPRINT("RtlDosPathNameToNtPathName_U() failed\n");
730 }
731
732 *lpCanonName = HeapAlloc(GetProcessHeap(),
734 NtServiceName.Length + sizeof(WCHAR));
735
736 if (*lpCanonName == NULL)
737 {
738 DPRINT("Error allocating memory for canonized service name\n");
739 RtlFreeUnicodeString(&NtServiceName);
741 }
742
743 /* Copy the string */
744 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
745
746 /* The unicode string is not needed anymore */
747 RtlFreeUnicodeString(&NtServiceName);
748
749 if (dwStartType != SERVICE_BOOT_START)
750 {
751 DPRINT("Canonicalized name %S\n", *lpCanonName);
752 return NO_ERROR;
753 }
754
755 /* The service is boot-started, so must be relative */
756 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
757 if (Result)
758 {
759 /* There is a problem, free name and return */
760 HeapFree(GetProcessHeap(), 0, *lpCanonName);
761 DPRINT("Error converting named\n");
762 return Result;
763 }
764
765 ASSERT(RelativeName);
766
767 /* Copy that string */
768 wcscpy(*lpCanonName, RelativeName + 12);
769
770 /* Free the allocated buffer */
771 HeapFree(GetProcessHeap(), 0, RelativeName);
772
773 DPRINT("Canonicalized name %S\n", *lpCanonName);
774
775 /* Success */
776 return NO_ERROR;
777}
778
779
780/* Recursively search for every dependency on every service */
781DWORD
783 PSERVICE lpService,
784 DWORD dwServiceState,
785 PSERVICE *lpServices,
787 LPDWORD lpServicesReturned)
788{
789 DWORD dwError = ERROR_SUCCESS;
790 WCHAR szNameBuf[MAX_PATH];
791 WCHAR szValueBuf[MAX_PATH];
792 WCHAR *lpszNameBuf = szNameBuf;
793 WCHAR *lpszValueBuf = szValueBuf;
795 DWORD dwNumSubKeys;
796 DWORD dwIteration;
797 PSERVICE lpCurrentService;
798 HKEY hServiceEnumKey;
799 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
800 DWORD dwDependServiceStrPtr = 0;
801 DWORD dwRequiredSize = 0;
802
803 /* Get the number of service keys */
805 NULL,
806 NULL,
807 NULL,
808 &dwNumSubKeys,
809 NULL,
810 NULL,
811 NULL,
812 NULL,
813 NULL,
814 NULL,
815 NULL);
816 if (dwError != ERROR_SUCCESS)
817 {
818 DPRINT("ERROR! Unable to get number of services keys\n");
819 return dwError;
820 }
821
822 /* Iterate the service keys to see if another service depends on the this service */
823 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
824 {
826 dwError = RegEnumKeyExW(hServicesKey,
827 dwIteration,
828 lpszNameBuf,
829 &dwSize,
830 NULL,
831 NULL,
832 NULL,
833 NULL);
834 if (dwError != ERROR_SUCCESS)
835 return dwError;
836
837 /* Open the Service key */
838 dwError = RegOpenKeyExW(hServicesKey,
839 lpszNameBuf,
840 0,
841 KEY_READ,
842 &hServiceEnumKey);
843 if (dwError != ERROR_SUCCESS)
844 return dwError;
845
846 dwSize = MAX_PATH * sizeof(WCHAR);
847
848 /* Check for the DependOnService Value */
849 dwError = RegQueryValueExW(hServiceEnumKey,
850 L"DependOnService",
851 NULL,
852 NULL,
853 (LPBYTE)lpszValueBuf,
854 &dwSize);
855
856 /* FIXME: Handle load order. */
857
858 /* If the service found has a DependOnService value */
859 if (dwError == ERROR_SUCCESS)
860 {
861 dwDependServiceStrPtr = 0;
862
863 /* Can be more than one Dependencies in the DependOnService string */
864 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
865 {
866 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
867 {
868 /* Get the current enumed service pointer */
869 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
870
871 /* Check for valid Service */
872 if (!lpCurrentService)
873 {
874 /* This should never happen! */
875 DPRINT("This should not happen at this point, report to Developer\n");
876 return ERROR_NOT_FOUND;
877 }
878
879 /* Determine state the service is in */
880 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
881 dwCurrentServiceState = SERVICE_INACTIVE;
882
883 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
884 if ((dwCurrentServiceState == dwServiceState) ||
885 (dwServiceState == SERVICE_STATE_ALL))
886 {
887 /* Calculate the required size */
888 dwRequiredSize += sizeof(SERVICE_STATUS);
889 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
890 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
891
892 /* Add the size for service name and display name pointers */
893 dwRequiredSize += (2 * sizeof(PVOID));
894
895 /* increase the BytesNeeded size */
896 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
897
898 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
899 comes first */
900
901 /* Recursive call to check for its dependencies */
903 lpCurrentService,
904 dwServiceState,
905 lpServices,
907 lpServicesReturned);
908
909 /* If the lpServices is valid set the service pointer */
910 if (lpServices)
911 lpServices[*lpServicesReturned] = lpCurrentService;
912
913 *lpServicesReturned = *lpServicesReturned + 1;
914 }
915 }
916
917 dwDependServiceStrPtr += (DWORD)(wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
918 }
919 }
920 else if (*pcbBytesNeeded)
921 {
922 dwError = ERROR_SUCCESS;
923 }
924
925 RegCloseKey(hServiceEnumKey);
926 }
927
928 return dwError;
929}
930
931
932/* Function 0 */
933DWORD
934WINAPI
936 LPSC_RPC_HANDLE hSCObject)
937{
938 PMANAGER_HANDLE hManager;
939 PSERVICE_HANDLE hService;
940 PSERVICE lpService;
941
942 DPRINT("RCloseServiceHandle() called\n");
943
944 DPRINT("hSCObject = %p\n", *hSCObject);
945
946 if (*hSCObject == 0)
948
949 hManager = ScmGetServiceManagerFromHandle(*hSCObject);
950 hService = ScmGetServiceFromHandle(*hSCObject);
951
952 if (hManager != NULL)
953 {
954 DPRINT("Found manager handle\n");
955
956 /* Make sure we don't access stale memory if someone tries to use this handle again. */
957 hManager->Handle.Tag = INVALID_TAG;
958
959 HeapFree(GetProcessHeap(), 0, hManager);
960 hManager = NULL;
961
962 *hSCObject = NULL;
963
964 DPRINT("RCloseServiceHandle() done\n");
965 return ERROR_SUCCESS;
966 }
967 else if (hService != NULL)
968 {
969 DPRINT("Found service handle\n");
970
971 /* Lock the service database exclusively */
973
974 /* Get the pointer to the service record */
975 lpService = hService->ServiceEntry;
976
977 /* Make sure we don't access stale memory if someone tries to use this handle again. */
978 hService->Handle.Tag = INVALID_TAG;
979
980 /* Free the handle */
981 HeapFree(GetProcessHeap(), 0, hService);
982 hService = NULL;
983
984
985 DPRINT("Closing service %S with %d references\n", lpService->lpServiceName, lpService->RefCount);
986 ScmDereferenceService(lpService);
987
989
990 *hSCObject = NULL;
991
992 DPRINT("RCloseServiceHandle() done\n");
993 return ERROR_SUCCESS;
994 }
995
996 DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
997
999}
1000
1001
1002/* Function 1 */
1003DWORD
1004WINAPI
1006 SC_RPC_HANDLE hService,
1007 DWORD dwControl,
1008 LPSERVICE_STATUS lpServiceStatus)
1009{
1010 PSERVICE_HANDLE hSvc;
1011 PSERVICE lpService;
1013 DWORD dwError = ERROR_SUCCESS;
1015 DWORD dwServicesReturned = 0;
1016 DWORD dwControlsAccepted;
1017 DWORD dwCurrentState;
1019 LPCWSTR lpLogStrings[2];
1020 WCHAR szLogBuffer[80];
1021 UINT uID;
1022
1023 DPRINT("RControlService() called\n");
1024
1025 if (ScmShutdown)
1027
1028 /* Check the service handle */
1029 hSvc = ScmGetServiceFromHandle(hService);
1030 if (hSvc == NULL)
1031 {
1032 DPRINT1("Invalid service handle\n");
1033 return ERROR_INVALID_HANDLE;
1034 }
1035
1036 /* Check the service entry point */
1037 lpService = hSvc->ServiceEntry;
1038 if (lpService == NULL)
1039 {
1040 DPRINT1("lpService == NULL\n");
1041 return ERROR_INVALID_HANDLE;
1042 }
1043
1044 /* Check access rights */
1045 switch (dwControl)
1046 {
1049 break;
1050
1059 break;
1060
1063 break;
1064
1065 default:
1066 if (dwControl >= 128 && dwControl <= 255)
1068 else
1070 break;
1071 }
1072
1075 return ERROR_ACCESS_DENIED;
1076
1077 /* Return the current service status information */
1078 RtlCopyMemory(lpServiceStatus,
1079 &lpService->Status,
1080 sizeof(SERVICE_STATUS));
1081
1082 if (dwControl == SERVICE_CONTROL_STOP)
1083 {
1084 /* Check if the service has dependencies running as windows
1085 doesn't stop a service that does */
1086
1087 /* Open the Services Reg key */
1089 L"System\\CurrentControlSet\\Services",
1090 0,
1091 KEY_READ,
1092 &hServicesKey);
1093 if (dwError != ERROR_SUCCESS)
1094 {
1095 DPRINT("Failed to open services key\n");
1096 return dwError;
1097 }
1098
1099 /* Call the internal function with NULL, just to get bytes we need */
1101 lpService,
1103 NULL,
1105 &dwServicesReturned);
1106
1108
1109 /* If pcbBytesNeeded is not zero then there are services running that
1110 are dependent on this service */
1111 if (pcbBytesNeeded != 0)
1112 {
1113 DPRINT("Service has running dependencies. Failed to stop service\n");
1115 }
1116 }
1117
1118 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1119 {
1120 /* Send control code to the driver */
1121 dwError = ScmControlDriver(lpService,
1122 dwControl,
1123 lpServiceStatus);
1124 }
1125 else
1126 {
1127 dwControlsAccepted = lpService->Status.dwControlsAccepted;
1128 dwCurrentState = lpService->Status.dwCurrentState;
1129
1130 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1131 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1133
1134 /* Check the current state before sending a control request */
1135 switch (dwCurrentState)
1136 {
1138 case SERVICE_STOPPED:
1140
1142 switch (dwControl)
1143 {
1145 break;
1146
1148 RtlCopyMemory(lpServiceStatus,
1149 &lpService->Status,
1150 sizeof(SERVICE_STATUS));
1151 return ERROR_SUCCESS;
1152
1153 default:
1155 }
1156 break;
1157 }
1158
1159 /* Check if the control code is acceptable to the service */
1160 switch (dwControl)
1161 {
1163 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1165 break;
1166
1169 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1171 break;
1172
1174 if ((dwControlsAccepted & SERVICE_ACCEPT_PARAMCHANGE) == 0)
1176 break;
1177
1182 if ((dwControlsAccepted & SERVICE_ACCEPT_NETBINDCHANGE) == 0)
1184 break;
1185 }
1186
1187 /* Send control code to the service */
1188 dwError = ScmControlService(lpService->lpImage->hControlPipe,
1189 lpService->lpServiceName,
1190 dwControl,
1191 (SERVICE_STATUS_HANDLE)lpService);
1192
1193 /* Return service status information */
1194 RtlCopyMemory(lpServiceStatus,
1195 &lpService->Status,
1196 sizeof(SERVICE_STATUS));
1197 }
1198
1199 if (dwError == ERROR_SUCCESS)
1200 {
1201 if (dwControl == SERVICE_CONTROL_STOP ||
1202 dwControl == SERVICE_CONTROL_PAUSE ||
1203 dwControl == SERVICE_CONTROL_CONTINUE)
1204 {
1205 /* Log a successful send control */
1206
1207 switch (dwControl)
1208 {
1210 uID = IDS_SERVICE_STOP;
1211 break;
1212
1214 uID = IDS_SERVICE_PAUSE;
1215 break;
1216
1218 uID = IDS_SERVICE_RESUME;
1219 break;
1220 }
1221 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1222
1223 lpLogStrings[0] = lpService->lpDisplayName;
1224 lpLogStrings[1] = szLogBuffer;
1225
1228 2,
1229 lpLogStrings);
1230 }
1231 }
1232
1233 return dwError;
1234}
1235
1236
1237/* Function 2 */
1238DWORD
1239WINAPI
1241 SC_RPC_HANDLE hService)
1242{
1243 PSERVICE_HANDLE hSvc;
1244 PSERVICE lpService;
1245 DWORD dwError;
1246
1247 DPRINT("RDeleteService() called\n");
1248
1249 if (ScmShutdown)
1251
1252 hSvc = ScmGetServiceFromHandle(hService);
1253 if (hSvc == NULL)
1254 {
1255 DPRINT1("Invalid service handle\n");
1256 return ERROR_INVALID_HANDLE;
1257 }
1258
1260 DELETE))
1261 return ERROR_ACCESS_DENIED;
1262
1263 lpService = hSvc->ServiceEntry;
1264 if (lpService == NULL)
1265 {
1266 DPRINT("lpService == NULL\n");
1267 return ERROR_INVALID_HANDLE;
1268 }
1269
1270 /* Lock the service database exclusively */
1272
1273 if (lpService->bDeleted)
1274 {
1275 DPRINT("Service has already been marked for delete\n");
1277 goto Done;
1278 }
1279
1280 /* Mark service for delete */
1281 lpService->bDeleted = TRUE;
1282
1283 dwError = ScmMarkServiceForDelete(lpService);
1284
1285Done:
1286 /* Unlock the service database */
1288
1289 DPRINT("RDeleteService() done\n");
1290
1291 return dwError;
1292}
1293
1294
1295/* Function 3 */
1296DWORD
1297WINAPI
1300 LPSC_RPC_LOCK lpLock)
1301{
1302 PMANAGER_HANDLE hMgr;
1303
1304 DPRINT("RLockServiceDatabase() called\n");
1305
1306 *lpLock = NULL;
1307
1309 if (hMgr == NULL)
1310 {
1311 DPRINT1("Invalid service manager handle\n");
1312 return ERROR_INVALID_HANDLE;
1313 }
1314
1317 return ERROR_ACCESS_DENIED;
1318
1319 return ScmAcquireServiceStartLock(FALSE, lpLock);
1320}
1321
1322
1323/* Function 4 */
1324DWORD
1325WINAPI
1327 SC_RPC_HANDLE hService,
1328 SECURITY_INFORMATION dwSecurityInformation,
1329 LPBYTE lpSecurityDescriptor,
1332{
1333 PSERVICE_HANDLE hSvc;
1334 PSERVICE lpService;
1335 ULONG DesiredAccess = 0;
1337 DWORD dwBytesNeeded;
1338 DWORD dwError;
1339
1340 DPRINT("RQueryServiceObjectSecurity() called\n");
1341
1342 hSvc = ScmGetServiceFromHandle(hService);
1343 if (hSvc == NULL)
1344 {
1345 DPRINT1("Invalid service handle\n");
1346 return ERROR_INVALID_HANDLE;
1347 }
1348
1349 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1353
1354 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1356
1359 {
1360 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1361 return ERROR_ACCESS_DENIED;
1362 }
1363
1364 lpService = hSvc->ServiceEntry;
1365 if (lpService == NULL)
1366 {
1367 DPRINT("lpService == NULL\n");
1368 return ERROR_INVALID_HANDLE;
1369 }
1370
1371 /* Lock the service database */
1373
1374 /* Retrieve the security descriptor */
1376 dwSecurityInformation,
1377 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1378 cbBufSize,
1379 &dwBytesNeeded);
1380
1381 /* Unlock the service database */
1383
1384 if (NT_SUCCESS(Status))
1385 {
1386 *pcbBytesNeeded = dwBytesNeeded;
1387 dwError = STATUS_SUCCESS;
1388 }
1389 else if (Status == STATUS_BUFFER_TOO_SMALL)
1390 {
1391 *pcbBytesNeeded = dwBytesNeeded;
1392 dwError = ERROR_INSUFFICIENT_BUFFER;
1393 }
1395 {
1396 dwError = ERROR_GEN_FAILURE;
1397 }
1398 else
1399 {
1400 dwError = RtlNtStatusToDosError(Status);
1401 }
1402
1403 return dwError;
1404}
1405
1406
1407/* Function 5 */
1408DWORD
1409WINAPI
1411 SC_RPC_HANDLE hService,
1412 DWORD dwSecurityInformation,
1413 LPBYTE lpSecurityDescriptor,
1414 DWORD dwSecurityDescriptorSize)
1415{
1416 PSERVICE_HANDLE hSvc;
1417 PSERVICE lpService;
1419 HANDLE hToken = NULL;
1420 HKEY hServiceKey = NULL;
1421 BOOL bDatabaseLocked = FALSE;
1423 DWORD dwError;
1424
1425 DPRINT("RSetServiceObjectSecurity() called\n");
1426
1427 hSvc = ScmGetServiceFromHandle(hService);
1428 if (hSvc == NULL)
1429 {
1430 DPRINT1("Invalid service handle\n");
1431 return ERROR_INVALID_HANDLE;
1432 }
1433
1434 if (dwSecurityInformation == 0 ||
1435 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1437 {
1439 }
1440
1441 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1443
1444 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1446
1447 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1449
1450 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1452
1453 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1454 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1455 {
1457 }
1458
1459 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1460 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1461 {
1463 }
1464
1467 {
1468 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1469 return ERROR_ACCESS_DENIED;
1470 }
1471
1472 lpService = hSvc->ServiceEntry;
1473 if (lpService == NULL)
1474 {
1475 DPRINT1("lpService == NULL\n");
1476 return ERROR_INVALID_HANDLE;
1477 }
1478
1479 if (lpService->bDeleted)
1481
1482#if 0
1484
1486 8,
1487 TRUE,
1488 &hToken);
1489 if (!NT_SUCCESS(Status))
1491
1493#endif
1494
1495 /* Build the new security descriptor */
1496 Status = RtlSetSecurityObject(dwSecurityInformation,
1497 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1498 &lpService->pSecurityDescriptor,
1500 hToken);
1501 if (!NT_SUCCESS(Status))
1502 {
1503 dwError = RtlNtStatusToDosError(Status);
1504 goto Done;
1505 }
1506
1507 /* Lock the service database exclusive */
1509 bDatabaseLocked = TRUE;
1510
1511 /* Open the service key */
1512 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1514 &hServiceKey);
1515 if (dwError != ERROR_SUCCESS)
1516 goto Done;
1517
1518 /* Store the new security descriptor */
1519 dwError = ScmWriteSecurityDescriptor(hServiceKey,
1520 lpService->pSecurityDescriptor);
1521
1522 RegFlushKey(hServiceKey);
1523
1524Done:
1525 if (hServiceKey != NULL)
1526 RegCloseKey(hServiceKey);
1527
1528 /* Unlock service database */
1529 if (bDatabaseLocked == TRUE)
1531
1532 if (hToken != NULL)
1533 NtClose(hToken);
1534
1535 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1536
1537 return dwError;
1538}
1539
1540
1541/* Function 6 */
1542DWORD
1543WINAPI
1545 SC_RPC_HANDLE hService,
1546 LPSERVICE_STATUS lpServiceStatus)
1547{
1548 PSERVICE_HANDLE hSvc;
1549 PSERVICE lpService;
1550
1551 DPRINT("RQueryServiceStatus() called\n");
1552
1553 if (ScmShutdown)
1555
1556 hSvc = ScmGetServiceFromHandle(hService);
1557 if (hSvc == NULL)
1558 {
1559 DPRINT1("Invalid service handle\n");
1560 return ERROR_INVALID_HANDLE;
1561 }
1562
1565 {
1566 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1567 return ERROR_ACCESS_DENIED;
1568 }
1569
1570 lpService = hSvc->ServiceEntry;
1571 if (lpService == NULL)
1572 {
1573 DPRINT("lpService == NULL\n");
1574 return ERROR_INVALID_HANDLE;
1575 }
1576
1577 /* Lock the service database shared */
1579
1580 /* Return service status information */
1581 RtlCopyMemory(lpServiceStatus,
1582 &lpService->Status,
1583 sizeof(SERVICE_STATUS));
1584
1585 /* Unlock the service database */
1587
1588 return ERROR_SUCCESS;
1589}
1590
1591
1592static BOOL
1594{
1595 switch (dwCurrentState)
1596 {
1597 case SERVICE_STOPPED:
1600 case SERVICE_RUNNING:
1603 case SERVICE_PAUSED:
1604 return TRUE;
1605
1606 default:
1607 return FALSE;
1608 }
1609}
1610
1611static
1612DWORD
1613WINAPI
1615{
1616 PSERVICE lpService = (PSERVICE)pParam;
1617 WCHAR szLogBuffer[80];
1618 LPCWSTR lpLogStrings[2];
1619
1620 /* Check if we are about to stop this service */
1621 if (lpService->lpImage->dwImageRunCount == 1)
1622 {
1623 /* Stop the dispatcher thread.
1624 * We must not send a control message while holding the database lock, otherwise it can cause timeouts
1625 * We are sure that the service won't be deleted in the meantime because we still have a reference to it. */
1626 DPRINT("Stopping the dispatcher thread for service %S\n", lpService->lpServiceName);
1628 L"",
1630 (SERVICE_STATUS_HANDLE)lpService);
1631 }
1632
1633 /* Lock the service database exclusively */
1635
1636 DPRINT("Service %S image count:%d\n", lpService->lpServiceName, lpService->lpImage->dwImageRunCount);
1637
1638 /* Decrement the image run counter */
1639 lpService->lpImage->dwImageRunCount--;
1640
1641 /* If we just stopped the last running service... */
1642 if (lpService->lpImage->dwImageRunCount == 0)
1643 {
1644 /* Remove the service image */
1645 DPRINT("Removing service image for %S\n", lpService->lpServiceName);
1646 ScmRemoveServiceImage(lpService->lpImage);
1647 lpService->lpImage = NULL;
1648 }
1649
1650 /* Report the results of the status change here */
1651 if (lpService->Status.dwWin32ExitCode != ERROR_SUCCESS)
1652 {
1653 /* Log a failed service stop */
1654 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
1655 L"%lu", lpService->Status.dwWin32ExitCode);
1656 lpLogStrings[0] = lpService->lpDisplayName;
1657 lpLogStrings[1] = szLogBuffer;
1658
1661 ARRAYSIZE(lpLogStrings),
1662 lpLogStrings);
1663 }
1664 else
1665 {
1666 /* Log a successful service status change */
1667 LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_STOPPED, szLogBuffer, ARRAYSIZE(szLogBuffer));
1668 lpLogStrings[0] = lpService->lpDisplayName;
1669 lpLogStrings[1] = szLogBuffer;
1670
1673 ARRAYSIZE(lpLogStrings),
1674 lpLogStrings);
1675 }
1676
1677 /* Remove the reference that was added when the service started */
1678 DPRINT("Service %S has %d references while stoping\n", lpService->lpServiceName, lpService->RefCount);
1679 ScmDereferenceService(lpService);
1680
1681 /* Unlock the service database */
1683
1684 return 0;
1685}
1686
1687/* Function 7 */
1688DWORD
1689WINAPI
1692 LPSERVICE_STATUS lpServiceStatus)
1693{
1694 PSERVICE lpService;
1695 DWORD dwPreviousState;
1696 DWORD dwPreviousType;
1697 LPCWSTR lpLogStrings[2];
1698 WCHAR szLogBuffer[80];
1699 UINT uID;
1700
1701 DPRINT("RSetServiceStatus() called\n");
1702 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1703 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1704 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1705 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1706 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1707 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1708 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1709 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1710
1711 if (hServiceStatus == 0)
1712 {
1713 DPRINT("hServiceStatus == NULL\n");
1714 return ERROR_INVALID_HANDLE;
1715 }
1716
1717 lpService = (PSERVICE)hServiceStatus;
1718
1719 /* Check current state */
1720 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1721 {
1722 DPRINT("Invalid service state\n");
1723 return ERROR_INVALID_DATA;
1724 }
1725
1726 /* Check service type */
1727 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1728 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1729 {
1730 DPRINT("Invalid service type\n");
1731 return ERROR_INVALID_DATA;
1732 }
1733
1734 /* Check accepted controls */
1735 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1736 {
1737 DPRINT("Invalid controls accepted\n");
1738 return ERROR_INVALID_DATA;
1739 }
1740
1741 /* Set the wait hint and check point only if the service is in a pending state,
1742 otherwise they should be 0 */
1743 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1744 lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1745 lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1746 {
1747 lpServiceStatus->dwWaitHint = 0;
1748 lpServiceStatus->dwCheckPoint = 0;
1749 }
1750
1751 /* Lock the service database exclusively */
1753
1754 /* Save the current service state */
1755 dwPreviousState = lpService->Status.dwCurrentState;
1756
1757 /* Save the current service type */
1758 dwPreviousType = lpService->Status.dwServiceType;
1759
1760 /* Update the service status */
1761 RtlCopyMemory(&lpService->Status,
1762 lpServiceStatus,
1763 sizeof(SERVICE_STATUS));
1764
1765 /* Restore the previous service type */
1766 lpService->Status.dwServiceType = dwPreviousType;
1767
1768 DPRINT("Service %S changed state %d to %d\n", lpService->lpServiceName, dwPreviousState, lpServiceStatus->dwCurrentState);
1769
1770 if (lpServiceStatus->dwCurrentState != SERVICE_STOPPED &&
1771 dwPreviousState == SERVICE_STOPPED)
1772 {
1773 /* Keep a reference on all non stopped services */
1774 ScmReferenceService(lpService);
1775 DPRINT("Service %S has %d references after starting\n", lpService->lpServiceName, lpService->RefCount);
1776 }
1777
1778 /* Check if the service just stopped */
1779 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED &&
1780 dwPreviousState != SERVICE_STOPPED)
1781 {
1782 HANDLE hStopThread;
1783 DWORD dwStopThreadId;
1784 DPRINT("Service %S, currentstate: %d, prev: %d\n", lpService->lpServiceName, lpServiceStatus->dwCurrentState, dwPreviousState);
1785
1786 /*
1787 * The service just changed its status to stopped.
1788 * Create a thread that will complete the stop sequence.
1789 * This thread will remove the reference that was added when the service started.
1790 * This will ensure that the service will remain valid as long as this reference is still held.
1791 */
1792 hStopThread = CreateThread(NULL,
1793 0,
1795 (LPVOID)lpService,
1796 0,
1797 &dwStopThreadId);
1798 if (hStopThread == NULL)
1799 {
1800 DPRINT1("Failed to create thread to complete service stop\n");
1801 /* We can't leave without releasing the reference.
1802 * We also can't remove it without holding the lock. */
1803 ScmDereferenceService(lpService);
1804 DPRINT1("Service %S has %d references after stop\n", lpService->lpServiceName, lpService->RefCount);
1805 }
1806 else
1807 {
1808 CloseHandle(hStopThread);
1809 }
1810 }
1811
1812 /* Unlock the service database */
1814
1815 /* Don't log any events here regarding a service stop as it can become invalid at any time */
1816
1817 if (lpServiceStatus->dwCurrentState != dwPreviousState &&
1818 (lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
1819 lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
1820 {
1821 /* Log a successful service status change */
1822 switch(lpServiceStatus->dwCurrentState)
1823 {
1824 case SERVICE_RUNNING:
1825 uID = IDS_SERVICE_RUNNING;
1826 break;
1827
1828 case SERVICE_PAUSED:
1829 uID = IDS_SERVICE_PAUSED;
1830 break;
1831 }
1832
1833 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1834 lpLogStrings[0] = lpService->lpDisplayName;
1835 lpLogStrings[1] = szLogBuffer;
1836
1839 2,
1840 lpLogStrings);
1841 }
1842
1843 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1844 DPRINT("RSetServiceStatus() done\n");
1845
1846 return ERROR_SUCCESS;
1847}
1848
1849
1850/* Function 8 */
1851DWORD
1852WINAPI
1855{
1856 DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1858}
1859
1860
1861/* Function 9 */
1862DWORD
1863WINAPI
1865 SVCCTL_HANDLEW lpMachineName,
1866 DWORD BootAcceptable)
1867{
1868 DPRINT("RNotifyBootConfigStatus(%p %lu)\n",
1869 lpMachineName, BootAcceptable);
1870
1871 if (BootAcceptable)
1872 return ScmAcceptBoot();
1873
1874 return ScmRunLastKnownGood();
1875}
1876
1877
1878/* Function 10 */
1879DWORD
1880WINAPI
1884 int bSetBitsOn,
1885 int bUpdateImmediately,
1886 wchar_t *lpString)
1887{
1888 PSERVICE pService;
1889
1890 DPRINT("RI_ScSetServiceBitsW(%p %lx %d %d %S)\n",
1891 hServiceStatus, dwServiceBits, bSetBitsOn,
1892 bUpdateImmediately, lpString);
1893
1894 if (ScmShutdown)
1896
1897 if (lpString != NULL)
1899
1900 if (hServiceStatus == 0)
1901 {
1902 DPRINT("hServiceStatus == NULL\n");
1903 return ERROR_INVALID_HANDLE;
1904 }
1905
1906 // FIXME: Validate the status handle
1907 pService = (PSERVICE)hServiceStatus;
1908
1909 if (bSetBitsOn)
1910 {
1911 DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1912 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1913 pService->dwServiceBits |= dwServiceBits;
1915 DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1916 DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1917 }
1918 else
1919 {
1920 DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1921 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1922 pService->dwServiceBits &= ~dwServiceBits;
1923 g_dwServiceBits &= ~dwServiceBits;
1924 DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1925 DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1926 }
1927
1928 return ERROR_SUCCESS;
1929}
1930
1931
1932/* Function 11 */
1933DWORD
1934WINAPI
1936 SC_RPC_HANDLE hService,
1937 DWORD dwServiceType,
1938 DWORD dwStartType,
1939 DWORD dwErrorControl,
1940 LPWSTR lpBinaryPathName,
1941 LPWSTR lpLoadOrderGroup,
1942 LPDWORD lpdwTagId,
1943 LPBYTE lpDependencies,
1944 DWORD dwDependSize,
1945 LPWSTR lpServiceStartName,
1946 LPBYTE lpPassword,
1947 DWORD dwPwSize,
1949{
1950 DWORD dwError = ERROR_SUCCESS;
1951 PSERVICE_HANDLE hSvc;
1952 PSERVICE lpService = NULL;
1953 HKEY hServiceKey = NULL;
1954 LPWSTR lpDisplayNameW = NULL;
1955 LPWSTR lpImagePathW = NULL;
1956 LPWSTR lpClearTextPassword = NULL;
1957
1958 DPRINT("RChangeServiceConfigW() called\n");
1959 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1960 DPRINT("dwStartType = %lu\n", dwStartType);
1961 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1962 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1963 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1964 DPRINT("lpServiceStartName = %S\n", lpServiceStartName);
1965 DPRINT("lpPassword = %p\n", lpPassword);
1966 DPRINT("dwPwSite = %lu\n", dwPwSize);
1967 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1968
1969 if (ScmShutdown)
1971
1972 hSvc = ScmGetServiceFromHandle(hService);
1973 if (hSvc == NULL)
1974 {
1975 DPRINT1("Invalid service handle\n");
1976 return ERROR_INVALID_HANDLE;
1977 }
1978
1981 {
1982 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1983 return ERROR_ACCESS_DENIED;
1984 }
1985
1986 /* Check for invalid service type value */
1987 if ((dwServiceType != SERVICE_NO_CHANGE) &&
1988 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
1989 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
1992 {
1994 }
1995
1996 /* Check for invalid start type value */
1997 if ((dwStartType != SERVICE_NO_CHANGE) &&
1998 (dwStartType != SERVICE_BOOT_START) &&
1999 (dwStartType != SERVICE_SYSTEM_START) &&
2000 (dwStartType != SERVICE_AUTO_START) &&
2001 (dwStartType != SERVICE_DEMAND_START) &&
2002 (dwStartType != SERVICE_DISABLED))
2003 {
2005 }
2006
2007 /* Only drivers can be boot start or system start services */
2008 if ((dwStartType == SERVICE_BOOT_START) ||
2009 (dwStartType == SERVICE_SYSTEM_START))
2010 {
2011 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2012 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2014 }
2015
2016 /* Check for invalid error control value */
2017 if ((dwErrorControl != SERVICE_NO_CHANGE) &&
2018 (dwErrorControl != SERVICE_ERROR_IGNORE) &&
2019 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2020 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2021 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2022 {
2024 }
2025
2026 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2027 {
2029 }
2030
2031 lpService = hSvc->ServiceEntry;
2032 if (lpService == NULL)
2033 {
2034 DPRINT("lpService == NULL\n");
2035 return ERROR_INVALID_HANDLE;
2036 }
2037
2038 /* Lock the service database exclusively */
2040
2041 if (lpService->bDeleted)
2042 {
2043 DPRINT("Service has already been marked for delete\n");
2045 goto done;
2046 }
2047
2048 /* Open the service key */
2049 dwError = ScmOpenServiceKey(lpService->szServiceName,
2051 &hServiceKey);
2052 if (dwError != ERROR_SUCCESS)
2053 goto done;
2054
2055 /* Write service data to the registry */
2056
2057 /* Set the display name */
2058 if (lpDisplayName != NULL && *lpDisplayName != 0)
2059 {
2060 RegSetValueExW(hServiceKey,
2061 L"DisplayName",
2062 0,
2063 REG_SZ,
2065 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2066
2067 /* Update the display name */
2068 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2070 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2071 if (lpDisplayNameW == NULL)
2072 {
2073 dwError = ERROR_NOT_ENOUGH_MEMORY;
2074 goto done;
2075 }
2076
2077 wcscpy(lpDisplayNameW, lpDisplayName);
2078 if (lpService->lpDisplayName != lpService->lpServiceName)
2079 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2080
2081 lpService->lpDisplayName = lpDisplayNameW;
2082 }
2083
2084 if (dwServiceType != SERVICE_NO_CHANGE)
2085 {
2086 /* Set the service type */
2087 dwError = RegSetValueExW(hServiceKey,
2088 L"Type",
2089 0,
2090 REG_DWORD,
2091 (LPBYTE)&dwServiceType,
2092 sizeof(DWORD));
2093 if (dwError != ERROR_SUCCESS)
2094 goto done;
2095
2096 lpService->Status.dwServiceType = dwServiceType;
2097 }
2098
2099 if (dwStartType != SERVICE_NO_CHANGE)
2100 {
2101 /* Set the start value */
2102 dwError = RegSetValueExW(hServiceKey,
2103 L"Start",
2104 0,
2105 REG_DWORD,
2106 (LPBYTE)&dwStartType,
2107 sizeof(DWORD));
2108 if (dwError != ERROR_SUCCESS)
2109 goto done;
2110
2111 lpService->dwStartType = dwStartType;
2112 }
2113
2114 if (dwErrorControl != SERVICE_NO_CHANGE)
2115 {
2116 /* Set the error control value */
2117 dwError = RegSetValueExW(hServiceKey,
2118 L"ErrorControl",
2119 0,
2120 REG_DWORD,
2121 (LPBYTE)&dwErrorControl,
2122 sizeof(DWORD));
2123 if (dwError != ERROR_SUCCESS)
2124 goto done;
2125
2126 lpService->dwErrorControl = dwErrorControl;
2127 }
2128
2129 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2130 {
2131 /* Set the image path */
2132 lpImagePathW = lpBinaryPathName;
2133
2134 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
2135 {
2136 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
2137 lpBinaryPathName,
2138 &lpImagePathW);
2139
2140 if (dwError != ERROR_SUCCESS)
2141 goto done;
2142 }
2143
2144 dwError = RegSetValueExW(hServiceKey,
2145 L"ImagePath",
2146 0,
2148 (LPBYTE)lpImagePathW,
2149 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
2150
2151 if (lpImagePathW != lpBinaryPathName)
2152 HeapFree(GetProcessHeap(), 0, lpImagePathW);
2153
2154 if (dwError != ERROR_SUCCESS)
2155 goto done;
2156 }
2157
2158 /* Set the group name */
2159 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2160 {
2161 dwError = RegSetValueExW(hServiceKey,
2162 L"Group",
2163 0,
2164 REG_SZ,
2165 (LPBYTE)lpLoadOrderGroup,
2166 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2167 if (dwError != ERROR_SUCCESS)
2168 goto done;
2169
2170 dwError = ScmSetServiceGroup(lpService,
2171 lpLoadOrderGroup);
2172 if (dwError != ERROR_SUCCESS)
2173 goto done;
2174 }
2175
2176 /* Set the tag */
2177 if (lpdwTagId != NULL)
2178 {
2179 dwError = ScmAssignNewTag(lpService);
2180 if (dwError != ERROR_SUCCESS)
2181 goto done;
2182
2183 dwError = RegSetValueExW(hServiceKey,
2184 L"Tag",
2185 0,
2186 REG_DWORD,
2187 (LPBYTE)&lpService->dwTag,
2188 sizeof(DWORD));
2189 if (dwError != ERROR_SUCCESS)
2190 goto done;
2191
2192 *lpdwTagId = lpService->dwTag;
2193 }
2194
2195 /* Write dependencies */
2196 if (lpDependencies != NULL && *lpDependencies != 0)
2197 {
2198 dwError = ScmWriteDependencies(hServiceKey,
2199 (LPWSTR)lpDependencies,
2200 dwDependSize);
2201 if (dwError != ERROR_SUCCESS)
2202 goto done;
2203 }
2204
2205 /* Start name and password are only used by Win32 services */
2206 if (lpService->Status.dwServiceType & SERVICE_WIN32)
2207 {
2208 /* Write service start name */
2209 if (lpServiceStartName != NULL && *lpServiceStartName != 0)
2210 {
2211 dwError = RegSetValueExW(hServiceKey,
2212 L"ObjectName",
2213 0,
2214 REG_SZ,
2215 (LPBYTE)lpServiceStartName,
2216 (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)));
2217 if (dwError != ERROR_SUCCESS)
2218 goto done;
2219 }
2220
2221 if (lpPassword != NULL)
2222 {
2223 if (*(LPWSTR)lpPassword != 0)
2224 {
2225 /* Decrypt the password */
2226 dwError = ScmDecryptPassword(hService,
2227 lpPassword,
2228 dwPwSize,
2229 &lpClearTextPassword);
2230 if (dwError != ERROR_SUCCESS)
2231 {
2232 DPRINT1("ScmDecryptPassword failed (Error %lu)\n", dwError);
2233 goto done;
2234 }
2235 DPRINT("Clear text password: %S\n", lpClearTextPassword);
2236
2237 /* Write the password */
2238 dwError = ScmSetServicePassword(lpService->szServiceName,
2239 lpClearTextPassword);
2240 if (dwError != ERROR_SUCCESS)
2241 {
2242 DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2243 goto done;
2244 }
2245 }
2246 else
2247 {
2248 /* Delete the password */
2249 dwError = ScmSetServicePassword(lpService->szServiceName,
2250 NULL);
2251 if (dwError == ERROR_FILE_NOT_FOUND)
2252 dwError = ERROR_SUCCESS;
2253
2254 if (dwError != ERROR_SUCCESS)
2255 {
2256 DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2257 goto done;
2258 }
2259 }
2260 }
2261 }
2262
2263done:
2264 if (lpClearTextPassword != NULL)
2265 {
2266 /* Wipe and release the password buffer */
2267 SecureZeroMemory(lpClearTextPassword,
2268 (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2269 HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2270 }
2271
2272 if (hServiceKey != NULL)
2273 RegCloseKey(hServiceKey);
2274
2275 /* Unlock the service database */
2277
2278 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2279
2280 return dwError;
2281}
2282
2283
2284/* Function 12 */
2285DWORD
2286WINAPI
2289 LPCWSTR lpServiceName,
2291 DWORD dwDesiredAccess,
2292 DWORD dwServiceType,
2293 DWORD dwStartType,
2294 DWORD dwErrorControl,
2295 LPCWSTR lpBinaryPathName,
2296 LPCWSTR lpLoadOrderGroup,
2297 LPDWORD lpdwTagId,
2298 LPBYTE lpDependencies,
2299 DWORD dwDependSize,
2300 LPCWSTR lpServiceStartName,
2301 LPBYTE lpPassword,
2302 DWORD dwPwSize,
2303 LPSC_RPC_HANDLE lpServiceHandle)
2304{
2305 PMANAGER_HANDLE hManager;
2306 DWORD dwError = ERROR_SUCCESS;
2307 PSERVICE lpService = NULL;
2308 SC_HANDLE hServiceHandle = NULL;
2309 LPWSTR lpImagePath = NULL;
2310 LPWSTR lpClearTextPassword = NULL;
2311 HKEY hServiceKey = NULL;
2312 LPWSTR lpObjectName;
2313
2314 DPRINT("RCreateServiceW() called\n");
2315 DPRINT("lpServiceName = %S\n", lpServiceName);
2316 DPRINT("lpDisplayName = %S\n", lpDisplayName);
2317 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2318 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2319 DPRINT("dwStartType = %lu\n", dwStartType);
2320 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2321 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2322 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2323 DPRINT("lpdwTagId = %p\n", lpdwTagId);
2324
2325 if (ScmShutdown)
2327
2329 if (hManager == NULL)
2330 {
2331 DPRINT1("Invalid service manager handle\n");
2332 return ERROR_INVALID_HANDLE;
2333 }
2334
2335 /* Check access rights */
2338 {
2339 DPRINT("Insufficient access rights! 0x%lx\n",
2340 hManager->Handle.DesiredAccess);
2341 return ERROR_ACCESS_DENIED;
2342 }
2343
2344 if (*lpServiceName == 0)
2345 return ERROR_INVALID_NAME;
2346
2347 if (*lpBinaryPathName == 0)
2349
2350 /* Check for invalid service type value */
2351 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2352 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2355 {
2357 }
2358
2359 /* Check for invalid start type value */
2360 if ((dwStartType != SERVICE_BOOT_START) &&
2361 (dwStartType != SERVICE_SYSTEM_START) &&
2362 (dwStartType != SERVICE_AUTO_START) &&
2363 (dwStartType != SERVICE_DEMAND_START) &&
2364 (dwStartType != SERVICE_DISABLED))
2365 {
2367 }
2368
2369 /* Only drivers can be boot start or system start services */
2370 if ((dwStartType == SERVICE_BOOT_START) ||
2371 (dwStartType == SERVICE_SYSTEM_START))
2372 {
2373 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2374 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2375 {
2377 }
2378 }
2379
2380 /* Check for invalid error control value */
2381 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2382 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2383 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2384 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2385 {
2387 }
2388
2389 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2390 (lpServiceStartName))
2391 {
2392 /* We allow LocalSystem to run interactive. */
2393 if (_wcsicmp(lpServiceStartName, L"LocalSystem"))
2394 {
2396 }
2397 }
2398
2399 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2400 {
2402 }
2403
2404 /* Lock the service database exclusively */
2406
2407 lpService = ScmGetServiceEntryByName(lpServiceName);
2408 if (lpService)
2409 {
2410 /* Unlock the service database */
2412
2413 /* Check if it is marked for deletion */
2414 if (lpService->bDeleted)
2416
2417 /* Return service-exists error */
2418 return ERROR_SERVICE_EXISTS;
2419 }
2420
2421 if (lpDisplayName != NULL &&
2423 {
2424 /* Unlock the service database */
2426
2428 }
2429
2430 if (dwServiceType & SERVICE_DRIVER)
2431 {
2432 dwError = ScmCanonDriverImagePath(dwStartType,
2433 lpBinaryPathName,
2434 &lpImagePath);
2435 if (dwError != ERROR_SUCCESS)
2436 goto done;
2437 }
2438 else
2439 {
2440 if (dwStartType == SERVICE_BOOT_START ||
2441 dwStartType == SERVICE_SYSTEM_START)
2442 {
2443 /* Unlock the service database */
2445
2447 }
2448 }
2449
2450 /* Allocate a new service entry */
2451 dwError = ScmCreateNewServiceRecord(lpServiceName,
2452 &lpService,
2453 dwServiceType,
2454 dwStartType);
2455 if (dwError != ERROR_SUCCESS)
2456 goto done;
2457
2458 /* Fill the new service entry */
2459 lpService->dwErrorControl = dwErrorControl;
2460
2461 /* Fill the display name */
2462 if (lpDisplayName != NULL &&
2463 *lpDisplayName != 0 &&
2464 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2465 {
2466 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2468 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2469 if (lpService->lpDisplayName == NULL)
2470 {
2471 dwError = ERROR_NOT_ENOUGH_MEMORY;
2472 goto done;
2473 }
2474 wcscpy(lpService->lpDisplayName, lpDisplayName);
2475 }
2476
2477 /* Assign the service to a group */
2478 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2479 {
2480 dwError = ScmSetServiceGroup(lpService,
2481 lpLoadOrderGroup);
2482 if (dwError != ERROR_SUCCESS)
2483 goto done;
2484 }
2485
2486 /* Assign a new tag */
2487 if (lpdwTagId != NULL)
2488 {
2489 dwError = ScmAssignNewTag(lpService);
2490 if (dwError != ERROR_SUCCESS)
2491 goto done;
2492 }
2493
2494 /* Assign the default security descriptor */
2495 if (dwServiceType & SERVICE_WIN32)
2496 {
2497 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
2498 if (dwError != ERROR_SUCCESS)
2499 goto done;
2500 }
2501
2502 /* Write service data to the registry */
2503 /* Create the service key */
2504 dwError = ScmCreateServiceKey(lpServiceName,
2505 KEY_WRITE,
2506 &hServiceKey);
2507 if (dwError != ERROR_SUCCESS)
2508 goto done;
2509
2510 /* Set the display name */
2511 if (lpDisplayName != NULL && *lpDisplayName != 0)
2512 {
2513 RegSetValueExW(hServiceKey,
2514 L"DisplayName",
2515 0,
2516 REG_SZ,
2518 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2519 }
2520
2521 /* Set the service type */
2522 dwError = RegSetValueExW(hServiceKey,
2523 L"Type",
2524 0,
2525 REG_DWORD,
2526 (LPBYTE)&dwServiceType,
2527 sizeof(DWORD));
2528 if (dwError != ERROR_SUCCESS)
2529 goto done;
2530
2531 /* Set the start value */
2532 dwError = RegSetValueExW(hServiceKey,
2533 L"Start",
2534 0,
2535 REG_DWORD,
2536 (LPBYTE)&dwStartType,
2537 sizeof(DWORD));
2538 if (dwError != ERROR_SUCCESS)
2539 goto done;
2540
2541 /* Set the error control value */
2542 dwError = RegSetValueExW(hServiceKey,
2543 L"ErrorControl",
2544 0,
2545 REG_DWORD,
2546 (LPBYTE)&dwErrorControl,
2547 sizeof(DWORD));
2548 if (dwError != ERROR_SUCCESS)
2549 goto done;
2550
2551 /* Set the image path */
2552 if (dwServiceType & SERVICE_WIN32)
2553 {
2554 dwError = RegSetValueExW(hServiceKey,
2555 L"ImagePath",
2556 0,
2558 (LPBYTE)lpBinaryPathName,
2559 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2560 if (dwError != ERROR_SUCCESS)
2561 goto done;
2562 }
2563 else if (dwServiceType & SERVICE_DRIVER)
2564 {
2565 dwError = RegSetValueExW(hServiceKey,
2566 L"ImagePath",
2567 0,
2569 (LPBYTE)lpImagePath,
2570 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2571 if (dwError != ERROR_SUCCESS)
2572 goto done;
2573 }
2574
2575 /* Set the group name */
2576 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2577 {
2578 dwError = RegSetValueExW(hServiceKey,
2579 L"Group",
2580 0,
2581 REG_SZ,
2582 (LPBYTE)lpLoadOrderGroup,
2583 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2584 if (dwError != ERROR_SUCCESS)
2585 goto done;
2586 }
2587
2588 /* Set the service tag */
2589 if (lpdwTagId != NULL)
2590 {
2591 dwError = RegSetValueExW(hServiceKey,
2592 L"Tag",
2593 0,
2594 REG_DWORD,
2595 (LPBYTE)&lpService->dwTag,
2596 sizeof(DWORD));
2597 if (dwError != ERROR_SUCCESS)
2598 goto done;
2599 }
2600
2601 /* Write dependencies */
2602 if (lpDependencies != NULL && *lpDependencies != 0)
2603 {
2604 dwError = ScmWriteDependencies(hServiceKey,
2605 (LPCWSTR)lpDependencies,
2606 dwDependSize);
2607 if (dwError != ERROR_SUCCESS)
2608 goto done;
2609 }
2610
2611 /* Start name and password are only used by Win32 services */
2612 if (dwServiceType & SERVICE_WIN32)
2613 {
2614 /* Write service start name */
2615 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2616 dwError = RegSetValueExW(hServiceKey,
2617 L"ObjectName",
2618 0,
2619 REG_SZ,
2620 (LPBYTE)lpObjectName,
2621 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2622 if (dwError != ERROR_SUCCESS)
2623 goto done;
2624
2625 if (lpPassword != NULL && *(LPWSTR)lpPassword != 0)
2626 {
2627 /* Decrypt the password */
2629 lpPassword,
2630 dwPwSize,
2631 &lpClearTextPassword);
2632 if (dwError != ERROR_SUCCESS)
2633 goto done;
2634
2635 /* Write the password */
2636 dwError = ScmSetServicePassword(lpServiceName,
2637 lpClearTextPassword);
2638 if (dwError != ERROR_SUCCESS)
2639 goto done;
2640 }
2641
2642 /* Write the security descriptor */
2643 dwError = ScmWriteSecurityDescriptor(hServiceKey,
2644 lpService->pSecurityDescriptor);
2645 if (dwError != ERROR_SUCCESS)
2646 goto done;
2647 }
2648
2649 dwError = ScmCreateServiceHandle(lpService,
2650 &hServiceHandle);
2651 if (dwError != ERROR_SUCCESS)
2652 goto done;
2653
2654 dwError = ScmCheckAccess(hServiceHandle,
2655 dwDesiredAccess);
2656 if (dwError != ERROR_SUCCESS)
2657 goto done;
2658
2659 ScmReferenceService(lpService);
2660
2661 /* Get the service tag (if Win32) */
2662 ScmGenerateServiceTag(lpService);
2663
2664 DPRINT("CreateService - lpService->RefCount %u\n", lpService->RefCount);
2665
2666done:
2667 /* Unlock the service database */
2669
2670 if (hServiceKey != NULL)
2671 RegCloseKey(hServiceKey);
2672
2673 if (lpClearTextPassword != NULL)
2674 {
2675 /* Wipe and release the password buffer */
2676 SecureZeroMemory(lpClearTextPassword,
2677 (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2678 HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2679 }
2680
2681 if (dwError == ERROR_SUCCESS)
2682 {
2683 DPRINT("hService %p\n", hServiceHandle);
2684 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2685
2686 if (lpdwTagId != NULL)
2687 *lpdwTagId = lpService->dwTag;
2688 }
2689 else
2690 {
2691 if (lpService != NULL &&
2692 lpService->lpServiceName != NULL)
2693 {
2694 /* Release the display name buffer */
2695 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2696 }
2697
2698 if (hServiceHandle)
2699 {
2700 /* Remove the service handle */
2701 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2702 }
2703
2704 if (lpService != NULL)
2705 {
2706 /* FIXME: remove the service entry */
2707 }
2708 }
2709
2710 if (lpImagePath != NULL)
2711 HeapFree(GetProcessHeap(), 0, lpImagePath);
2712
2713 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2714
2715 return dwError;
2716}
2717
2718
2719/* Function 13 */
2720DWORD
2721WINAPI
2723 SC_RPC_HANDLE hService,
2724 DWORD dwServiceState,
2725 LPBYTE lpServices,
2728 LPBOUNDED_DWORD_256K lpServicesReturned)
2729{
2730 DWORD dwError = ERROR_SUCCESS;
2731 DWORD dwServicesReturned = 0;
2732 DWORD dwServiceCount;
2734 PSERVICE_HANDLE hSvc;
2735 PSERVICE lpService = NULL;
2736 PSERVICE *lpServicesArray = NULL;
2737 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2738 LPWSTR lpStr;
2739
2740 *pcbBytesNeeded = 0;
2741 *lpServicesReturned = 0;
2742
2743 DPRINT("REnumDependentServicesW() called\n");
2744
2745 hSvc = ScmGetServiceFromHandle(hService);
2746 if (hSvc == NULL)
2747 {
2748 DPRINT1("Invalid service handle\n");
2749 return ERROR_INVALID_HANDLE;
2750 }
2751
2752 lpService = hSvc->ServiceEntry;
2753
2754 /* Check access rights */
2757 {
2758 DPRINT("Insufficient access rights! 0x%lx\n",
2759 hSvc->Handle.DesiredAccess);
2760 return ERROR_ACCESS_DENIED;
2761 }
2762
2763 /* Open the Services Reg key */
2765 L"System\\CurrentControlSet\\Services",
2766 0,
2767 KEY_READ,
2768 &hServicesKey);
2769 if (dwError != ERROR_SUCCESS)
2770 return dwError;
2771
2772 /* First determine the bytes needed and get the number of dependent services */
2774 lpService,
2775 dwServiceState,
2776 NULL,
2778 &dwServicesReturned);
2779 if (dwError != ERROR_SUCCESS)
2780 goto Done;
2781
2782 /* If buffer size is less than the bytes needed or pointer is null */
2783 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2784 {
2785 dwError = ERROR_MORE_DATA;
2786 goto Done;
2787 }
2788
2789 /* Allocate memory for array of service pointers */
2790 lpServicesArray = HeapAlloc(GetProcessHeap(),
2792 (dwServicesReturned + 1) * sizeof(PSERVICE));
2793 if (!lpServicesArray)
2794 {
2795 DPRINT1("Could not allocate buffer\n");
2796 dwError = ERROR_NOT_ENOUGH_MEMORY;
2797 goto Done;
2798 }
2799
2800 dwServicesReturned = 0;
2801 *pcbBytesNeeded = 0;
2802
2804 lpService,
2805 dwServiceState,
2806 lpServicesArray,
2808 &dwServicesReturned);
2809 if (dwError != ERROR_SUCCESS)
2810 {
2811 goto Done;
2812 }
2813
2814 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2815 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2816
2817 /* Copy EnumDepenedentService to Buffer */
2818 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2819 {
2820 lpService = lpServicesArray[dwServiceCount];
2821
2822 /* Copy status info */
2823 memcpy(&lpServicesPtr->ServiceStatus,
2824 &lpService->Status,
2825 sizeof(SERVICE_STATUS));
2826
2827 /* Copy display name */
2828 wcscpy(lpStr, lpService->lpDisplayName);
2829 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2830 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2831
2832 /* Copy service name */
2833 wcscpy(lpStr, lpService->lpServiceName);
2834 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2835 lpStr += (wcslen(lpService->lpServiceName) + 1);
2836
2837 lpServicesPtr++;
2838 }
2839
2840 *lpServicesReturned = dwServicesReturned;
2841
2842Done:
2843 if (lpServicesArray != NULL)
2844 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2845
2847
2848 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2849
2850 return dwError;
2851}
2852
2853
2854/* Function 14 */
2855DWORD
2856WINAPI
2859 DWORD dwServiceType,
2860 DWORD dwServiceState,
2862 DWORD dwBufSize,
2864 LPBOUNDED_DWORD_256K lpServicesReturned,
2865 LPBOUNDED_DWORD_256K lpResumeHandle)
2866{
2867 /* Enumerate all the services, not regarding of their group */
2869 dwServiceType,
2870 dwServiceState,
2871 lpBuffer,
2872 dwBufSize,
2874 lpServicesReturned,
2875 lpResumeHandle,
2876 NULL);
2877}
2878
2879
2880/* Function 15 */
2881DWORD
2882WINAPI
2884 LPWSTR lpMachineName,
2885 LPWSTR lpDatabaseName,
2886 DWORD dwDesiredAccess,
2887 LPSC_RPC_HANDLE lpScHandle)
2888{
2889 DWORD dwError;
2890 SC_HANDLE hHandle;
2891
2892 DPRINT("ROpenSCManagerW() called\n");
2893 DPRINT("lpMachineName = %p\n", lpMachineName);
2894 DPRINT("lpMachineName: %S\n", lpMachineName);
2895 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2896 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2897 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2898
2899 if (ScmShutdown)
2901
2902 if (!lpScHandle)
2904
2905 dwError = ScmCreateManagerHandle(lpDatabaseName,
2906 &hHandle);
2907 if (dwError != ERROR_SUCCESS)
2908 {
2909 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2910 return dwError;
2911 }
2912
2913 /* Check the desired access */
2914 dwError = ScmCheckAccess(hHandle,
2915 dwDesiredAccess | SC_MANAGER_CONNECT);
2916 if (dwError != ERROR_SUCCESS)
2917 {
2918 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2919 HeapFree(GetProcessHeap(), 0, hHandle);
2920 return dwError;
2921 }
2922
2923 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2924 DPRINT("*hScm = %p\n", *lpScHandle);
2925
2926 DPRINT("ROpenSCManagerW() done\n");
2927
2928 return ERROR_SUCCESS;
2929}
2930
2931
2932/* Function 16 */
2933DWORD
2934WINAPI
2937 LPWSTR lpServiceName,
2938 DWORD dwDesiredAccess,
2939 LPSC_RPC_HANDLE lpServiceHandle)
2940{
2941 PSERVICE lpService;
2942 PMANAGER_HANDLE hManager;
2943 SC_HANDLE hHandle;
2944 DWORD dwError = ERROR_SUCCESS;
2945
2946 DPRINT("ROpenServiceW() called\n");
2947 DPRINT("hSCManager = %p\n", hSCManager);
2948 DPRINT("lpServiceName = %p\n", lpServiceName);
2949 DPRINT("lpServiceName: %S\n", lpServiceName);
2950 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2951
2952 if (ScmShutdown)
2954
2956 if (hManager == NULL)
2957 {
2958 DPRINT1("Invalid service manager handle\n");
2959 return ERROR_INVALID_HANDLE;
2960 }
2961
2962 if (!lpServiceHandle)
2964
2965 if (!lpServiceName)
2966 return ERROR_INVALID_ADDRESS;
2967
2968 /* Lock the service database exclusive */
2970
2971 /* Get service database entry */
2972 lpService = ScmGetServiceEntryByName(lpServiceName);
2973 if (lpService == NULL)
2974 {
2975 DPRINT("Could not find service\n");
2977 goto Done;
2978 }
2979
2980 /* Create a service handle */
2981 dwError = ScmCreateServiceHandle(lpService,
2982 &hHandle);
2983 if (dwError != ERROR_SUCCESS)
2984 {
2985 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2986 goto Done;
2987 }
2988
2989 /* Check the desired access */
2990 dwError = ScmCheckAccess(hHandle,
2991 dwDesiredAccess);
2992 if (dwError != ERROR_SUCCESS)
2993 {
2994 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2995 HeapFree(GetProcessHeap(), 0, hHandle);
2996 goto Done;
2997 }
2998
2999 ScmReferenceService(lpService);
3000 DPRINT("OpenService %S - lpService->RefCount %u\n", lpService->lpServiceName, lpService->RefCount);
3001
3002 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
3003 DPRINT("*hService = %p\n", *lpServiceHandle);
3004
3005Done:
3006 /* Unlock the service database */
3008
3009 DPRINT("ROpenServiceW() done\n");
3010
3011 return dwError;
3012}
3013
3014
3015/* Function 17 */
3016DWORD
3017WINAPI
3019 SC_RPC_HANDLE hService,
3020 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
3023{
3024 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
3025 DWORD dwError = ERROR_SUCCESS;
3026 PSERVICE_HANDLE hSvc;
3027 PSERVICE lpService = NULL;
3028 HKEY hServiceKey = NULL;
3029 LPWSTR lpImagePath = NULL;
3030 LPWSTR lpServiceStartName = NULL;
3031 LPWSTR lpDependencies = NULL;
3032 DWORD dwDependenciesLength = 0;
3033 DWORD dwRequiredSize;
3034 LPWSTR lpStr;
3035
3036 DPRINT("RQueryServiceConfigW() called\n");
3037
3038 if (ScmShutdown)
3040
3041 hSvc = ScmGetServiceFromHandle(hService);
3042 if (hSvc == NULL)
3043 {
3044 DPRINT1("Invalid service handle\n");
3045 return ERROR_INVALID_HANDLE;
3046 }
3047
3050 {
3051 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3052 return ERROR_ACCESS_DENIED;
3053 }
3054
3055 lpService = hSvc->ServiceEntry;
3056 if (lpService == NULL)
3057 {
3058 DPRINT("lpService == NULL\n");
3059 return ERROR_INVALID_HANDLE;
3060 }
3061
3062 /* Lock the service database shared */
3064
3065 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3066 KEY_READ,
3067 &hServiceKey);
3068 if (dwError != ERROR_SUCCESS)
3069 goto Done;
3070
3071 /* Read the image path */
3072 dwError = ScmReadString(hServiceKey,
3073 L"ImagePath",
3074 &lpImagePath);
3075 if (dwError != ERROR_SUCCESS)
3076 goto Done;
3077
3078 /* Read the service start name */
3079 ScmReadString(hServiceKey,
3080 L"ObjectName",
3081 &lpServiceStartName);
3082
3083 /* Read the dependencies */
3084 ScmReadDependencies(hServiceKey,
3085 &lpDependencies,
3086 &dwDependenciesLength);
3087
3088 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3089
3090 if (lpImagePath != NULL)
3091 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
3092 else
3093 dwRequiredSize += 2 * sizeof(WCHAR);
3094
3095 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3096 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
3097 else
3098 dwRequiredSize += 2 * sizeof(WCHAR);
3099
3100 if (lpDependencies != NULL)
3101 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
3102 else
3103 dwRequiredSize += 2 * sizeof(WCHAR);
3104
3105 if (lpServiceStartName != NULL)
3106 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
3107 else
3108 dwRequiredSize += 2 * sizeof(WCHAR);
3109
3110 if (lpService->lpDisplayName != NULL)
3111 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
3112 else
3113 dwRequiredSize += 2 * sizeof(WCHAR);
3114
3115 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3116 {
3117 dwError = ERROR_INSUFFICIENT_BUFFER;
3118 }
3119 else
3120 {
3121 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
3122 lpServiceConfig->dwStartType = lpService->dwStartType;
3123 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
3124 lpServiceConfig->dwTagId = lpService->dwTag;
3125
3126 lpStr = (LPWSTR)(lpServiceConfig + 1);
3127
3128 /* Append the image path */
3129 if (lpImagePath != NULL)
3130 {
3131 wcscpy(lpStr, lpImagePath);
3132 }
3133 else
3134 {
3135 *lpStr = 0;
3136 }
3137
3138 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3139 lpStr += (wcslen(lpStr) + 1);
3140
3141 /* Append the group name */
3142 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3143 {
3144 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
3145 }
3146 else
3147 {
3148 *lpStr = 0;
3149 }
3150
3151 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3152 lpStr += (wcslen(lpStr) + 1);
3153
3154 /* Append Dependencies */
3155 if (lpDependencies != NULL)
3156 {
3157 memcpy(lpStr,
3158 lpDependencies,
3159 dwDependenciesLength * sizeof(WCHAR));
3160 }
3161 else
3162 {
3163 *lpStr = 0;
3164 }
3165
3166 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3167 if (lpDependencies != NULL)
3168 lpStr += dwDependenciesLength;
3169 else
3170 lpStr += (wcslen(lpStr) + 1);
3171
3172 /* Append the service start name */
3173 if (lpServiceStartName != NULL)
3174 {
3175 wcscpy(lpStr, lpServiceStartName);
3176 }
3177 else
3178 {
3179 *lpStr = 0;
3180 }
3181
3182 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3183 lpStr += (wcslen(lpStr) + 1);
3184
3185 /* Append the display name */
3186 if (lpService->lpDisplayName != NULL)
3187 {
3188 wcscpy(lpStr, lpService->lpDisplayName);
3189 }
3190 else
3191 {
3192 *lpStr = 0;
3193 }
3194
3195 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3196 }
3197
3198 if (pcbBytesNeeded != NULL)
3199 *pcbBytesNeeded = dwRequiredSize;
3200
3201Done:
3202 /* Unlock the service database */
3204
3205 if (lpImagePath != NULL)
3206 HeapFree(GetProcessHeap(), 0, lpImagePath);
3207
3208 if (lpServiceStartName != NULL)
3209 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3210
3211 if (lpDependencies != NULL)
3212 HeapFree(GetProcessHeap(), 0, lpDependencies);
3213
3214 if (hServiceKey != NULL)
3215 RegCloseKey(hServiceKey);
3216
3217 DPRINT("RQueryServiceConfigW() done\n");
3218
3219 return dwError;
3220}
3221
3222
3223/* Function 18 */
3224DWORD
3225WINAPI
3228 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3231{
3233 PMANAGER_HANDLE hMgr;
3234 DWORD dwRequiredSize;
3235
3236 if (!lpLockStatus || !pcbBytesNeeded)
3238
3240 if (hMgr == NULL)
3241 {
3242 DPRINT1("Invalid service manager handle\n");
3243 return ERROR_INVALID_HANDLE;
3244 }
3245
3248 {
3249 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
3250 return ERROR_ACCESS_DENIED;
3251 }
3252
3253 /* FIXME: we need to compute instead the real length of the owner name */
3254 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
3255 *pcbBytesNeeded = dwRequiredSize;
3256
3257 if (cbBufSize < dwRequiredSize)
3259
3260 ScmQueryServiceLockStatusW(lpLockStatus);
3261
3262 return ERROR_SUCCESS;
3263}
3264
3265
3266/* Function 19 */
3267DWORD
3268WINAPI
3270 SC_RPC_HANDLE hService,
3271 DWORD argc,
3273{
3274 DWORD dwError = ERROR_SUCCESS;
3275 PSERVICE_HANDLE hSvc;
3276 PSERVICE lpService = NULL;
3277
3278#ifndef NDEBUG
3279 DWORD i;
3280
3281 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3282 DPRINT(" argc: %lu\n", argc);
3283 if (argv != NULL)
3284 {
3285 for (i = 0; i < argc; i++)
3286 {
3287 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
3288 }
3289 }
3290#endif
3291
3292 if (ScmShutdown)
3294
3295 hSvc = ScmGetServiceFromHandle(hService);
3296 if (hSvc == NULL)
3297 {
3298 DPRINT1("Invalid service handle\n");
3299 return ERROR_INVALID_HANDLE;
3300 }
3301
3304 {
3305 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3306 return ERROR_ACCESS_DENIED;
3307 }
3308
3309 lpService = hSvc->ServiceEntry;
3310 if (lpService == NULL)
3311 {
3312 DPRINT("lpService == NULL\n");
3313 return ERROR_INVALID_HANDLE;
3314 }
3315
3316 if (lpService->dwStartType == SERVICE_DISABLED)
3318
3319 if (lpService->bDeleted)
3321
3322 /* Start the service */
3323 dwError = ScmStartService(lpService, argc, (PCWSTR*)argv);
3324
3325 return dwError;
3326}
3327
3328
3329/* Function 20 */
3330DWORD
3331WINAPI
3334 LPCWSTR lpServiceName,
3336 DWORD *lpcchBuffer)
3337{
3338 // PMANAGER_HANDLE hManager;
3339 PSERVICE lpService;
3340 LPCWSTR lpSvcDisplayName;
3342 DWORD dwError;
3343
3344 DPRINT("RGetServiceDisplayNameW() called\n");
3345 DPRINT("hSCManager = %p\n", hSCManager);
3346 DPRINT("lpServiceName: %S\n", lpServiceName);
3347 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3348 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3349
3350#if 0
3351 hManager = (PMANAGER_HANDLE)hSCManager;
3352 if (hManager->Handle.Tag != MANAGER_TAG)
3353 {
3354 DPRINT("Invalid manager handle\n");
3355 return ERROR_INVALID_HANDLE;
3356 }
3357#endif
3358
3359 /* Get service database entry */
3360 lpService = ScmGetServiceEntryByName(lpServiceName);
3361 if (lpService == NULL)
3362 {
3363 DPRINT("Could not find service\n");
3365 }
3366
3367 if (lpService->lpDisplayName)
3368 lpSvcDisplayName = lpService->lpDisplayName;
3369 else
3370 lpSvcDisplayName = lpService->lpServiceName;
3371
3372 dwLength = (DWORD)wcslen(lpSvcDisplayName);
3373
3374 if (*lpcchBuffer > dwLength)
3375 {
3376 if (lpDisplayName != NULL)
3377 wcscpy(lpDisplayName, lpSvcDisplayName);
3378
3379 dwError = ERROR_SUCCESS;
3380 }
3381 else
3382 {
3383 dwError = ERROR_INSUFFICIENT_BUFFER;
3384 }
3385
3386 *lpcchBuffer = dwLength;
3387
3388 return dwError;
3389}
3390
3391
3392/* Function 21 */
3393DWORD
3394WINAPI
3398 LPWSTR lpServiceName,
3399 DWORD *lpcchBuffer)
3400{
3401 // PMANAGER_HANDLE hManager;
3402 PSERVICE lpService;
3404 DWORD dwError;
3405
3406 DPRINT("RGetServiceKeyNameW() called\n");
3407 DPRINT("hSCManager = %p\n", hSCManager);
3408 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3409 DPRINT("lpServiceName: %p\n", lpServiceName);
3410 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3411
3412#if 0
3413 hManager = (PMANAGER_HANDLE)hSCManager;
3414 if (hManager->Handle.Tag != MANAGER_TAG)
3415 {
3416 DPRINT("Invalid manager handle\n");
3417 return ERROR_INVALID_HANDLE;
3418 }
3419#endif
3420
3421 /* Get service database entry */
3423 if (lpService == NULL)
3424 {
3425 DPRINT("Could not find service\n");
3427 }
3428
3429 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3430
3431 if (*lpcchBuffer > dwLength)
3432 {
3433 if (lpServiceName != NULL)
3434 wcscpy(lpServiceName, lpService->lpServiceName);
3435
3436 dwError = ERROR_SUCCESS;
3437 }
3438 else
3439 {
3440 dwError = ERROR_INSUFFICIENT_BUFFER;
3441 }
3442
3443 *lpcchBuffer = dwLength;
3444
3445 return dwError;
3446}
3447
3448
3449/* Function 22 */
3450DWORD
3451WINAPI
3455 int bSetBitsOn,
3456 int bUpdateImmediately,
3457 char *lpString)
3458{
3459 if (ScmShutdown)
3461
3462 if (lpString != NULL)
3464
3467 bSetBitsOn,
3468 bUpdateImmediately,
3469 NULL);
3470}
3471
3472
3473/* Function 23 */
3474DWORD
3475WINAPI
3477 SC_RPC_HANDLE hService,
3478 DWORD dwServiceType,
3479 DWORD dwStartType,
3480 DWORD dwErrorControl,
3481 LPSTR lpBinaryPathName,
3482 LPSTR lpLoadOrderGroup,
3483 LPDWORD lpdwTagId,
3484 LPBYTE lpDependencies,
3485 DWORD dwDependSize,
3486 LPSTR lpServiceStartName,
3487 LPBYTE lpPassword,
3488 DWORD dwPwSize,
3490{
3491 DWORD dwError = ERROR_SUCCESS;
3492 LPWSTR lpBinaryPathNameW = NULL;
3493 LPWSTR lpLoadOrderGroupW = NULL;
3494 LPWSTR lpDependenciesW = NULL;
3495 LPWSTR lpServiceStartNameW = NULL;
3496 LPWSTR lpDisplayNameW = NULL;
3497 DWORD dwDependenciesLength = 0;
3498 SIZE_T cchLength;
3499 int len;
3500 LPCSTR lpStr;
3501
3502 if (lpBinaryPathName)
3503 {
3504 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3505 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3506 if (!lpBinaryPathNameW)
3507 {
3509 goto cleanup;
3510 }
3511 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3512 }
3513
3514 if (lpLoadOrderGroup)
3515 {
3516 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3517 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3518 if (!lpLoadOrderGroupW)
3519 {
3521 goto cleanup;
3522 }
3523 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3524 }
3525
3526 if (lpDependencies)
3527 {
3528 lpStr = (LPCSTR)lpDependencies;
3529 while (*lpStr)
3530 {
3531 cchLength = strlen(lpStr) + 1;
3532 dwDependenciesLength += (DWORD)cchLength;
3533 lpStr = lpStr + cchLength;
3534 }
3535 dwDependenciesLength++;
3536
3537 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3538 if (!lpDependenciesW)
3539 {
3541 goto cleanup;
3542 }
3543 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3544 }
3545
3546 if (lpServiceStartName)
3547 {
3548 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3549 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3550 if (!lpServiceStartNameW)
3551 {
3553 goto cleanup;
3554 }
3555 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3556 }
3557
3558 if (lpDisplayName)
3559 {
3561 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3562 if (!lpDisplayNameW)
3563 {
3565 goto cleanup;
3566 }
3567 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3568 }
3569
3570 dwError = RChangeServiceConfigW(hService,
3571 dwServiceType,
3572 dwStartType,
3573 dwErrorControl,
3574 lpBinaryPathNameW,
3575 lpLoadOrderGroupW,
3576 lpdwTagId,
3577 (LPBYTE)lpDependenciesW,
3578 dwDependenciesLength,
3579 lpServiceStartNameW,
3580 lpPassword,
3581 dwPwSize,
3582 lpDisplayNameW);
3583
3584cleanup:
3585 if (lpBinaryPathNameW != NULL)
3586 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3587
3588 if (lpLoadOrderGroupW != NULL)
3589 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3590
3591 if (lpDependenciesW != NULL)
3592 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3593
3594 if (lpServiceStartNameW != NULL)
3595 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3596
3597 if (lpDisplayNameW != NULL)
3598 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3599
3600 return dwError;
3601}
3602
3603
3604/* Function 24 */
3605DWORD
3606WINAPI
3609 LPSTR lpServiceName,
3611 DWORD dwDesiredAccess,
3612 DWORD dwServiceType,
3613 DWORD dwStartType,
3614 DWORD dwErrorControl,
3615 LPSTR lpBinaryPathName,
3616 LPSTR lpLoadOrderGroup,
3617 LPDWORD lpdwTagId,
3618 LPBYTE lpDependencies,
3619 DWORD dwDependSize,
3620 LPSTR lpServiceStartName,
3621 LPBYTE lpPassword,
3622 DWORD dwPwSize,
3623 LPSC_RPC_HANDLE lpServiceHandle)
3624{
3625 DWORD dwError = ERROR_SUCCESS;
3626 LPWSTR lpServiceNameW = NULL;
3627 LPWSTR lpDisplayNameW = NULL;
3628 LPWSTR lpBinaryPathNameW = NULL;
3629 LPWSTR lpLoadOrderGroupW = NULL;
3630 LPWSTR lpDependenciesW = NULL;
3631 LPWSTR lpServiceStartNameW = NULL;
3632 DWORD dwDependenciesLength = 0;
3633 SIZE_T cchLength;
3634 int len;
3635 LPCSTR lpStr;
3636
3637 if (lpServiceName)
3638 {
3639 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3640 lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3641 if (!lpServiceNameW)
3642 {
3644 goto cleanup;
3645 }
3646 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3647 }
3648
3649 if (lpDisplayName)
3650 {
3652 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3653 if (!lpDisplayNameW)
3654 {
3656 goto cleanup;
3657 }
3658 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3659 }
3660
3661 if (lpBinaryPathName)
3662 {
3663 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3664 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3665 if (!lpBinaryPathNameW)
3666 {
3668 goto cleanup;
3669 }
3670 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3671 }
3672
3673 if (lpLoadOrderGroup)
3674 {
3675 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3676 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3677 if (!lpLoadOrderGroupW)
3678 {
3680 goto cleanup;
3681 }
3682 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3683 }
3684
3685 if (lpDependencies)
3686 {
3687 lpStr = (LPCSTR)lpDependencies;
3688 while (*lpStr)
3689 {
3690 cchLength = strlen(lpStr) + 1;
3691 dwDependenciesLength += (DWORD)cchLength;
3692 lpStr = lpStr + cchLength;
3693 }
3694 dwDependenciesLength++;
3695
3696 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3697 if (!lpDependenciesW)
3698 {
3700 goto cleanup;
3701 }
3702 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3703 }
3704
3705 if (lpServiceStartName)
3706 {
3707 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3708 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3709 if (!lpServiceStartNameW)
3710 {
3712 goto cleanup;
3713 }
3714 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3715 }
3716
3717 dwError = RCreateServiceW(hSCManager,
3718 lpServiceNameW,
3719 lpDisplayNameW,
3720 dwDesiredAccess,
3721 dwServiceType,
3722 dwStartType,
3723 dwErrorControl,
3724 lpBinaryPathNameW,
3725 lpLoadOrderGroupW,
3726 lpdwTagId,
3727 (LPBYTE)lpDependenciesW,
3728 dwDependenciesLength,
3729 lpServiceStartNameW,
3730 lpPassword,
3731 dwPwSize,
3732 lpServiceHandle);
3733
3734cleanup:
3735 if (lpServiceNameW !=NULL)
3736 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3737
3738 if (lpDisplayNameW != NULL)
3739 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3740
3741 if (lpBinaryPathNameW != NULL)
3742 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3743
3744 if (lpLoadOrderGroupW != NULL)
3745 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3746
3747 if (lpDependenciesW != NULL)
3748 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3749
3750 if (lpServiceStartNameW != NULL)
3751 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3752
3753 return dwError;
3754}
3755
3756
3757/* Function 25 */
3758DWORD
3759WINAPI
3761 SC_RPC_HANDLE hService,
3762 DWORD dwServiceState,
3763 LPBYTE lpServices,
3766 LPBOUNDED_DWORD_256K lpServicesReturned)
3767{
3768 DWORD dwError = ERROR_SUCCESS;
3769 DWORD dwServicesReturned = 0;
3770 DWORD dwServiceCount;
3772 PSERVICE_HANDLE hSvc;
3773 PSERVICE lpService = NULL;
3774 PSERVICE *lpServicesArray = NULL;
3775 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3776 LPSTR lpStr;
3777
3778 *pcbBytesNeeded = 0;
3779 *lpServicesReturned = 0;
3780
3781 DPRINT("REnumDependentServicesA() called\n");
3782
3783 hSvc = ScmGetServiceFromHandle(hService);
3784 if (hSvc == NULL)
3785 {
3786 DPRINT1("Invalid service handle\n");
3787 return ERROR_INVALID_HANDLE;
3788 }
3789
3790 lpService = hSvc->ServiceEntry;
3791
3792 /* Check access rights */
3795 {
3796 DPRINT("Insufficient access rights! 0x%lx\n",
3797 hSvc->Handle.DesiredAccess);
3798 return ERROR_ACCESS_DENIED;
3799 }
3800
3801 /* Open the Services Reg key */
3803 L"System\\CurrentControlSet\\Services",
3804 0,
3805 KEY_READ,
3806 &hServicesKey);
3807
3808 if (dwError != ERROR_SUCCESS)
3809 return dwError;
3810
3811 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3812 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3813 are the same for both. Verified in WINXP. */
3814
3815 /* First determine the bytes needed and get the number of dependent services*/
3817 lpService,
3818 dwServiceState,
3819 NULL,
3821 &dwServicesReturned);
3822 if (dwError != ERROR_SUCCESS)
3823 goto Done;
3824
3825 /* If buffer size is less than the bytes needed or pointer is null*/
3826 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3827 {
3828 dwError = ERROR_MORE_DATA;
3829 goto Done;
3830 }
3831
3832 /* Allocate memory for array of service pointers */
3833 lpServicesArray = HeapAlloc(GetProcessHeap(),
3835 (dwServicesReturned + 1) * sizeof(PSERVICE));
3836 if (!lpServicesArray)
3837 {
3838 DPRINT("Could not allocate buffer\n");
3839 dwError = ERROR_NOT_ENOUGH_MEMORY;
3840 goto Done;
3841 }
3842
3843 dwServicesReturned = 0;
3844 *pcbBytesNeeded = 0;
3845
3847 lpService,
3848 dwServiceState,
3849 lpServicesArray,
3851 &dwServicesReturned);
3852 if (dwError != ERROR_SUCCESS)
3853 {
3854 goto Done;
3855 }
3856
3857 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3858 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3859
3860 /* Copy EnumDepenedentService to Buffer */
3861 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3862 {
3863 lpService = lpServicesArray[dwServiceCount];
3864
3865 /* Copy the status info */
3866 memcpy(&lpServicesPtr->ServiceStatus,
3867 &lpService->Status,
3868 sizeof(SERVICE_STATUS));
3869
3870 /* Copy display name */
3872 0,
3873 lpService->lpDisplayName,
3874 -1,
3875 lpStr,
3876 (int)wcslen(lpService->lpDisplayName),
3877 0,
3878 0);
3879 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3880 lpStr += strlen(lpStr) + 1;
3881
3882 /* Copy service name */
3884 0,
3885 lpService->lpServiceName,
3886 -1,
3887 lpStr,
3888 (int)wcslen(lpService->lpServiceName),
3889 0,
3890 0);
3891 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3892 lpStr += strlen(lpStr) + 1;
3893
3894 lpServicesPtr++;
3895 }
3896
3897 *lpServicesReturned = dwServicesReturned;
3898
3899Done:
3900 if (lpServicesArray)
3901 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3902
3904
3905 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3906
3907 return dwError;
3908}
3909
3910
3911/* Function 26 */
3912DWORD
3913WINAPI
3916 DWORD dwServiceType,
3917 DWORD dwServiceState,
3919 DWORD dwBufSize,
3921 LPBOUNDED_DWORD_256K lpServicesReturned,
3922 LPBOUNDED_DWORD_256K lpResumeHandle)
3923{
3924 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3925 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
3926 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3927 LPWSTR lpStringPtrW;
3928 LPSTR lpStringPtrA;
3929 DWORD dwError;
3930 DWORD dwServiceCount;
3931
3932 DPRINT("REnumServicesStatusA() called\n");
3933
3934 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
3935 {
3936 return ERROR_INVALID_ADDRESS;
3937 }
3938
3939 if ((dwBufSize > 0) && (lpBuffer))
3940 {
3941 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3942 if (!lpStatusPtrW)
3943 {
3944 DPRINT("Failed to allocate buffer\n");
3946 }
3947 }
3948
3950 dwServiceType,
3951 dwServiceState,
3952 (LPBYTE)lpStatusPtrW,
3953 dwBufSize,
3955 lpServicesReturned,
3956 lpResumeHandle);
3957
3958 /* if no services were returned then we are Done */
3959 if (*lpServicesReturned == 0)
3960 goto Done;
3961
3962 lpStatusPtrIncrW = lpStatusPtrW;
3963 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3964 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3965 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3966 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3967 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3968
3969 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3970 {
3971 /* Copy the service name */
3973 0,
3974 lpStringPtrW,
3975 -1,
3976 lpStringPtrA,
3977 (int)wcslen(lpStringPtrW),
3978 0,
3979 0);
3980
3981 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3982 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3983 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3984
3985 /* Copy the display name */
3987 0,
3988 lpStringPtrW,
3989 -1,
3990 lpStringPtrA,
3991 (int)wcslen(lpStringPtrW),
3992 0,
3993 0);
3994
3995 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3996 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3997 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3998
3999 /* Copy the status information */
4000 memcpy(&lpStatusPtrA->ServiceStatus,
4001 &lpStatusPtrIncrW->ServiceStatus,
4002 sizeof(SERVICE_STATUS));
4003
4004 lpStatusPtrIncrW++;
4005 lpStatusPtrA++;
4006 }
4007
4008Done:
4009 if (lpStatusPtrW)
4010 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
4011
4012 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
4013
4014 return dwError;
4015}
4016
4017
4018/* Function 27 */
4019DWORD
4020WINAPI
4022 LPSTR lpMachineName,
4023 LPSTR lpDatabaseName,
4024 DWORD dwDesiredAccess,
4025 LPSC_RPC_HANDLE lpScHandle)
4026{
4028 UNICODE_STRING DatabaseName;
4029 DWORD dwError;
4030
4031 DPRINT("ROpenSCManagerA() called\n");
4032
4033 if (lpMachineName)
4035 lpMachineName);
4036
4037 if (lpDatabaseName)
4039 lpDatabaseName);
4040
4041 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
4042 lpDatabaseName ? DatabaseName.Buffer : NULL,
4043 dwDesiredAccess,
4044 lpScHandle);
4045
4046 if (lpMachineName)
4048
4049 if (lpDatabaseName)
4050 RtlFreeUnicodeString(&DatabaseName);
4051
4052 return dwError;
4053}
4054
4055
4056/* Function 28 */
4057DWORD
4058WINAPI
4061 LPSTR lpServiceName,
4062 DWORD dwDesiredAccess,
4063 LPSC_RPC_HANDLE lpServiceHandle)
4064{
4066 DWORD dwError;
4067
4068 DPRINT("ROpenServiceA() called\n");
4069
4070 if (lpServiceName)
4072 lpServiceName);
4073
4074 dwError = ROpenServiceW(hSCManager,
4075 lpServiceName ? ServiceName.Buffer : NULL,
4076 dwDesiredAccess,
4077 lpServiceHandle);
4078
4079 if (lpServiceName)
4081
4082 return dwError;
4083}
4084
4085
4086/* Function 29 */
4087DWORD
4088WINAPI
4090 SC_RPC_HANDLE hService,
4091 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4094{
4095 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
4096 DWORD dwError = ERROR_SUCCESS;
4097 PSERVICE_HANDLE hSvc;
4098 PSERVICE lpService = NULL;
4099 HKEY hServiceKey = NULL;
4100 LPWSTR lpImagePath = NULL;
4101 LPWSTR lpServiceStartName = NULL;
4102 LPWSTR lpDependencies = NULL;
4103 DWORD dwDependenciesLength = 0;
4104 DWORD dwRequiredSize;
4105 LPSTR lpStr;
4106
4107 DPRINT("RQueryServiceConfigA() called\n");
4108
4109 if (ScmShutdown)
4111
4112 hSvc = ScmGetServiceFromHandle(hService);
4113 if (hSvc == NULL)
4114 {
4115 DPRINT1("Invalid service handle\n");
4116 return ERROR_INVALID_HANDLE;
4117 }
4118
4121 {
4122 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4123 return ERROR_ACCESS_DENIED;
4124 }
4125
4126 lpService = hSvc->ServiceEntry;
4127 if (lpService == NULL)
4128 {
4129 DPRINT("lpService == NULL\n");
4130 return ERROR_INVALID_HANDLE;
4131 }
4132
4133 /* Lock the service database shared */
4135
4136 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4137 KEY_READ,
4138 &hServiceKey);
4139 if (dwError != ERROR_SUCCESS)
4140 goto Done;
4141
4142 /* Read the image path */
4143 dwError = ScmReadString(hServiceKey,
4144 L"ImagePath",
4145 &lpImagePath);
4146 if (dwError != ERROR_SUCCESS)
4147 goto Done;
4148
4149 /* Read the service start name */
4150 ScmReadString(hServiceKey,
4151 L"ObjectName",
4152 &lpServiceStartName);
4153
4154 /* Read the dependencies */
4155 ScmReadDependencies(hServiceKey,
4156 &lpDependencies,
4157 &dwDependenciesLength);
4158
4159 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA);
4160
4161 if (lpImagePath != NULL)
4162 dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
4163 else
4164 dwRequiredSize += 2 * sizeof(CHAR);
4165
4166 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
4167 dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
4168 else
4169 dwRequiredSize += 2 * sizeof(CHAR);
4170
4171 /* Add Dependencies length */
4172 if (lpDependencies != NULL)
4173 dwRequiredSize += dwDependenciesLength;
4174 else
4175 dwRequiredSize += 2 * sizeof(CHAR);
4176
4177 if (lpServiceStartName != NULL)
4178 dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
4179 else
4180 dwRequiredSize += 2 * sizeof(CHAR);
4181
4182 if (lpService->lpDisplayName != NULL)
4183 dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
4184 else
4185 dwRequiredSize += 2 * sizeof(CHAR);
4186
4187 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
4188 {
4189 dwError = ERROR_INSUFFICIENT_BUFFER;
4190 }
4191 else
4192 {
4193 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
4194 lpServiceConfig->dwStartType = lpService->dwStartType;
4195 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
4196 lpServiceConfig->dwTagId = lpService->dwTag;
4197
4198 lpStr = (LPSTR)(lpServiceConfig + 1);
4199
4200 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4201 Verified in WINXP */
4202
4203 if (lpImagePath)
4204 {
4206 0,
4207 lpImagePath,
4208 -1,
4209 lpStr,
4210 (int)(wcslen(lpImagePath) + 1),
4211 0,
4212 0);
4213 }
4214 else
4215 {
4216 *lpStr = 0;
4217 }
4218
4219 lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4220 lpStr += (strlen((LPSTR)lpStr) + 1);
4221
4222 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4223 {
4225 0,
4226 lpService->lpGroup->lpGroupName,
4227 -1,
4228 lpStr,
4229 (int)(wcslen(lpService->lpGroup->lpGroupName) + 1),
4230 0,
4231 0);
4232 }
4233 else
4234 {
4235 *lpStr = 0;
4236 }
4237
4238 lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4239 lpStr += (strlen(lpStr) + 1);
4240
4241 /* Append Dependencies */
4242 if (lpDependencies)
4243 {
4245 0,
4246 lpDependencies,
4247 dwDependenciesLength,
4248 lpStr,
4249 dwDependenciesLength,
4250 0,
4251 0);
4252 }
4253 else
4254 {
4255 *lpStr = 0;
4256 }
4257
4258 lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4259 if (lpDependencies)
4260 lpStr += dwDependenciesLength;
4261 else
4262 lpStr += (strlen(lpStr) + 1);
4263
4264 if (lpServiceStartName)
4265 {
4267 0,
4268 lpServiceStartName,
4269 -1,
4270 lpStr,
4271 (int)(wcslen(lpServiceStartName) + 1),
4272 0,
4273 0);
4274 }
4275 else
4276 {
4277 *lpStr = 0;
4278 }
4279
4280 lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4281 lpStr += (strlen(lpStr) + 1);
4282
4283 if (lpService->lpDisplayName)
4284 {
4286 0,
4287 lpService->lpDisplayName,
4288 -1,
4289 lpStr,
4290 (int)(wcslen(lpService->lpDisplayName) + 1),
4291 0,
4292 0);
4293 }
4294 else
4295 {
4296 *lpStr = 0;
4297 }
4298
4299 lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4300 }
4301
4302 if (pcbBytesNeeded != NULL)
4303 *pcbBytesNeeded = dwRequiredSize;
4304
4305Done:
4306 /* Unlock the service database */
4308
4309 if (lpImagePath != NULL)
4310 HeapFree(GetProcessHeap(), 0, lpImagePath);
4311
4312 if (lpServiceStartName != NULL)
4313 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4314
4315 if (lpDependencies != NULL)
4316 HeapFree(GetProcessHeap(), 0, lpDependencies);
4317
4318 if (hServiceKey != NULL)
4319 RegCloseKey(hServiceKey);
4320
4321 DPRINT("RQueryServiceConfigA() done\n");
4322
4323 return dwError;
4324}
4325
4326
4327/* Function 30 */
4328DWORD
4329WINAPI
4332 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4335{
4337 PMANAGER_HANDLE hMgr;
4338 DWORD dwRequiredSize;
4339
4340 if (!lpLockStatus || !pcbBytesNeeded)
4342
4344 if (hMgr == NULL)
4345 {
4346 DPRINT1("Invalid service manager handle\n");
4347 return ERROR_INVALID_HANDLE;
4348 }
4349
4352 {
4353 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
4354 return ERROR_ACCESS_DENIED;
4355 }
4356
4357 /* FIXME: we need to compute instead the real length of the owner name */
4358 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR);
4359 *pcbBytesNeeded = dwRequiredSize;
4360
4361 if (cbBufSize < dwRequiredSize)
4363
4364 ScmQueryServiceLockStatusA(lpLockStatus);
4365
4366 return ERROR_SUCCESS;
4367}
4368
4369
4370/* Function 31 */
4371DWORD
4372WINAPI
4374 SC_RPC_HANDLE hService,
4375 DWORD argc,
4377{
4378 DWORD dwError = ERROR_SUCCESS;
4379 PSERVICE_HANDLE hSvc;
4380 PSERVICE lpService = NULL;
4381 PWSTR* pVector = NULL;
4382 DWORD i;
4384
4385 DPRINT("RStartServiceA() called\n");
4386
4387 if (ScmShutdown)
4389
4390 hSvc = ScmGetServiceFromHandle(hService);
4391 if (hSvc == NULL)
4392 {
4393 DPRINT1("Invalid service handle\n");
4394 return ERROR_INVALID_HANDLE;
4395 }
4396
4399 {
4400 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4401 return ERROR_ACCESS_DENIED;
4402 }
4403
4404 lpService = hSvc->ServiceEntry;
4405 if (lpService == NULL)
4406 {
4407 DPRINT("lpService == NULL\n");
4408 return ERROR_INVALID_HANDLE;
4409 }
4410
4411 if (lpService->dwStartType == SERVICE_DISABLED)
4413
4414 if (lpService->bDeleted)
4416
4417 /* Build a Unicode argument vector */
4418 if (argc > 0)
4419 {
4420 pVector = HeapAlloc(GetProcessHeap(),
4422 argc * sizeof(PWSTR));
4423 if (!pVector)
4425
4426 for (i = 0; i < argc; i++)
4427 {
4429 0,
4430 argv[i].StringPtr,
4431 -1,
4432 NULL,
4433 0);
4434
4435 pVector[i] = HeapAlloc(GetProcessHeap(),
4437 dwLength * sizeof(WCHAR));
4438 if (!pVector[i])
4439 {
4440 dwError = ERROR_NOT_ENOUGH_MEMORY;
4441 goto done;
4442 }
4443
4445 0,
4446 argv[i].StringPtr,
4447 -1,
4448 pVector[i],
4449 dwLength);
4450 }
4451 }
4452
4453 /* Start the service */
4454 dwError = ScmStartService(lpService, argc, (PCWSTR*)pVector);
4455
4456done:
4457 /* Free the Unicode argument vector */
4458 if (pVector)
4459 {
4460 for (i = 0; i < argc; i++)
4461 {
4462 if (pVector[i])
4463 HeapFree(GetProcessHeap(), 0, pVector[i]);
4464 }
4465 HeapFree(GetProcessHeap(), 0, pVector);
4466 }
4467
4468 return dwError;
4469}
4470
4471
4472/* Function 32 */
4473DWORD
4474WINAPI
4477 LPCSTR lpServiceName,
4479 LPBOUNDED_DWORD_4K lpcchBuffer)
4480{
4481 // PMANAGER_HANDLE hManager;
4482 PSERVICE lpService = NULL;
4483 LPCWSTR lpSvcDisplayName;
4484 LPWSTR lpServiceNameW;
4486
4487 DPRINT("RGetServiceDisplayNameA() called\n");
4488 DPRINT("hSCManager = %p\n", hSCManager);
4489 DPRINT("lpServiceName: %s\n", lpServiceName);
4490 DPRINT("lpDisplayName: %p\n", lpDisplayName);
4491 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4492
4493#if 0
4494 hManager = (PMANAGER_HANDLE)hSCManager;
4495 if (hManager->Handle.Tag != MANAGER_TAG)
4496 {
4497 DPRINT("Invalid manager handle\n");
4498 return ERROR_INVALID_HANDLE;
4499 }
4500#endif
4501
4502 /* Get service database entry */
4503 if (lpServiceName != NULL)
4504 {
4505 dwLength = (DWORD)(strlen(lpServiceName) + 1);
4506 lpServiceNameW = HeapAlloc(GetProcessHeap(),
4508 dwLength * sizeof(WCHAR));
4509 if (!lpServiceNameW)
4511
4513 0,
4514 lpServiceName,
4515 -1,
4516 lpServiceNameW,
4517 dwLength);
4518
4519 lpService = ScmGetServiceEntryByName(lpServiceNameW);
4520
4521 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4522 }
4523
4524 if (lpService == NULL)
4525 {
4526 DPRINT("Could not find service\n");
4528 }
4529
4530 if (lpService->lpDisplayName)
4531 lpSvcDisplayName = lpService->lpDisplayName;
4532 else
4533 lpSvcDisplayName = lpService->lpServiceName;
4534
4535 /*
4536 * NOTE: On Windows the comparison on *lpcchBuffer is made against
4537 * the number of (wide) characters of the UNICODE display name, and
4538 * not against the number of bytes needed to store the ANSI string.
4539 */
4540 dwLength = (DWORD)wcslen(lpSvcDisplayName);
4541
4542 if (*lpcchBuffer > dwLength)
4543 {
4544 if (lpDisplayName != NULL &&
4546 0,
4547 lpSvcDisplayName,
4548 -1,
4550 (int)*lpcchBuffer,
4551 NULL,
4552 NULL) == 0)
4553 {
4554 /*
4555 * But then, if *lpcchBuffer was greater than the number of
4556 * (wide) characters of the UNICODE display name, yet smaller
4557 * than the number of bytes needed due to the possible presence
4558 * of DBCS characters, the *exact* number of bytes is returned
4559 * (without the NULL terminator).
4560 */
4562 0,
4563 lpSvcDisplayName,
4564 (int)dwLength,
4565 NULL,
4566 0,
4567 NULL,
4568 NULL);
4569 *lpDisplayName = 0;
4570 *lpcchBuffer = dwLength;
4572 }
4573
4574 /*
4575 * NOTE: On Windows, RGetServiceDisplayNameA() does not update
4576 * *lpcchBuffer on success, contrary to RGetServiceDisplayNameW().
4577 */
4578 return ERROR_SUCCESS;
4579 }
4580 else
4581 {
4582 /*
4583 * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4584 * (wide) characters of the UNICODE display name, only an upper
4585 * estimation is returned by doubling the string length, to account
4586 * for the presence of any possible DBCS characters.
4587 */
4588 *lpcchBuffer = dwLength * sizeof(WCHAR);
4590 }
4591}
4592
4593
4594/* Function 33 */
4595DWORD
4596WINAPI
4600 LPSTR lpServiceName,
4601 LPBOUNDED_DWORD_4K lpcchBuffer)
4602{
4603 // PMANAGER_HANDLE hManager;
4604 PSERVICE lpService;
4605 LPWSTR lpDisplayNameW;
4607
4608 DPRINT("RGetServiceKeyNameA() called\n");
4609 DPRINT("hSCManager = %p\n", hSCManager);
4610 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4611 DPRINT("lpServiceName: %p\n", lpServiceName);
4612 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4613
4614#if 0
4615 hManager = (PMANAGER_HANDLE)hSCManager;
4616 if (hManager->Handle.Tag != MANAGER_TAG)
4617 {
4618 DPRINT("Invalid manager handle\n");
4619 return ERROR_INVALID_HANDLE;
4620 }
4621#endif
4622
4623 /* Get service database entry */
4624
4626 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4628 dwLength * sizeof(WCHAR));
4629 if (!lpDisplayNameW)
4631
4633 0,
4635 -1,
4636 lpDisplayNameW,
4637 dwLength);
4638
4639 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4640
4641 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4642
4643 if (lpService == NULL)
4644 {
4645 DPRINT("Could not find service\n");
4647 }
4648
4649 /*
4650 * NOTE: On Windows the comparison on *lpcchBuffer is made against
4651 * the number of (wide) characters of the UNICODE service name, and
4652 * not against the number of bytes needed to store the ANSI string.
4653 */
4654 dwLength = (DWORD)wcslen(lpService->lpServiceName);
4655
4656 if (*lpcchBuffer > dwLength)
4657 {
4658 if (lpServiceName != NULL &&
4660 0,
4661 lpService->lpServiceName,
4662 -1,
4663 lpServiceName,
4664 (int)*lpcchBuffer,
4665 NULL,
4666 NULL) == 0)
4667 {
4668 /*
4669 * But then, if *lpcchBuffer was greater than the number of
4670 * (wide) characters of the UNICODE service name, yet smaller
4671 * than the number of bytes needed due to the possible presence
4672 * of DBCS characters, the *exact* number of bytes is returned
4673 * (without the NULL terminator).
4674 */
4676 0,
4677 lpService->lpServiceName,
4678 (int)dwLength,
4679 NULL,
4680 0,
4681 NULL,
4682 NULL);
4683 *lpServiceName = 0;
4684 *lpcchBuffer = dwLength;
4686 }
4687
4688 /*
4689 * NOTE: On Windows, RGetServiceKeyNameA() does not update
4690 * *lpcchBuffer on success, contrary to RGetServiceKeyNameW().
4691 */
4692 return ERROR_SUCCESS;
4693 }
4694 else
4695 {
4696 /*
4697 * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4698 * (wide) characters of the UNICODE service name, only an upper
4699 * estimation is returned by doubling the string length, to account
4700 * for the presence of any possible DBCS characters.
4701 */
4702 *lpcchBuffer = dwLength * sizeof(WCHAR);
4704 }
4705}
4706
4707
4708/* Function 34 */
4709DWORD
4710WINAPI
4713 LPWSTR lpLoadOrderGroup,
4714 LPDWORD lpState)
4715{
4716 PMANAGER_HANDLE hManager;
4717 PSERVICE_GROUP pServiceGroup;
4718 DWORD dwError = ERROR_SUCCESS;
4719
4720 DPRINT("RI_ScGetCurrentGroupStateW() called\n");
4721
4722 if (ScmShutdown)
4724
4726 if (hManager == NULL)
4727 {
4728 DPRINT1("Invalid service manager handle\n");
4729 return ERROR_INVALID_HANDLE;
4730 }
4731
4732 /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */
4735 {
4736 DPRINT("Insufficient access rights! 0x%lx\n",
4737 hManager->Handle.DesiredAccess);
4738 return ERROR_ACCESS_DENIED;
4739 }
4740
4741 /* Lock the service database shared */
4743
4744 /* Get the group list entry */
4745 pServiceGroup = ScmGetServiceGroupByName(lpLoadOrderGroup);
4746 if (pServiceGroup == NULL)
4747 {
4749 goto done;
4750 }
4751
4752 /* FIXME: Return the group state */
4753 *lpState = 0;
4754
4755done:
4756 /* Unlock the service database */
4758
4759 DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError);
4760
4761 return dwError;
4762}
4763
4764
4765/* Function 35 */
4766DWORD
4767WINAPI
4770 DWORD dwServiceType,
4771 DWORD dwServiceState,
4775 LPBOUNDED_DWORD_256K lpServicesReturned,
4776 LPBOUNDED_DWORD_256K lpResumeIndex,
4777 LPCWSTR pszGroupName)
4778{
4779 PMANAGER_HANDLE hManager;
4780 PSERVICE lpService;
4781 DWORD dwError = ERROR_SUCCESS;
4782 PLIST_ENTRY ServiceEntry;
4783 PSERVICE CurrentService;
4784 DWORD dwState;
4785 DWORD dwRequiredSize;
4786 DWORD dwServiceCount;
4787 DWORD dwSize;
4788 DWORD dwLastResumeCount = 0;
4789 LPENUM_SERVICE_STATUSW lpStatusPtr;
4790 LPWSTR lpStringPtr;
4791
4792 DPRINT("REnumServiceGroupW() called\n");
4793
4794 if (ScmShutdown)
4796
4798 if (hManager == NULL)
4799 {
4800 DPRINT1("Invalid service manager handle\n");
4801 return ERROR_INVALID_HANDLE;
4802 }
4803
4804 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
4805 {
4806 return ERROR_INVALID_ADDRESS;
4807 }
4808
4809 *pcbBytesNeeded = 0;
4810 *lpServicesReturned = 0;
4811
4812 if ((dwServiceType == 0) ||
4813 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
4814 {
4815 DPRINT("Invalid Service Type\n");
4817 }
4818
4819 if ((dwServiceState == 0) ||
4820 ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
4821 {
4822 DPRINT("Invalid Service State\n");
4824 }
4825
4826 /* Check access rights */
4829 {
4830 DPRINT("Insufficient access rights! 0x%lx\n",
4831 hManager->Handle.DesiredAccess);
4832 return ERROR_ACCESS_DENIED;
4833 }
4834
4835 if (lpResumeIndex)
4836 dwLastResumeCount = *lpResumeIndex;
4837
4838 /* Lock the service database shared */
4840
4841 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4842 if (lpService == NULL)
4843 {
4844 dwError = ERROR_SUCCESS;
4845 goto Done;
4846 }
4847
4848 dwRequiredSize = 0;
4849 dwServiceCount = 0;
4850
4851 for (ServiceEntry = &lpService->ServiceListEntry;
4852 ServiceEntry != &ServiceListHead;
4853 ServiceEntry = ServiceEntry->Flink)
4854 {
4855 CurrentService = CONTAINING_RECORD(ServiceEntry,
4856 SERVICE,
4857 ServiceListEntry);
4858
4859 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4860 continue;
4861
4862 dwState = SERVICE_ACTIVE;
4863 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4864 dwState = SERVICE_INACTIVE;
4865
4866 if ((dwState & dwServiceState) == 0)
4867 continue;
4868
4869 if (pszGroupName)
4870 {
4871 if (*pszGroupName == 0)
4872 {
4873 if (CurrentService->lpGroup != NULL)
4874 continue;
4875 }
4876 else
4877 {
4878 if ((CurrentService->lpGroup == NULL) ||
4879 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4880 continue;
4881 }
4882 }
4883
4884 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4885 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4886 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4887
4888 if (dwRequiredSize + dwSize > cbBufSize)
4889 {
4890 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4891 break;
4892 }
4893
4894 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4895 dwRequiredSize += dwSize;
4896 dwServiceCount++;
4897 dwLastResumeCount = CurrentService->dwResumeCount;
4898 }
4899
4900 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4901 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4902
4903 for (;
4904 ServiceEntry != &ServiceListHead;
4905 ServiceEntry = ServiceEntry->Flink)
4906 {
4907 CurrentService = CONTAINING_RECORD(ServiceEntry,