ReactOS 0.4.15-dev-7906-g1b85a5f
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/* Internal recursive function */
781/* Need to search for every dependency on every service */
782static DWORD
784 PSERVICE lpService,
785 DWORD dwServiceState,
786 PSERVICE *lpServices,
788 LPDWORD lpServicesReturned)
789{
790 DWORD dwError = ERROR_SUCCESS;
791 WCHAR szNameBuf[MAX_PATH];
792 WCHAR szValueBuf[MAX_PATH];
793 WCHAR *lpszNameBuf = szNameBuf;
794 WCHAR *lpszValueBuf = szValueBuf;
796 DWORD dwNumSubKeys;
797 DWORD dwIteration;
798 PSERVICE lpCurrentService;
799 HKEY hServiceEnumKey;
800 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
801 DWORD dwDependServiceStrPtr = 0;
802 DWORD dwRequiredSize = 0;
803
804 /* Get the number of service keys */
806 NULL,
807 NULL,
808 NULL,
809 &dwNumSubKeys,
810 NULL,
811 NULL,
812 NULL,
813 NULL,
814 NULL,
815 NULL,
816 NULL);
817 if (dwError != ERROR_SUCCESS)
818 {
819 DPRINT("ERROR! Unable to get number of services keys\n");
820 return dwError;
821 }
822
823 /* Iterate the service keys to see if another service depends on the this service */
824 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
825 {
827 dwError = RegEnumKeyExW(hServicesKey,
828 dwIteration,
829 lpszNameBuf,
830 &dwSize,
831 NULL,
832 NULL,
833 NULL,
834 NULL);
835 if (dwError != ERROR_SUCCESS)
836 return dwError;
837
838 /* Open the Service key */
839 dwError = RegOpenKeyExW(hServicesKey,
840 lpszNameBuf,
841 0,
842 KEY_READ,
843 &hServiceEnumKey);
844 if (dwError != ERROR_SUCCESS)
845 return dwError;
846
847 dwSize = MAX_PATH * sizeof(WCHAR);
848
849 /* Check for the DependOnService Value */
850 dwError = RegQueryValueExW(hServiceEnumKey,
851 L"DependOnService",
852 NULL,
853 NULL,
854 (LPBYTE)lpszValueBuf,
855 &dwSize);
856
857 /* FIXME: Handle load order. */
858
859 /* If the service found has a DependOnService value */
860 if (dwError == ERROR_SUCCESS)
861 {
862 dwDependServiceStrPtr = 0;
863
864 /* Can be more than one Dependencies in the DependOnService string */
865 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
866 {
867 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
868 {
869 /* Get the current enumed service pointer */
870 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
871
872 /* Check for valid Service */
873 if (!lpCurrentService)
874 {
875 /* This should never happen! */
876 DPRINT("This should not happen at this point, report to Developer\n");
877 return ERROR_NOT_FOUND;
878 }
879
880 /* Determine state the service is in */
881 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
882 dwCurrentServiceState = SERVICE_INACTIVE;
883
884 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
885 if ((dwCurrentServiceState == dwServiceState) ||
886 (dwServiceState == SERVICE_STATE_ALL))
887 {
888 /* Calculate the required size */
889 dwRequiredSize += sizeof(SERVICE_STATUS);
890 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
891 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
892
893 /* Add the size for service name and display name pointers */
894 dwRequiredSize += (2 * sizeof(PVOID));
895
896 /* increase the BytesNeeded size */
897 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
898
899 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
900 comes first */
901
902 /* Recursive call to check for its dependencies */
904 lpCurrentService,
905 dwServiceState,
906 lpServices,
908 lpServicesReturned);
909
910 /* If the lpServices is valid set the service pointer */
911 if (lpServices)
912 lpServices[*lpServicesReturned] = lpCurrentService;
913
914 *lpServicesReturned = *lpServicesReturned + 1;
915 }
916 }
917
918 dwDependServiceStrPtr += (DWORD)(wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
919 }
920 }
921 else if (*pcbBytesNeeded)
922 {
923 dwError = ERROR_SUCCESS;
924 }
925
926 RegCloseKey(hServiceEnumKey);
927 }
928
929 return dwError;
930}
931
932
933/* Function 0 */
934DWORD
935WINAPI
937 LPSC_RPC_HANDLE hSCObject)
938{
939 PMANAGER_HANDLE hManager;
940 PSERVICE_HANDLE hService;
941 PSERVICE lpService;
943 DWORD dwError;
945 DWORD dwServicesReturned = 0;
946
947 DPRINT("RCloseServiceHandle() called\n");
948
949 DPRINT("hSCObject = %p\n", *hSCObject);
950
951 if (*hSCObject == 0)
953
954 hManager = ScmGetServiceManagerFromHandle(*hSCObject);
955 hService = ScmGetServiceFromHandle(*hSCObject);
956
957 if (hManager != NULL)
958 {
959 DPRINT("Found manager handle\n");
960
961 /* Make sure we don't access stale memory if someone tries to use this handle again. */
962 hManager->Handle.Tag = INVALID_TAG;
963
964 HeapFree(GetProcessHeap(), 0, hManager);
965 hManager = NULL;
966
967 *hSCObject = NULL;
968
969 DPRINT("RCloseServiceHandle() done\n");
970 return ERROR_SUCCESS;
971 }
972 else if (hService != NULL)
973 {
974 DPRINT("Found service handle\n");
975
976 /* Lock the service database exclusively */
978
979 /* Get the pointer to the service record */
980 lpService = hService->ServiceEntry;
981
982 /* Make sure we don't access stale memory if someone tries to use this handle again. */
983 hService->Handle.Tag = INVALID_TAG;
984
985 /* Free the handle */
986 HeapFree(GetProcessHeap(), 0, hService);
987 hService = NULL;
988
989 ASSERT(lpService->dwRefCount > 0);
990
991 lpService->dwRefCount--;
992 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
993 lpService->dwRefCount);
994
995 if (lpService->dwRefCount == 0)
996 {
997 /* If this service has been marked for deletion */
998 if (lpService->bDeleted &&
1000 {
1001 /* Open the Services Reg key */
1003 L"System\\CurrentControlSet\\Services",
1004 0,
1006 &hServicesKey);
1007 if (dwError != ERROR_SUCCESS)
1008 {
1009 DPRINT("Failed to open services key\n");
1011 return dwError;
1012 }
1013
1014 /* Call the internal function with NULL, just to get bytes we need */
1016 lpService,
1018 NULL,
1020 &dwServicesReturned);
1021
1022 /* If pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1023 if (pcbBytesNeeded)
1024 {
1025 DPRINT("Deletion failed due to running dependencies\n");
1028 return ERROR_SUCCESS;
1029 }
1030
1031 /* There are no references and no running dependencies,
1032 it is now safe to delete the service */
1033
1034 /* Delete the Service Key */
1035 dwError = ScmDeleteRegKey(hServicesKey,
1036 lpService->lpServiceName);
1037
1039
1040 if (dwError != ERROR_SUCCESS)
1041 {
1042 DPRINT("Failed to Delete the Service Registry key\n");
1044 return dwError;
1045 }
1046
1047 /* Delete the Service */
1048 ScmDeleteServiceRecord(lpService);
1049 }
1050 }
1051
1053
1054 *hSCObject = NULL;
1055
1056 DPRINT("RCloseServiceHandle() done\n");
1057 return ERROR_SUCCESS;
1058 }
1059
1060 DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
1061
1062 return ERROR_INVALID_HANDLE;
1063}
1064
1065
1066/* Function 1 */
1067DWORD
1068WINAPI
1070 SC_RPC_HANDLE hService,
1071 DWORD dwControl,
1072 LPSERVICE_STATUS lpServiceStatus)
1073{
1074 PSERVICE_HANDLE hSvc;
1075 PSERVICE lpService;
1077 DWORD dwError = ERROR_SUCCESS;
1079 DWORD dwServicesReturned = 0;
1080 DWORD dwControlsAccepted;
1081 DWORD dwCurrentState;
1083 LPCWSTR lpLogStrings[2];
1084 WCHAR szLogBuffer[80];
1085 UINT uID;
1086
1087 DPRINT("RControlService() called\n");
1088
1089 if (ScmShutdown)
1091
1092 /* Check the service handle */
1093 hSvc = ScmGetServiceFromHandle(hService);
1094 if (hSvc == NULL)
1095 {
1096 DPRINT1("Invalid service handle\n");
1097 return ERROR_INVALID_HANDLE;
1098 }
1099
1100 /* Check the service entry point */
1101 lpService = hSvc->ServiceEntry;
1102 if (lpService == NULL)
1103 {
1104 DPRINT1("lpService == NULL\n");
1105 return ERROR_INVALID_HANDLE;
1106 }
1107
1108 /* Check access rights */
1109 switch (dwControl)
1110 {
1113 break;
1114
1123 break;
1124
1127 break;
1128
1129 default:
1130 if (dwControl >= 128 && dwControl <= 255)
1132 else
1134 break;
1135 }
1136
1139 return ERROR_ACCESS_DENIED;
1140
1141 /* Return the current service status information */
1142 RtlCopyMemory(lpServiceStatus,
1143 &lpService->Status,
1144 sizeof(SERVICE_STATUS));
1145
1146 if (dwControl == SERVICE_CONTROL_STOP)
1147 {
1148 /* Check if the service has dependencies running as windows
1149 doesn't stop a service that does */
1150
1151 /* Open the Services Reg key */
1153 L"System\\CurrentControlSet\\Services",
1154 0,
1155 KEY_READ,
1156 &hServicesKey);
1157 if (dwError != ERROR_SUCCESS)
1158 {
1159 DPRINT("Failed to open services key\n");
1160 return dwError;
1161 }
1162
1163 /* Call the internal function with NULL, just to get bytes we need */
1165 lpService,
1167 NULL,
1169 &dwServicesReturned);
1170
1172
1173 /* If pcbBytesNeeded is not zero then there are services running that
1174 are dependent on this service */
1175 if (pcbBytesNeeded != 0)
1176 {
1177 DPRINT("Service has running dependencies. Failed to stop service\n");
1179 }
1180 }
1181
1182 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1183 {
1184 /* Send control code to the driver */
1185 dwError = ScmControlDriver(lpService,
1186 dwControl,
1187 lpServiceStatus);
1188 }
1189 else
1190 {
1191 dwControlsAccepted = lpService->Status.dwControlsAccepted;
1192 dwCurrentState = lpService->Status.dwCurrentState;
1193
1194 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1195 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1197
1198 /* Check the current state before sending a control request */
1199 switch (dwCurrentState)
1200 {
1202 case SERVICE_STOPPED:
1204
1206 switch (dwControl)
1207 {
1209 break;
1210
1212 RtlCopyMemory(lpServiceStatus,
1213 &lpService->Status,
1214 sizeof(SERVICE_STATUS));
1215 return ERROR_SUCCESS;
1216
1217 default:
1219 }
1220 break;
1221 }
1222
1223 /* Check if the control code is acceptable to the service */
1224 switch (dwControl)
1225 {
1227 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1229 break;
1230
1233 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1235 break;
1236
1238 if ((dwControlsAccepted & SERVICE_ACCEPT_PARAMCHANGE) == 0)
1240 break;
1241
1246 if ((dwControlsAccepted & SERVICE_ACCEPT_NETBINDCHANGE) == 0)
1248 break;
1249 }
1250
1251 /* Send control code to the service */
1252 dwError = ScmControlService(lpService->lpImage->hControlPipe,
1253 lpService->lpServiceName,
1254 (SERVICE_STATUS_HANDLE)lpService,
1255 dwControl);
1256
1257 /* Return service status information */
1258 RtlCopyMemory(lpServiceStatus,
1259 &lpService->Status,
1260 sizeof(SERVICE_STATUS));
1261 }
1262
1263 if (dwError == ERROR_SUCCESS)
1264 {
1265 if (dwControl == SERVICE_CONTROL_STOP ||
1266 dwControl == SERVICE_CONTROL_PAUSE ||
1267 dwControl == SERVICE_CONTROL_CONTINUE)
1268 {
1269 /* Log a successful send control */
1270
1271 switch (dwControl)
1272 {
1274 uID = IDS_SERVICE_STOP;
1275 break;
1276
1278 uID = IDS_SERVICE_PAUSE;
1279 break;
1280
1282 uID = IDS_SERVICE_RESUME;
1283 break;
1284 }
1285 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1286
1287 lpLogStrings[0] = lpService->lpDisplayName;
1288 lpLogStrings[1] = szLogBuffer;
1289
1292 2,
1293 lpLogStrings);
1294 }
1295 }
1296
1297 return dwError;
1298}
1299
1300
1301/* Function 2 */
1302DWORD
1303WINAPI
1305 SC_RPC_HANDLE hService)
1306{
1307 PSERVICE_HANDLE hSvc;
1308 PSERVICE lpService;
1309 DWORD dwError;
1310
1311 DPRINT("RDeleteService() called\n");
1312
1313 if (ScmShutdown)
1315
1316 hSvc = ScmGetServiceFromHandle(hService);
1317 if (hSvc == NULL)
1318 {
1319 DPRINT1("Invalid service handle\n");
1320 return ERROR_INVALID_HANDLE;
1321 }
1322
1324 DELETE))
1325 return ERROR_ACCESS_DENIED;
1326
1327 lpService = hSvc->ServiceEntry;
1328 if (lpService == NULL)
1329 {
1330 DPRINT("lpService == NULL\n");
1331 return ERROR_INVALID_HANDLE;
1332 }
1333
1334 /* Lock the service database exclusively */
1336
1337 if (lpService->bDeleted)
1338 {
1339 DPRINT("Service has already been marked for delete\n");
1341 goto Done;
1342 }
1343
1344 /* Mark service for delete */
1345 lpService->bDeleted = TRUE;
1346
1347 dwError = ScmMarkServiceForDelete(lpService);
1348
1349Done:
1350 /* Unlock the service database */
1352
1353 DPRINT("RDeleteService() done\n");
1354
1355 return dwError;
1356}
1357
1358
1359/* Function 3 */
1360DWORD
1361WINAPI
1364 LPSC_RPC_LOCK lpLock)
1365{
1366 PMANAGER_HANDLE hMgr;
1367
1368 DPRINT("RLockServiceDatabase() called\n");
1369
1370 *lpLock = NULL;
1371
1373 if (hMgr == NULL)
1374 {
1375 DPRINT1("Invalid service manager handle\n");
1376 return ERROR_INVALID_HANDLE;
1377 }
1378
1381 return ERROR_ACCESS_DENIED;
1382
1383 return ScmAcquireServiceStartLock(FALSE, lpLock);
1384}
1385
1386
1387/* Function 4 */
1388DWORD
1389WINAPI
1391 SC_RPC_HANDLE hService,
1392 SECURITY_INFORMATION dwSecurityInformation,
1393 LPBYTE lpSecurityDescriptor,
1396{
1397 PSERVICE_HANDLE hSvc;
1398 PSERVICE lpService;
1399 ULONG DesiredAccess = 0;
1401 DWORD dwBytesNeeded;
1402 DWORD dwError;
1403
1404 DPRINT("RQueryServiceObjectSecurity() called\n");
1405
1406 hSvc = ScmGetServiceFromHandle(hService);
1407 if (hSvc == NULL)
1408 {
1409 DPRINT1("Invalid service handle\n");
1410 return ERROR_INVALID_HANDLE;
1411 }
1412
1413 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1417
1418 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1420
1423 {
1424 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1425 return ERROR_ACCESS_DENIED;
1426 }
1427
1428 lpService = hSvc->ServiceEntry;
1429 if (lpService == NULL)
1430 {
1431 DPRINT("lpService == NULL\n");
1432 return ERROR_INVALID_HANDLE;
1433 }
1434
1435 /* Lock the service database */
1437
1438 /* Retrieve the security descriptor */
1440 dwSecurityInformation,
1441 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1442 cbBufSize,
1443 &dwBytesNeeded);
1444
1445 /* Unlock the service database */
1447
1448 if (NT_SUCCESS(Status))
1449 {
1450 *pcbBytesNeeded = dwBytesNeeded;
1451 dwError = STATUS_SUCCESS;
1452 }
1453 else if (Status == STATUS_BUFFER_TOO_SMALL)
1454 {
1455 *pcbBytesNeeded = dwBytesNeeded;
1456 dwError = ERROR_INSUFFICIENT_BUFFER;
1457 }
1459 {
1460 dwError = ERROR_GEN_FAILURE;
1461 }
1462 else
1463 {
1464 dwError = RtlNtStatusToDosError(Status);
1465 }
1466
1467 return dwError;
1468}
1469
1470
1471/* Function 5 */
1472DWORD
1473WINAPI
1475 SC_RPC_HANDLE hService,
1476 DWORD dwSecurityInformation,
1477 LPBYTE lpSecurityDescriptor,
1478 DWORD dwSecurityDescriptorSize)
1479{
1480 PSERVICE_HANDLE hSvc;
1481 PSERVICE lpService;
1483 HANDLE hToken = NULL;
1484 HKEY hServiceKey = NULL;
1485 BOOL bDatabaseLocked = FALSE;
1487 DWORD dwError;
1488
1489 DPRINT("RSetServiceObjectSecurity() called\n");
1490
1491 hSvc = ScmGetServiceFromHandle(hService);
1492 if (hSvc == NULL)
1493 {
1494 DPRINT1("Invalid service handle\n");
1495 return ERROR_INVALID_HANDLE;
1496 }
1497
1498 if (dwSecurityInformation == 0 ||
1499 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1501 {
1503 }
1504
1505 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1507
1508 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1510
1511 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1513
1514 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1516
1517 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1518 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1519 {
1521 }
1522
1523 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1524 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1525 {
1527 }
1528
1531 {
1532 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1533 return ERROR_ACCESS_DENIED;
1534 }
1535
1536 lpService = hSvc->ServiceEntry;
1537 if (lpService == NULL)
1538 {
1539 DPRINT1("lpService == NULL\n");
1540 return ERROR_INVALID_HANDLE;
1541 }
1542
1543 if (lpService->bDeleted)
1545
1546#if 0
1548
1550 8,
1551 TRUE,
1552 &hToken);
1553 if (!NT_SUCCESS(Status))
1555
1557#endif
1558
1559 /* Build the new security descriptor */
1560 Status = RtlSetSecurityObject(dwSecurityInformation,
1561 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1562 &lpService->pSecurityDescriptor,
1564 hToken);
1565 if (!NT_SUCCESS(Status))
1566 {
1567 dwError = RtlNtStatusToDosError(Status);
1568 goto Done;
1569 }
1570
1571 /* Lock the service database exclusive */
1573 bDatabaseLocked = TRUE;
1574
1575 /* Open the service key */
1576 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1578 &hServiceKey);
1579 if (dwError != ERROR_SUCCESS)
1580 goto Done;
1581
1582 /* Store the new security descriptor */
1583 dwError = ScmWriteSecurityDescriptor(hServiceKey,
1584 lpService->pSecurityDescriptor);
1585
1586 RegFlushKey(hServiceKey);
1587
1588Done:
1589 if (hServiceKey != NULL)
1590 RegCloseKey(hServiceKey);
1591
1592 /* Unlock service database */
1593 if (bDatabaseLocked == TRUE)
1595
1596 if (hToken != NULL)
1597 NtClose(hToken);
1598
1599 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1600
1601 return dwError;
1602}
1603
1604
1605/* Function 6 */
1606DWORD
1607WINAPI
1609 SC_RPC_HANDLE hService,
1610 LPSERVICE_STATUS lpServiceStatus)
1611{
1612 PSERVICE_HANDLE hSvc;
1613 PSERVICE lpService;
1614
1615 DPRINT("RQueryServiceStatus() called\n");
1616
1617 if (ScmShutdown)
1619
1620 hSvc = ScmGetServiceFromHandle(hService);
1621 if (hSvc == NULL)
1622 {
1623 DPRINT1("Invalid service handle\n");
1624 return ERROR_INVALID_HANDLE;
1625 }
1626
1629 {
1630 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1631 return ERROR_ACCESS_DENIED;
1632 }
1633
1634 lpService = hSvc->ServiceEntry;
1635 if (lpService == NULL)
1636 {
1637 DPRINT("lpService == NULL\n");
1638 return ERROR_INVALID_HANDLE;
1639 }
1640
1641 /* Lock the service database shared */
1643
1644 /* Return service status information */
1645 RtlCopyMemory(lpServiceStatus,
1646 &lpService->Status,
1647 sizeof(SERVICE_STATUS));
1648
1649 /* Unlock the service database */
1651
1652 return ERROR_SUCCESS;
1653}
1654
1655
1656static BOOL
1658{
1659 switch (dwCurrentState)
1660 {
1661 case SERVICE_STOPPED:
1664 case SERVICE_RUNNING:
1667 case SERVICE_PAUSED:
1668 return TRUE;
1669
1670 default:
1671 return FALSE;
1672 }
1673}
1674
1675
1676/* Function 7 */
1677DWORD
1678WINAPI
1681 LPSERVICE_STATUS lpServiceStatus)
1682{
1683 PSERVICE lpService;
1684 DWORD dwPreviousState;
1685 DWORD dwPreviousType;
1686 LPCWSTR lpLogStrings[2];
1687 WCHAR szLogBuffer[80];
1688 UINT uID;
1689
1690 DPRINT("RSetServiceStatus() called\n");
1691 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1692 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1693 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1694 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1695 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1696 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1697 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1698 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1699
1700 if (hServiceStatus == 0)
1701 {
1702 DPRINT("hServiceStatus == NULL\n");
1703 return ERROR_INVALID_HANDLE;
1704 }
1705
1706 lpService = (PSERVICE)hServiceStatus;
1707
1708 /* Check current state */
1709 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1710 {
1711 DPRINT("Invalid service state\n");
1712 return ERROR_INVALID_DATA;
1713 }
1714
1715 /* Check service type */
1716 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1717 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1718 {
1719 DPRINT("Invalid service type\n");
1720 return ERROR_INVALID_DATA;
1721 }
1722
1723 /* Check accepted controls */
1724 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1725 {
1726 DPRINT("Invalid controls accepted\n");
1727 return ERROR_INVALID_DATA;
1728 }
1729
1730 /* Set the wait hint and check point only if the service is in a pending state,
1731 otherwise they should be 0 */
1732 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1733 lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1734 lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1735 {
1736 lpServiceStatus->dwWaitHint = 0;
1737 lpServiceStatus->dwCheckPoint = 0;
1738 }
1739
1740 /* Lock the service database exclusively */
1742
1743 /* Save the current service state */
1744 dwPreviousState = lpService->Status.dwCurrentState;
1745
1746 /* Save the current service type */
1747 dwPreviousType = lpService->Status.dwServiceType;
1748
1749 /* Update the service status */
1750 RtlCopyMemory(&lpService->Status,
1751 lpServiceStatus,
1752 sizeof(SERVICE_STATUS));
1753
1754 /* Restore the previous service type */
1755 lpService->Status.dwServiceType = dwPreviousType;
1756
1757 /* Dereference a stopped service */
1758 if ((lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1759 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED))
1760 {
1761 /* Decrement the image run counter */
1762 lpService->lpImage->dwImageRunCount--;
1763
1764 /* If we just stopped the last running service... */
1765 if (lpService->lpImage->dwImageRunCount == 0)
1766 {
1767 /* Stop the dispatcher thread */
1769 L"",
1770 (SERVICE_STATUS_HANDLE)lpService,
1772
1773 /* Remove the service image */
1774 ScmRemoveServiceImage(lpService->lpImage);
1775 lpService->lpImage = NULL;
1776 }
1777 }
1778
1779 /* Unlock the service database */
1781
1782 if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1783 (dwPreviousState != SERVICE_STOPPED) &&
1784 (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
1785 {
1786 /* Log a failed service stop */
1787 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
1788 L"%lu", lpServiceStatus->dwWin32ExitCode);
1789 lpLogStrings[0] = lpService->lpDisplayName;
1790 lpLogStrings[1] = szLogBuffer;
1791
1794 2,
1795 lpLogStrings);
1796 }
1797 else if (lpServiceStatus->dwCurrentState != dwPreviousState &&
1798 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1799 lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
1800 lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
1801 {
1802 /* Log a successful service status change */
1803 switch(lpServiceStatus->dwCurrentState)
1804 {
1805 case SERVICE_STOPPED:
1806 uID = IDS_SERVICE_STOPPED;
1807 break;
1808
1809 case SERVICE_RUNNING:
1810 uID = IDS_SERVICE_RUNNING;
1811 break;
1812
1813 case SERVICE_PAUSED:
1814 uID = IDS_SERVICE_PAUSED;
1815 break;
1816 }
1817
1818 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1819 lpLogStrings[0] = lpService->lpDisplayName;
1820 lpLogStrings[1] = szLogBuffer;
1821
1824 2,
1825 lpLogStrings);
1826 }
1827
1828 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1829 DPRINT("RSetServiceStatus() done\n");
1830
1831 return ERROR_SUCCESS;
1832}
1833
1834
1835/* Function 8 */
1836DWORD
1837WINAPI
1840{
1841 DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1843}
1844
1845
1846/* Function 9 */
1847DWORD
1848WINAPI
1850 SVCCTL_HANDLEW lpMachineName,
1851 DWORD BootAcceptable)
1852{
1853 DPRINT("RNotifyBootConfigStatus(%p %lu)\n",
1854 lpMachineName, BootAcceptable);
1855
1856 if (BootAcceptable)
1857 return ScmAcceptBoot();
1858
1859 return ScmRunLastKnownGood();
1860}
1861
1862
1863/* Function 10 */
1864DWORD
1865WINAPI
1869 int bSetBitsOn,
1870 int bUpdateImmediately,
1871 wchar_t *lpString)
1872{
1873 PSERVICE pService;
1874
1875 DPRINT("RI_ScSetServiceBitsW(%p %lx %d %d %S)\n",
1876 hServiceStatus, dwServiceBits, bSetBitsOn,
1877 bUpdateImmediately, lpString);
1878
1879 if (ScmShutdown)
1881
1882 if (lpString != NULL)
1884
1885 if (hServiceStatus == 0)
1886 {
1887 DPRINT("hServiceStatus == NULL\n");
1888 return ERROR_INVALID_HANDLE;
1889 }
1890
1891 // FIXME: Validate the status handle
1892 pService = (PSERVICE)hServiceStatus;
1893
1894 if (bSetBitsOn)
1895 {
1896 DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1897 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1898 pService->dwServiceBits |= dwServiceBits;
1900 DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1901 DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1902 }
1903 else
1904 {
1905 DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1906 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1907 pService->dwServiceBits &= ~dwServiceBits;
1908 g_dwServiceBits &= ~dwServiceBits;
1909 DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1910 DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1911 }
1912
1913 return ERROR_SUCCESS;
1914}
1915
1916
1917/* Function 11 */
1918DWORD
1919WINAPI
1921 SC_RPC_HANDLE hService,
1922 DWORD dwServiceType,
1923 DWORD dwStartType,
1924 DWORD dwErrorControl,
1925 LPWSTR lpBinaryPathName,
1926 LPWSTR lpLoadOrderGroup,
1927 LPDWORD lpdwTagId,
1928 LPBYTE lpDependencies,
1929 DWORD dwDependSize,
1930 LPWSTR lpServiceStartName,
1931 LPBYTE lpPassword,
1932 DWORD dwPwSize,
1934{
1935 DWORD dwError = ERROR_SUCCESS;
1936 PSERVICE_HANDLE hSvc;
1937 PSERVICE lpService = NULL;
1938 HKEY hServiceKey = NULL;
1939 LPWSTR lpDisplayNameW = NULL;
1940 LPWSTR lpImagePathW = NULL;
1941 LPWSTR lpClearTextPassword = NULL;
1942
1943 DPRINT("RChangeServiceConfigW() called\n");
1944 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1945 DPRINT("dwStartType = %lu\n", dwStartType);
1946 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1947 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1948 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1949 DPRINT("lpServiceStartName = %S\n", lpServiceStartName);
1950 DPRINT("lpPassword = %p\n", lpPassword);
1951 DPRINT("dwPwSite = %lu\n", dwPwSize);
1952 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1953
1954 if (ScmShutdown)
1956
1957 hSvc = ScmGetServiceFromHandle(hService);
1958 if (hSvc == NULL)
1959 {
1960 DPRINT1("Invalid service handle\n");
1961 return ERROR_INVALID_HANDLE;
1962 }
1963
1966 {
1967 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1968 return ERROR_ACCESS_DENIED;
1969 }
1970
1971 /* Check for invalid service type value */
1972 if ((dwServiceType != SERVICE_NO_CHANGE) &&
1973 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
1974 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
1977 {
1979 }
1980
1981 /* Check for invalid start type value */
1982 if ((dwStartType != SERVICE_NO_CHANGE) &&
1983 (dwStartType != SERVICE_BOOT_START) &&
1984 (dwStartType != SERVICE_SYSTEM_START) &&
1985 (dwStartType != SERVICE_AUTO_START) &&
1986 (dwStartType != SERVICE_DEMAND_START) &&
1987 (dwStartType != SERVICE_DISABLED))
1988 {
1990 }
1991
1992 /* Only drivers can be boot start or system start services */
1993 if ((dwStartType == SERVICE_BOOT_START) ||
1994 (dwStartType == SERVICE_SYSTEM_START))
1995 {
1996 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
1997 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
1999 }
2000
2001 /* Check for invalid error control value */
2002 if ((dwErrorControl != SERVICE_NO_CHANGE) &&
2003 (dwErrorControl != SERVICE_ERROR_IGNORE) &&
2004 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2005 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2006 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2007 {
2009 }
2010
2011 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2012 {
2014 }
2015
2016 lpService = hSvc->ServiceEntry;
2017 if (lpService == NULL)
2018 {
2019 DPRINT("lpService == NULL\n");
2020 return ERROR_INVALID_HANDLE;
2021 }
2022
2023 /* Lock the service database exclusively */
2025
2026 if (lpService->bDeleted)
2027 {
2028 DPRINT("Service has already been marked for delete\n");
2030 goto done;
2031 }
2032
2033 /* Open the service key */
2034 dwError = ScmOpenServiceKey(lpService->szServiceName,
2036 &hServiceKey);
2037 if (dwError != ERROR_SUCCESS)
2038 goto done;
2039
2040 /* Write service data to the registry */
2041
2042 /* Set the display name */
2043 if (lpDisplayName != NULL && *lpDisplayName != 0)
2044 {
2045 RegSetValueExW(hServiceKey,
2046 L"DisplayName",
2047 0,
2048 REG_SZ,
2050 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2051
2052 /* Update the display name */
2053 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2055 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2056 if (lpDisplayNameW == NULL)
2057 {
2058 dwError = ERROR_NOT_ENOUGH_MEMORY;
2059 goto done;
2060 }
2061
2062 wcscpy(lpDisplayNameW, lpDisplayName);
2063 if (lpService->lpDisplayName != lpService->lpServiceName)
2064 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2065
2066 lpService->lpDisplayName = lpDisplayNameW;
2067 }
2068
2069 if (dwServiceType != SERVICE_NO_CHANGE)
2070 {
2071 /* Set the service type */
2072 dwError = RegSetValueExW(hServiceKey,
2073 L"Type",
2074 0,
2075 REG_DWORD,
2076 (LPBYTE)&dwServiceType,
2077 sizeof(DWORD));
2078 if (dwError != ERROR_SUCCESS)
2079 goto done;
2080
2081 lpService->Status.dwServiceType = dwServiceType;
2082 }
2083
2084 if (dwStartType != SERVICE_NO_CHANGE)
2085 {
2086 /* Set the start value */
2087 dwError = RegSetValueExW(hServiceKey,
2088 L"Start",
2089 0,
2090 REG_DWORD,
2091 (LPBYTE)&dwStartType,
2092 sizeof(DWORD));
2093 if (dwError != ERROR_SUCCESS)
2094 goto done;
2095
2096 lpService->dwStartType = dwStartType;
2097 }
2098
2099 if (dwErrorControl != SERVICE_NO_CHANGE)
2100 {
2101 /* Set the error control value */
2102 dwError = RegSetValueExW(hServiceKey,
2103 L"ErrorControl",
2104 0,
2105 REG_DWORD,
2106 (LPBYTE)&dwErrorControl,
2107 sizeof(DWORD));
2108 if (dwError != ERROR_SUCCESS)
2109 goto done;
2110
2111 lpService->dwErrorControl = dwErrorControl;
2112 }
2113
2114 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2115 {
2116 /* Set the image path */
2117 lpImagePathW = lpBinaryPathName;
2118
2119 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
2120 {
2121 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
2122 lpBinaryPathName,
2123 &lpImagePathW);
2124
2125 if (dwError != ERROR_SUCCESS)
2126 goto done;
2127 }
2128
2129 dwError = RegSetValueExW(hServiceKey,
2130 L"ImagePath",
2131 0,
2133 (LPBYTE)lpImagePathW,
2134 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
2135
2136 if (lpImagePathW != lpBinaryPathName)
2137 HeapFree(GetProcessHeap(), 0, lpImagePathW);
2138
2139 if (dwError != ERROR_SUCCESS)
2140 goto done;
2141 }
2142
2143 /* Set the group name */
2144 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2145 {
2146 dwError = RegSetValueExW(hServiceKey,
2147 L"Group",
2148 0,
2149 REG_SZ,
2150 (LPBYTE)lpLoadOrderGroup,
2151 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2152 if (dwError != ERROR_SUCCESS)
2153 goto done;
2154
2155 dwError = ScmSetServiceGroup(lpService,
2156 lpLoadOrderGroup);
2157 if (dwError != ERROR_SUCCESS)
2158 goto done;
2159 }
2160
2161 /* Set the tag */
2162 if (lpdwTagId != NULL)
2163 {
2164 dwError = ScmAssignNewTag(lpService);
2165 if (dwError != ERROR_SUCCESS)
2166 goto done;
2167
2168 dwError = RegSetValueExW(hServiceKey,
2169 L"Tag",
2170 0,
2171 REG_DWORD,
2172 (LPBYTE)&lpService->dwTag,
2173 sizeof(DWORD));
2174 if (dwError != ERROR_SUCCESS)
2175 goto done;
2176
2177 *lpdwTagId = lpService->dwTag;
2178 }
2179
2180 /* Write dependencies */
2181 if (lpDependencies != NULL && *lpDependencies != 0)
2182 {
2183 dwError = ScmWriteDependencies(hServiceKey,
2184 (LPWSTR)lpDependencies,
2185 dwDependSize);
2186 if (dwError != ERROR_SUCCESS)
2187 goto done;
2188 }
2189
2190 /* Start name and password are only used by Win32 services */
2191 if (lpService->Status.dwServiceType & SERVICE_WIN32)
2192 {
2193 /* Write service start name */
2194 if (lpServiceStartName != NULL && *lpServiceStartName != 0)
2195 {
2196 dwError = RegSetValueExW(hServiceKey,
2197 L"ObjectName",
2198 0,
2199 REG_SZ,
2200 (LPBYTE)lpServiceStartName,
2201 (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)));
2202 if (dwError != ERROR_SUCCESS)
2203 goto done;
2204 }
2205
2206 if (lpPassword != NULL)
2207 {
2208 if (*(LPWSTR)lpPassword != 0)
2209 {
2210 /* Decrypt the password */
2211 dwError = ScmDecryptPassword(hService,
2212 lpPassword,
2213 dwPwSize,
2214 &lpClearTextPassword);
2215 if (dwError != ERROR_SUCCESS)
2216 {
2217 DPRINT1("ScmDecryptPassword failed (Error %lu)\n", dwError);
2218 goto done;
2219 }
2220 DPRINT1("Clear text password: %S\n", lpClearTextPassword);
2221
2222 /* Write the password */
2223 dwError = ScmSetServicePassword(lpService->szServiceName,
2224 lpClearTextPassword);
2225 if (dwError != ERROR_SUCCESS)
2226 {
2227 DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2228 goto done;
2229 }
2230 }
2231 else
2232 {
2233 /* Delete the password */
2234 dwError = ScmSetServicePassword(lpService->szServiceName,
2235 NULL);
2236 if (dwError == ERROR_FILE_NOT_FOUND)
2237 dwError = ERROR_SUCCESS;
2238
2239 if (dwError != ERROR_SUCCESS)
2240 {
2241 DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2242 goto done;
2243 }
2244 }
2245 }
2246 }
2247
2248done:
2249 if (lpClearTextPassword != NULL)
2250 {
2251 /* Wipe and release the password buffer */
2252 SecureZeroMemory(lpClearTextPassword,
2253 (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2254 HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2255 }
2256
2257 if (hServiceKey != NULL)
2258 RegCloseKey(hServiceKey);
2259
2260 /* Unlock the service database */
2262
2263 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2264
2265 return dwError;
2266}
2267
2268
2269/* Function 12 */
2270DWORD
2271WINAPI
2274 LPCWSTR lpServiceName,
2276 DWORD dwDesiredAccess,
2277 DWORD dwServiceType,
2278 DWORD dwStartType,
2279 DWORD dwErrorControl,
2280 LPCWSTR lpBinaryPathName,
2281 LPCWSTR lpLoadOrderGroup,
2282 LPDWORD lpdwTagId,
2283 LPBYTE lpDependencies,
2284 DWORD dwDependSize,
2285 LPCWSTR lpServiceStartName,
2286 LPBYTE lpPassword,
2287 DWORD dwPwSize,
2288 LPSC_RPC_HANDLE lpServiceHandle)
2289{
2290 PMANAGER_HANDLE hManager;
2291 DWORD dwError = ERROR_SUCCESS;
2292 PSERVICE lpService = NULL;
2293 SC_HANDLE hServiceHandle = NULL;
2294 LPWSTR lpImagePath = NULL;
2295 LPWSTR lpClearTextPassword = NULL;
2296 HKEY hServiceKey = NULL;
2297 LPWSTR lpObjectName;
2298
2299 DPRINT("RCreateServiceW() called\n");
2300 DPRINT("lpServiceName = %S\n", lpServiceName);
2301 DPRINT("lpDisplayName = %S\n", lpDisplayName);
2302 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2303 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2304 DPRINT("dwStartType = %lu\n", dwStartType);
2305 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2306 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2307 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2308 DPRINT("lpdwTagId = %p\n", lpdwTagId);
2309
2310 if (ScmShutdown)
2312
2314 if (hManager == NULL)
2315 {
2316 DPRINT1("Invalid service manager handle\n");
2317 return ERROR_INVALID_HANDLE;
2318 }
2319
2320 /* Check access rights */
2323 {
2324 DPRINT("Insufficient access rights! 0x%lx\n",
2325 hManager->Handle.DesiredAccess);
2326 return ERROR_ACCESS_DENIED;
2327 }
2328
2329 if (*lpServiceName == 0)
2330 return ERROR_INVALID_NAME;
2331
2332 if (*lpBinaryPathName == 0)
2334
2335 /* Check for invalid service type value */
2336 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2337 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2340 {
2342 }
2343
2344 /* Check for invalid start type value */
2345 if ((dwStartType != SERVICE_BOOT_START) &&
2346 (dwStartType != SERVICE_SYSTEM_START) &&
2347 (dwStartType != SERVICE_AUTO_START) &&
2348 (dwStartType != SERVICE_DEMAND_START) &&
2349 (dwStartType != SERVICE_DISABLED))
2350 {
2352 }
2353
2354 /* Only drivers can be boot start or system start services */
2355 if ((dwStartType == SERVICE_BOOT_START) ||
2356 (dwStartType == SERVICE_SYSTEM_START))
2357 {
2358 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2359 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2360 {
2362 }
2363 }
2364
2365 /* Check for invalid error control value */
2366 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2367 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2368 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2369 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2370 {
2372 }
2373
2374 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2375 (lpServiceStartName))
2376 {
2377 /* We allow LocalSystem to run interactive. */
2378 if (wcsicmp(lpServiceStartName, L"LocalSystem"))
2379 {
2381 }
2382 }
2383
2384 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2385 {
2387 }
2388
2389 /* Lock the service database exclusively */
2391
2392 lpService = ScmGetServiceEntryByName(lpServiceName);
2393 if (lpService)
2394 {
2395 /* Unlock the service database */
2397
2398 /* Check if it is marked for deletion */
2399 if (lpService->bDeleted)
2401
2402 /* Return service-exists error */
2403 return ERROR_SERVICE_EXISTS;
2404 }
2405
2406 if (lpDisplayName != NULL &&
2408 {
2409 /* Unlock the service database */
2411
2413 }
2414
2415 if (dwServiceType & SERVICE_DRIVER)
2416 {
2417 dwError = ScmCanonDriverImagePath(dwStartType,
2418 lpBinaryPathName,
2419 &lpImagePath);
2420 if (dwError != ERROR_SUCCESS)
2421 goto done;
2422 }
2423 else
2424 {
2425 if (dwStartType == SERVICE_BOOT_START ||
2426 dwStartType == SERVICE_SYSTEM_START)
2427 {
2428 /* Unlock the service database */
2430
2432 }
2433 }
2434
2435 /* Allocate a new service entry */
2436 dwError = ScmCreateNewServiceRecord(lpServiceName,
2437 &lpService,
2438 dwServiceType,
2439 dwStartType);
2440 if (dwError != ERROR_SUCCESS)
2441 goto done;
2442
2443 /* Fill the new service entry */
2444 lpService->dwErrorControl = dwErrorControl;
2445
2446 /* Fill the display name */
2447 if (lpDisplayName != NULL &&
2448 *lpDisplayName != 0 &&
2449 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2450 {
2451 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2453 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2454 if (lpService->lpDisplayName == NULL)
2455 {
2456 dwError = ERROR_NOT_ENOUGH_MEMORY;
2457 goto done;
2458 }
2459 wcscpy(lpService->lpDisplayName, lpDisplayName);
2460 }
2461
2462 /* Assign the service to a group */
2463 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2464 {
2465 dwError = ScmSetServiceGroup(lpService,
2466 lpLoadOrderGroup);
2467 if (dwError != ERROR_SUCCESS)
2468 goto done;
2469 }
2470
2471 /* Assign a new tag */
2472 if (lpdwTagId != NULL)
2473 {
2474 dwError = ScmAssignNewTag(lpService);
2475 if (dwError != ERROR_SUCCESS)
2476 goto done;
2477 }
2478
2479 /* Assign the default security descriptor */
2480 if (dwServiceType & SERVICE_WIN32)
2481 {
2482 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
2483 if (dwError != ERROR_SUCCESS)
2484 goto done;
2485 }
2486
2487 /* Write service data to the registry */
2488 /* Create the service key */
2489 dwError = ScmCreateServiceKey(lpServiceName,
2490 KEY_WRITE,
2491 &hServiceKey);
2492 if (dwError != ERROR_SUCCESS)
2493 goto done;
2494
2495 /* Set the display name */
2496 if (lpDisplayName != NULL && *lpDisplayName != 0)
2497 {
2498 RegSetValueExW(hServiceKey,
2499 L"DisplayName",
2500 0,
2501 REG_SZ,
2503 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2504 }
2505
2506 /* Set the service type */
2507 dwError = RegSetValueExW(hServiceKey,
2508 L"Type",
2509 0,
2510 REG_DWORD,
2511 (LPBYTE)&dwServiceType,
2512 sizeof(DWORD));
2513 if (dwError != ERROR_SUCCESS)
2514 goto done;
2515
2516 /* Set the start value */
2517 dwError = RegSetValueExW(hServiceKey,
2518 L"Start",
2519 0,
2520 REG_DWORD,
2521 (LPBYTE)&dwStartType,
2522 sizeof(DWORD));
2523 if (dwError != ERROR_SUCCESS)
2524 goto done;
2525
2526 /* Set the error control value */
2527 dwError = RegSetValueExW(hServiceKey,
2528 L"ErrorControl",
2529 0,
2530 REG_DWORD,
2531 (LPBYTE)&dwErrorControl,
2532 sizeof(DWORD));
2533 if (dwError != ERROR_SUCCESS)
2534 goto done;
2535
2536 /* Set the image path */
2537 if (dwServiceType & SERVICE_WIN32)
2538 {
2539 dwError = RegSetValueExW(hServiceKey,
2540 L"ImagePath",
2541 0,
2543 (LPBYTE)lpBinaryPathName,
2544 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2545 if (dwError != ERROR_SUCCESS)
2546 goto done;
2547 }
2548 else if (dwServiceType & SERVICE_DRIVER)
2549 {
2550 dwError = RegSetValueExW(hServiceKey,
2551 L"ImagePath",
2552 0,
2554 (LPBYTE)lpImagePath,
2555 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2556 if (dwError != ERROR_SUCCESS)
2557 goto done;
2558 }
2559
2560 /* Set the group name */
2561 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2562 {
2563 dwError = RegSetValueExW(hServiceKey,
2564 L"Group",
2565 0,
2566 REG_SZ,
2567 (LPBYTE)lpLoadOrderGroup,
2568 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2569 if (dwError != ERROR_SUCCESS)
2570 goto done;
2571 }
2572
2573 /* Set the service tag */
2574 if (lpdwTagId != NULL)
2575 {
2576 dwError = RegSetValueExW(hServiceKey,
2577 L"Tag",
2578 0,
2579 REG_DWORD,
2580 (LPBYTE)&lpService->dwTag,
2581 sizeof(DWORD));
2582 if (dwError != ERROR_SUCCESS)
2583 goto done;
2584 }
2585
2586 /* Write dependencies */
2587 if (lpDependencies != NULL && *lpDependencies != 0)
2588 {
2589 dwError = ScmWriteDependencies(hServiceKey,
2590 (LPCWSTR)lpDependencies,
2591 dwDependSize);
2592 if (dwError != ERROR_SUCCESS)
2593 goto done;
2594 }
2595
2596 /* Start name and password are only used by Win32 services */
2597 if (dwServiceType & SERVICE_WIN32)
2598 {
2599 /* Write service start name */
2600 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2601 dwError = RegSetValueExW(hServiceKey,
2602 L"ObjectName",
2603 0,
2604 REG_SZ,
2605 (LPBYTE)lpObjectName,
2606 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2607 if (dwError != ERROR_SUCCESS)
2608 goto done;
2609
2610 if (lpPassword != NULL && *(LPWSTR)lpPassword != 0)
2611 {
2612 /* Decrypt the password */
2614 lpPassword,
2615 dwPwSize,
2616 &lpClearTextPassword);
2617 if (dwError != ERROR_SUCCESS)
2618 goto done;
2619
2620 /* Write the password */
2621 dwError = ScmSetServicePassword(lpServiceName,
2622 lpClearTextPassword);
2623 if (dwError != ERROR_SUCCESS)
2624 goto done;
2625 }
2626
2627 /* Write the security descriptor */
2628 dwError = ScmWriteSecurityDescriptor(hServiceKey,
2629 lpService->pSecurityDescriptor);
2630 if (dwError != ERROR_SUCCESS)
2631 goto done;
2632 }
2633
2634 dwError = ScmCreateServiceHandle(lpService,
2635 &hServiceHandle);
2636 if (dwError != ERROR_SUCCESS)
2637 goto done;
2638
2639 dwError = ScmCheckAccess(hServiceHandle,
2640 dwDesiredAccess);
2641 if (dwError != ERROR_SUCCESS)
2642 goto done;
2643
2644 lpService->dwRefCount = 1;
2645
2646 /* Get the service tag (if Win32) */
2647 ScmGenerateServiceTag(lpService);
2648
2649 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2650
2651done:
2652 /* Unlock the service database */
2654
2655 if (hServiceKey != NULL)
2656 RegCloseKey(hServiceKey);
2657
2658 if (lpClearTextPassword != NULL)
2659 {
2660 /* Wipe and release the password buffer */
2661 SecureZeroMemory(lpClearTextPassword,
2662 (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2663 HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2664 }
2665
2666 if (dwError == ERROR_SUCCESS)
2667 {
2668 DPRINT("hService %p\n", hServiceHandle);
2669 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2670
2671 if (lpdwTagId != NULL)
2672 *lpdwTagId = lpService->dwTag;
2673 }
2674 else
2675 {
2676 if (lpService != NULL &&
2677 lpService->lpServiceName != NULL)
2678 {
2679 /* Release the display name buffer */
2680 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2681 }
2682
2683 if (hServiceHandle)
2684 {
2685 /* Remove the service handle */
2686 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2687 }
2688
2689 if (lpService != NULL)
2690 {
2691 /* FIXME: remove the service entry */
2692 }
2693 }
2694
2695 if (lpImagePath != NULL)
2696 HeapFree(GetProcessHeap(), 0, lpImagePath);
2697
2698 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2699
2700 return dwError;
2701}
2702
2703
2704/* Function 13 */
2705DWORD
2706WINAPI
2708 SC_RPC_HANDLE hService,
2709 DWORD dwServiceState,
2710 LPBYTE lpServices,
2713 LPBOUNDED_DWORD_256K lpServicesReturned)
2714{
2715 DWORD dwError = ERROR_SUCCESS;
2716 DWORD dwServicesReturned = 0;
2717 DWORD dwServiceCount;
2719 PSERVICE_HANDLE hSvc;
2720 PSERVICE lpService = NULL;
2721 PSERVICE *lpServicesArray = NULL;
2722 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2723 LPWSTR lpStr;
2724
2725 *pcbBytesNeeded = 0;
2726 *lpServicesReturned = 0;
2727
2728 DPRINT("REnumDependentServicesW() called\n");
2729
2730 hSvc = ScmGetServiceFromHandle(hService);
2731 if (hSvc == NULL)
2732 {
2733 DPRINT1("Invalid service handle\n");
2734 return ERROR_INVALID_HANDLE;
2735 }
2736
2737 lpService = hSvc->ServiceEntry;
2738
2739 /* Check access rights */
2742 {
2743 DPRINT("Insufficient access rights! 0x%lx\n",
2744 hSvc->Handle.DesiredAccess);
2745 return ERROR_ACCESS_DENIED;
2746 }
2747
2748 /* Open the Services Reg key */
2750 L"System\\CurrentControlSet\\Services",
2751 0,
2752 KEY_READ,
2753 &hServicesKey);
2754 if (dwError != ERROR_SUCCESS)
2755 return dwError;
2756
2757 /* First determine the bytes needed and get the number of dependent services */
2759 lpService,
2760 dwServiceState,
2761 NULL,
2763 &dwServicesReturned);
2764 if (dwError != ERROR_SUCCESS)
2765 goto Done;
2766
2767 /* If buffer size is less than the bytes needed or pointer is null */
2768 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2769 {
2770 dwError = ERROR_MORE_DATA;
2771 goto Done;
2772 }
2773
2774 /* Allocate memory for array of service pointers */
2775 lpServicesArray = HeapAlloc(GetProcessHeap(),
2777 (dwServicesReturned + 1) * sizeof(PSERVICE));
2778 if (!lpServicesArray)
2779 {
2780 DPRINT1("Could not allocate buffer\n");
2781 dwError = ERROR_NOT_ENOUGH_MEMORY;
2782 goto Done;
2783 }
2784
2785 dwServicesReturned = 0;
2786 *pcbBytesNeeded = 0;
2787
2789 lpService,
2790 dwServiceState,
2791 lpServicesArray,
2793 &dwServicesReturned);
2794 if (dwError != ERROR_SUCCESS)
2795 {
2796 goto Done;
2797 }
2798
2799 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2800 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2801
2802 /* Copy EnumDepenedentService to Buffer */
2803 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2804 {
2805 lpService = lpServicesArray[dwServiceCount];
2806
2807 /* Copy status info */
2808 memcpy(&lpServicesPtr->ServiceStatus,
2809 &lpService->Status,
2810 sizeof(SERVICE_STATUS));
2811
2812 /* Copy display name */
2813 wcscpy(lpStr, lpService->lpDisplayName);
2814 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2815 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2816
2817 /* Copy service name */
2818 wcscpy(lpStr, lpService->lpServiceName);
2819 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2820 lpStr += (wcslen(lpService->lpServiceName) + 1);
2821
2822 lpServicesPtr++;
2823 }
2824
2825 *lpServicesReturned = dwServicesReturned;
2826
2827Done:
2828 if (lpServicesArray != NULL)
2829 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2830
2832
2833 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2834
2835 return dwError;
2836}
2837
2838
2839/* Function 14 */
2840DWORD
2841WINAPI
2844 DWORD dwServiceType,
2845 DWORD dwServiceState,
2847 DWORD dwBufSize,
2849 LPBOUNDED_DWORD_256K lpServicesReturned,
2850 LPBOUNDED_DWORD_256K lpResumeHandle)
2851{
2852 /* Enumerate all the services, not regarding of their group */
2854 dwServiceType,
2855 dwServiceState,
2856 lpBuffer,
2857 dwBufSize,
2859 lpServicesReturned,
2860 lpResumeHandle,
2861 NULL);
2862}
2863
2864
2865/* Function 15 */
2866DWORD
2867WINAPI
2869 LPWSTR lpMachineName,
2870 LPWSTR lpDatabaseName,
2871 DWORD dwDesiredAccess,
2872 LPSC_RPC_HANDLE lpScHandle)
2873{
2874 DWORD dwError;
2875 SC_HANDLE hHandle;
2876
2877 DPRINT("ROpenSCManagerW() called\n");
2878 DPRINT("lpMachineName = %p\n", lpMachineName);
2879 DPRINT("lpMachineName: %S\n", lpMachineName);
2880 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2881 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2882 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2883
2884 if (ScmShutdown)
2886
2887 if (!lpScHandle)
2889
2890 dwError = ScmCreateManagerHandle(lpDatabaseName,
2891 &hHandle);
2892 if (dwError != ERROR_SUCCESS)
2893 {
2894 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2895 return dwError;
2896 }
2897
2898 /* Check the desired access */
2899 dwError = ScmCheckAccess(hHandle,
2900 dwDesiredAccess | SC_MANAGER_CONNECT);
2901 if (dwError != ERROR_SUCCESS)
2902 {
2903 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2904 HeapFree(GetProcessHeap(), 0, hHandle);
2905 return dwError;
2906 }
2907
2908 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2909 DPRINT("*hScm = %p\n", *lpScHandle);
2910
2911 DPRINT("ROpenSCManagerW() done\n");
2912
2913 return ERROR_SUCCESS;
2914}
2915
2916
2917/* Function 16 */
2918DWORD
2919WINAPI
2922 LPWSTR lpServiceName,
2923 DWORD dwDesiredAccess,
2924 LPSC_RPC_HANDLE lpServiceHandle)
2925{
2926 PSERVICE lpService;
2927 PMANAGER_HANDLE hManager;
2928 SC_HANDLE hHandle;
2929 DWORD dwError = ERROR_SUCCESS;
2930
2931 DPRINT("ROpenServiceW() called\n");
2932 DPRINT("hSCManager = %p\n", hSCManager);
2933 DPRINT("lpServiceName = %p\n", lpServiceName);
2934 DPRINT("lpServiceName: %S\n", lpServiceName);
2935 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2936
2937 if (ScmShutdown)
2939
2941 if (hManager == NULL)
2942 {
2943 DPRINT1("Invalid service manager handle\n");
2944 return ERROR_INVALID_HANDLE;
2945 }
2946
2947 if (!lpServiceHandle)
2949
2950 if (!lpServiceName)
2951 return ERROR_INVALID_ADDRESS;
2952
2953 /* Lock the service database exclusive */
2955
2956 /* Get service database entry */
2957 lpService = ScmGetServiceEntryByName(lpServiceName);
2958 if (lpService == NULL)
2959 {
2960 DPRINT("Could not find service\n");
2962 goto Done;
2963 }
2964
2965 /* Create a service handle */
2966 dwError = ScmCreateServiceHandle(lpService,
2967 &hHandle);
2968 if (dwError != ERROR_SUCCESS)
2969 {
2970 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2971 goto Done;
2972 }
2973
2974 /* Check the desired access */
2975 dwError = ScmCheckAccess(hHandle,
2976 dwDesiredAccess);
2977 if (dwError != ERROR_SUCCESS)
2978 {
2979 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2980 HeapFree(GetProcessHeap(), 0, hHandle);
2981 goto Done;
2982 }
2983
2984 lpService->dwRefCount++;
2985 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2986
2987 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2988 DPRINT("*hService = %p\n", *lpServiceHandle);
2989
2990Done:
2991 /* Unlock the service database */
2993
2994 DPRINT("ROpenServiceW() done\n");
2995
2996 return dwError;
2997}
2998
2999
3000/* Function 17 */
3001DWORD
3002WINAPI
3004 SC_RPC_HANDLE hService,
3005 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
3008{
3009 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
3010 DWORD dwError = ERROR_SUCCESS;
3011 PSERVICE_HANDLE hSvc;
3012 PSERVICE lpService = NULL;
3013 HKEY hServiceKey = NULL;
3014 LPWSTR lpImagePath = NULL;
3015 LPWSTR lpServiceStartName = NULL;
3016 LPWSTR lpDependencies = NULL;
3017 DWORD dwDependenciesLength = 0;
3018 DWORD dwRequiredSize;
3019 LPWSTR lpStr;
3020
3021 DPRINT("RQueryServiceConfigW() called\n");
3022
3023 if (ScmShutdown)
3025
3026 hSvc = ScmGetServiceFromHandle(hService);
3027 if (hSvc == NULL)
3028 {
3029 DPRINT1("Invalid service handle\n");
3030 return ERROR_INVALID_HANDLE;
3031 }
3032
3035 {
3036 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3037 return ERROR_ACCESS_DENIED;
3038 }
3039
3040 lpService = hSvc->ServiceEntry;
3041 if (lpService == NULL)
3042 {
3043 DPRINT("lpService == NULL\n");
3044 return ERROR_INVALID_HANDLE;
3045 }
3046
3047 /* Lock the service database shared */
3049
3050 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3051 KEY_READ,
3052 &hServiceKey);
3053 if (dwError != ERROR_SUCCESS)
3054 goto Done;
3055
3056 /* Read the image path */
3057 dwError = ScmReadString(hServiceKey,
3058 L"ImagePath",
3059 &lpImagePath);
3060 if (dwError != ERROR_SUCCESS)
3061 goto Done;
3062
3063 /* Read the service start name */
3064 ScmReadString(hServiceKey,
3065 L"ObjectName",
3066 &lpServiceStartName);
3067
3068 /* Read the dependencies */
3069 ScmReadDependencies(hServiceKey,
3070 &lpDependencies,
3071 &dwDependenciesLength);
3072
3073 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3074
3075 if (lpImagePath != NULL)
3076 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
3077 else
3078 dwRequiredSize += 2 * sizeof(WCHAR);
3079
3080 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3081 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
3082 else
3083 dwRequiredSize += 2 * sizeof(WCHAR);
3084
3085 if (lpDependencies != NULL)
3086 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
3087 else
3088 dwRequiredSize += 2 * sizeof(WCHAR);
3089
3090 if (lpServiceStartName != NULL)
3091 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
3092 else
3093 dwRequiredSize += 2 * sizeof(WCHAR);
3094
3095 if (lpService->lpDisplayName != NULL)
3096 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
3097 else
3098 dwRequiredSize += 2 * sizeof(WCHAR);
3099
3100 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3101 {
3102 dwError = ERROR_INSUFFICIENT_BUFFER;
3103 }
3104 else
3105 {
3106 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
3107 lpServiceConfig->dwStartType = lpService->dwStartType;
3108 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
3109 lpServiceConfig->dwTagId = lpService->dwTag;
3110
3111 lpStr = (LPWSTR)(lpServiceConfig + 1);
3112
3113 /* Append the image path */
3114 if (lpImagePath != NULL)
3115 {
3116 wcscpy(lpStr, lpImagePath);
3117 }
3118 else
3119 {
3120 *lpStr = 0;
3121 }
3122
3123 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3124 lpStr += (wcslen(lpStr) + 1);
3125
3126 /* Append the group name */
3127 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3128 {
3129 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
3130 }
3131 else
3132 {
3133 *lpStr = 0;
3134 }
3135
3136 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3137 lpStr += (wcslen(lpStr) + 1);
3138
3139 /* Append Dependencies */
3140 if (lpDependencies != NULL)
3141 {
3142 memcpy(lpStr,
3143 lpDependencies,
3144 dwDependenciesLength * sizeof(WCHAR));
3145 }
3146 else
3147 {
3148 *lpStr = 0;
3149 }
3150
3151 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3152 if (lpDependencies != NULL)
3153 lpStr += dwDependenciesLength;
3154 else
3155 lpStr += (wcslen(lpStr) + 1);
3156
3157 /* Append the service start name */
3158 if (lpServiceStartName != NULL)
3159 {
3160 wcscpy(lpStr, lpServiceStartName);
3161 }
3162 else
3163 {
3164 *lpStr = 0;
3165 }
3166
3167 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3168 lpStr += (wcslen(lpStr) + 1);
3169
3170 /* Append the display name */
3171 if (lpService->lpDisplayName != NULL)
3172 {
3173 wcscpy(lpStr, lpService->lpDisplayName);
3174 }
3175 else
3176 {
3177 *lpStr = 0;
3178 }
3179
3180 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3181 }
3182
3183 if (pcbBytesNeeded != NULL)
3184 *pcbBytesNeeded = dwRequiredSize;
3185
3186Done:
3187 /* Unlock the service database */
3189
3190 if (lpImagePath != NULL)
3191 HeapFree(GetProcessHeap(), 0, lpImagePath);
3192
3193 if (lpServiceStartName != NULL)
3194 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3195
3196 if (lpDependencies != NULL)
3197 HeapFree(GetProcessHeap(), 0, lpDependencies);
3198
3199 if (hServiceKey != NULL)
3200 RegCloseKey(hServiceKey);
3201
3202 DPRINT("RQueryServiceConfigW() done\n");
3203
3204 return dwError;
3205}
3206
3207
3208/* Function 18 */
3209DWORD
3210WINAPI
3213 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3216{
3218 PMANAGER_HANDLE hMgr;
3219 DWORD dwRequiredSize;
3220
3221 if (!lpLockStatus || !pcbBytesNeeded)
3223
3225 if (hMgr == NULL)
3226 {
3227 DPRINT1("Invalid service manager handle\n");
3228 return ERROR_INVALID_HANDLE;
3229 }
3230
3233 {
3234 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
3235 return ERROR_ACCESS_DENIED;
3236 }
3237
3238 /* FIXME: we need to compute instead the real length of the owner name */
3239 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
3240 *pcbBytesNeeded = dwRequiredSize;
3241
3242 if (cbBufSize < dwRequiredSize)
3244
3245 ScmQueryServiceLockStatusW(lpLockStatus);
3246
3247 return ERROR_SUCCESS;
3248}
3249
3250
3251/* Function 19 */
3252DWORD
3253WINAPI
3255 SC_RPC_HANDLE hService,
3256 DWORD argc,
3258{
3259 DWORD dwError = ERROR_SUCCESS;
3260 PSERVICE_HANDLE hSvc;
3261 PSERVICE lpService = NULL;
3262
3263#ifndef NDEBUG
3264 DWORD i;
3265
3266 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3267 DPRINT(" argc: %lu\n", argc);
3268 if (argv != NULL)
3269 {
3270 for (i = 0; i < argc; i++)
3271 {
3272 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
3273 }
3274 }
3275#endif
3276
3277 if (ScmShutdown)
3279
3280 hSvc = ScmGetServiceFromHandle(hService);
3281 if (hSvc == NULL)
3282 {
3283 DPRINT1("Invalid service handle\n");
3284 return ERROR_INVALID_HANDLE;
3285 }
3286
3289 {
3290 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3291 return ERROR_ACCESS_DENIED;
3292 }
3293
3294 lpService = hSvc->ServiceEntry;
3295 if (lpService == NULL)
3296 {
3297 DPRINT("lpService == NULL\n");
3298 return ERROR_INVALID_HANDLE;
3299 }
3300
3301 if (lpService->dwStartType == SERVICE_DISABLED)
3303
3304 if (lpService->bDeleted)
3306
3307 /* Start the service */
3308 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3309
3310 return dwError;
3311}
3312
3313
3314/* Function 20 */
3315DWORD
3316WINAPI
3319 LPCWSTR lpServiceName,
3321 DWORD *lpcchBuffer)
3322{
3323 // PMANAGER_HANDLE hManager;
3324 PSERVICE lpService;
3325 LPCWSTR lpSvcDisplayName;
3327 DWORD dwError;
3328
3329 DPRINT("RGetServiceDisplayNameW() called\n");
3330 DPRINT("hSCManager = %p\n", hSCManager);
3331 DPRINT("lpServiceName: %S\n", lpServiceName);
3332 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3333 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3334
3335#if 0
3336 hManager = (PMANAGER_HANDLE)hSCManager;
3337 if (hManager->Handle.Tag != MANAGER_TAG)
3338 {
3339 DPRINT("Invalid manager handle\n");
3340 return ERROR_INVALID_HANDLE;
3341 }
3342#endif
3343
3344 /* Get service database entry */
3345 lpService = ScmGetServiceEntryByName(lpServiceName);
3346 if (lpService == NULL)
3347 {
3348 DPRINT("Could not find service\n");
3350 }
3351
3352 if (lpService->lpDisplayName)
3353 lpSvcDisplayName = lpService->lpDisplayName;
3354 else
3355 lpSvcDisplayName = lpService->lpServiceName;
3356
3357 dwLength = (DWORD)wcslen(lpSvcDisplayName);
3358
3359 if (*lpcchBuffer > dwLength)
3360 {
3361 if (lpDisplayName != NULL)
3362 wcscpy(lpDisplayName, lpSvcDisplayName);
3363
3364 dwError = ERROR_SUCCESS;
3365 }
3366 else
3367 {
3368 dwError = ERROR_INSUFFICIENT_BUFFER;
3369 }
3370
3371 *lpcchBuffer = dwLength;
3372
3373 return dwError;
3374}
3375
3376
3377/* Function 21 */
3378DWORD
3379WINAPI
3383 LPWSTR lpServiceName,
3384 DWORD *lpcchBuffer)
3385{
3386 // PMANAGER_HANDLE hManager;
3387 PSERVICE lpService;
3389 DWORD dwError;
3390
3391 DPRINT("RGetServiceKeyNameW() called\n");
3392 DPRINT("hSCManager = %p\n", hSCManager);
3393 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3394 DPRINT("lpServiceName: %p\n", lpServiceName);
3395 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3396
3397#if 0
3398 hManager = (PMANAGER_HANDLE)hSCManager;
3399 if (hManager->Handle.Tag != MANAGER_TAG)
3400 {
3401 DPRINT("Invalid manager handle\n");
3402 return ERROR_INVALID_HANDLE;
3403 }
3404#endif
3405
3406 /* Get service database entry */
3408 if (lpService == NULL)
3409 {
3410 DPRINT("Could not find service\n");
3412 }
3413
3414 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3415
3416 if (*lpcchBuffer > dwLength)
3417 {
3418 if (lpServiceName != NULL)
3419 wcscpy(lpServiceName, lpService->lpServiceName);
3420
3421 dwError = ERROR_SUCCESS;
3422 }
3423 else
3424 {
3425 dwError = ERROR_INSUFFICIENT_BUFFER;
3426 }
3427
3428 *lpcchBuffer = dwLength;
3429
3430 return dwError;
3431}
3432
3433
3434/* Function 22 */
3435DWORD
3436WINAPI
3440 int bSetBitsOn,
3441 int bUpdateImmediately,
3442 char *lpString)
3443{
3444 if (ScmShutdown)
3446
3447 if (lpString != NULL)
3449
3452 bSetBitsOn,
3453 bUpdateImmediately,
3454 NULL);
3455}
3456
3457
3458/* Function 23 */
3459DWORD
3460WINAPI
3462 SC_RPC_HANDLE hService,
3463 DWORD dwServiceType,
3464 DWORD dwStartType,
3465 DWORD dwErrorControl,
3466 LPSTR lpBinaryPathName,
3467 LPSTR lpLoadOrderGroup,
3468 LPDWORD lpdwTagId,
3469 LPBYTE lpDependencies,
3470 DWORD dwDependSize,
3471 LPSTR lpServiceStartName,
3472 LPBYTE lpPassword,
3473 DWORD dwPwSize,
3475{
3476 DWORD dwError = ERROR_SUCCESS;
3477 LPWSTR lpBinaryPathNameW = NULL;
3478 LPWSTR lpLoadOrderGroupW = NULL;
3479 LPWSTR lpDependenciesW = NULL;
3480 LPWSTR lpServiceStartNameW = NULL;
3481 LPWSTR lpDisplayNameW = NULL;
3482 DWORD dwDependenciesLength = 0;
3483 SIZE_T cchLength;
3484 int len;
3485 LPCSTR lpStr;
3486
3487 if (lpBinaryPathName)
3488 {
3489 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3490 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3491 if (!lpBinaryPathNameW)
3492 {
3494 goto cleanup;
3495 }
3496 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3497 }
3498
3499 if (lpLoadOrderGroup)
3500 {
3501 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3502 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3503 if (!lpLoadOrderGroupW)
3504 {
3506 goto cleanup;
3507 }
3508 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3509 }
3510
3511 if (lpDependencies)
3512 {
3513 lpStr = (LPCSTR)lpDependencies;
3514 while (*lpStr)
3515 {
3516 cchLength = strlen(lpStr) + 1;
3517 dwDependenciesLength += (DWORD)cchLength;
3518 lpStr = lpStr + cchLength;
3519 }
3520 dwDependenciesLength++;
3521
3522 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3523 if (!lpDependenciesW)
3524 {
3526 goto cleanup;
3527 }
3528 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3529 }
3530
3531 if (lpServiceStartName)
3532 {
3533 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3534 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3535 if (!lpServiceStartNameW)
3536 {
3538 goto cleanup;
3539 }
3540 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3541 }
3542
3543 if (lpDisplayName)
3544 {
3546 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3547 if (!lpDisplayNameW)
3548 {
3550 goto cleanup;
3551 }
3552 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3553 }
3554
3555 dwError = RChangeServiceConfigW(hService,
3556 dwServiceType,
3557 dwStartType,
3558 dwErrorControl,
3559 lpBinaryPathNameW,
3560 lpLoadOrderGroupW,
3561 lpdwTagId,
3562 (LPBYTE)lpDependenciesW,
3563 dwDependenciesLength,
3564 lpServiceStartNameW,
3565 lpPassword,
3566 dwPwSize,
3567 lpDisplayNameW);
3568
3569cleanup:
3570 if (lpBinaryPathNameW != NULL)
3571 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3572
3573 if (lpLoadOrderGroupW != NULL)
3574 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3575
3576 if (lpDependenciesW != NULL)
3577 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3578
3579 if (lpServiceStartNameW != NULL)
3580 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3581
3582 if (lpDisplayNameW != NULL)
3583 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3584
3585 return dwError;
3586}
3587
3588
3589/* Function 24 */
3590DWORD
3591WINAPI
3594 LPSTR lpServiceName,
3596 DWORD dwDesiredAccess,
3597 DWORD dwServiceType,
3598 DWORD dwStartType,
3599 DWORD dwErrorControl,
3600 LPSTR lpBinaryPathName,
3601 LPSTR lpLoadOrderGroup,
3602 LPDWORD lpdwTagId,
3603 LPBYTE lpDependencies,
3604 DWORD dwDependSize,
3605 LPSTR lpServiceStartName,
3606 LPBYTE lpPassword,
3607 DWORD dwPwSize,
3608 LPSC_RPC_HANDLE lpServiceHandle)
3609{
3610 DWORD dwError = ERROR_SUCCESS;
3611 LPWSTR lpServiceNameW = NULL;
3612 LPWSTR lpDisplayNameW = NULL;
3613 LPWSTR lpBinaryPathNameW = NULL;
3614 LPWSTR lpLoadOrderGroupW = NULL;
3615 LPWSTR lpDependenciesW = NULL;
3616 LPWSTR lpServiceStartNameW = NULL;
3617 DWORD dwDependenciesLength = 0;
3618 SIZE_T cchLength;
3619 int len;
3620 LPCSTR lpStr;
3621
3622 if (lpServiceName)
3623 {
3624 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3625 lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3626 if (!lpServiceNameW)
3627 {
3629 goto cleanup;
3630 }
3631 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3632 }
3633
3634 if (lpDisplayName)
3635 {
3637 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3638 if (!lpDisplayNameW)
3639 {
3641 goto cleanup;
3642 }
3643 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3644 }
3645
3646 if (lpBinaryPathName)
3647 {
3648 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3649 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3650 if (!lpBinaryPathNameW)
3651 {
3653 goto cleanup;
3654 }
3655 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3656 }
3657
3658 if (lpLoadOrderGroup)
3659 {
3660 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3661 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3662 if (!lpLoadOrderGroupW)
3663 {
3665 goto cleanup;
3666 }
3667 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3668 }
3669
3670 if (lpDependencies)
3671 {
3672 lpStr = (LPCSTR)lpDependencies;
3673 while (*lpStr)
3674 {
3675 cchLength = strlen(lpStr) + 1;
3676 dwDependenciesLength += (DWORD)cchLength;
3677 lpStr = lpStr + cchLength;
3678 }
3679 dwDependenciesLength++;
3680
3681 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3682 if (!lpDependenciesW)
3683 {
3685 goto cleanup;
3686 }
3687 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3688 }
3689
3690 if (lpServiceStartName)
3691 {
3692 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3693 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3694 if (!lpServiceStartNameW)
3695 {
3697 goto cleanup;
3698 }
3699 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3700 }
3701
3702 dwError = RCreateServiceW(hSCManager,
3703 lpServiceNameW,
3704 lpDisplayNameW,
3705 dwDesiredAccess,
3706 dwServiceType,
3707 dwStartType,
3708 dwErrorControl,
3709 lpBinaryPathNameW,
3710 lpLoadOrderGroupW,
3711 lpdwTagId,
3712 (LPBYTE)lpDependenciesW,
3713 dwDependenciesLength,
3714 lpServiceStartNameW,
3715 lpPassword,
3716 dwPwSize,
3717 lpServiceHandle);
3718
3719cleanup:
3720 if (lpServiceNameW !=NULL)
3721 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3722
3723 if (lpDisplayNameW != NULL)
3724 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3725
3726 if (lpBinaryPathNameW != NULL)
3727 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3728
3729 if (lpLoadOrderGroupW != NULL)
3730 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3731
3732 if (lpDependenciesW != NULL)
3733 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3734
3735 if (lpServiceStartNameW != NULL)
3736 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3737
3738 return dwError;
3739}
3740
3741
3742/* Function 25 */
3743DWORD
3744WINAPI
3746 SC_RPC_HANDLE hService,
3747 DWORD dwServiceState,
3748 LPBYTE lpServices,
3751 LPBOUNDED_DWORD_256K lpServicesReturned)
3752{
3753 DWORD dwError = ERROR_SUCCESS;
3754 DWORD dwServicesReturned = 0;
3755 DWORD dwServiceCount;
3757 PSERVICE_HANDLE hSvc;
3758 PSERVICE lpService = NULL;
3759 PSERVICE *lpServicesArray = NULL;
3760 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3761 LPSTR lpStr;
3762
3763 *pcbBytesNeeded = 0;
3764 *lpServicesReturned = 0;
3765
3766 DPRINT("REnumDependentServicesA() called\n");
3767
3768 hSvc = ScmGetServiceFromHandle(hService);
3769 if (hSvc == NULL)
3770 {
3771 DPRINT1("Invalid service handle\n");
3772 return ERROR_INVALID_HANDLE;
3773 }
3774
3775 lpService = hSvc->ServiceEntry;
3776
3777 /* Check access rights */
3780 {
3781 DPRINT("Insufficient access rights! 0x%lx\n",
3782 hSvc->Handle.DesiredAccess);
3783 return ERROR_ACCESS_DENIED;
3784 }
3785
3786 /* Open the Services Reg key */
3788 L"System\\CurrentControlSet\\Services",
3789 0,
3790 KEY_READ,
3791 &hServicesKey);
3792
3793 if (dwError != ERROR_SUCCESS)
3794 return dwError;
3795
3796 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3797 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3798 are the same for both. Verified in WINXP. */
3799
3800 /* First determine the bytes needed and get the number of dependent services*/
3802 lpService,
3803 dwServiceState,
3804 NULL,
3806 &dwServicesReturned);
3807 if (dwError != ERROR_SUCCESS)
3808 goto Done;
3809
3810 /* If buffer size is less than the bytes needed or pointer is null*/
3811 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3812 {
3813 dwError = ERROR_MORE_DATA;
3814 goto Done;
3815 }
3816
3817 /* Allocate memory for array of service pointers */
3818 lpServicesArray = HeapAlloc(GetProcessHeap(),
3820 (dwServicesReturned + 1) * sizeof(PSERVICE));
3821 if (!lpServicesArray)
3822 {
3823 DPRINT("Could not allocate buffer\n");
3824 dwError = ERROR_NOT_ENOUGH_MEMORY;
3825 goto Done;
3826 }
3827
3828 dwServicesReturned = 0;
3829 *pcbBytesNeeded = 0;
3830
3832 lpService,
3833 dwServiceState,
3834 lpServicesArray,
3836 &dwServicesReturned);
3837 if (dwError != ERROR_SUCCESS)
3838 {
3839 goto Done;
3840 }
3841
3842 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3843 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3844
3845 /* Copy EnumDepenedentService to Buffer */
3846 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3847 {
3848 lpService = lpServicesArray[dwServiceCount];
3849
3850 /* Copy the status info */
3851 memcpy(&lpServicesPtr->ServiceStatus,
3852 &lpService->Status,
3853 sizeof(SERVICE_STATUS));
3854
3855 /* Copy display name */
3857 0,
3858 lpService->lpDisplayName,
3859 -1,
3860 lpStr,
3861 (int)wcslen(lpService->lpDisplayName),
3862 0,
3863 0);
3864 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3865 lpStr += strlen(lpStr) + 1;
3866
3867 /* Copy service name */
3869 0,
3870 lpService->lpServiceName,
3871 -1,
3872 lpStr,
3873 (int)wcslen(lpService->lpServiceName),
3874 0,
3875 0);
3876 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3877 lpStr += strlen(lpStr) + 1;
3878
3879 lpServicesPtr++;
3880 }
3881
3882 *lpServicesReturned = dwServicesReturned;
3883
3884Done:
3885 if (lpServicesArray)
3886 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3887
3889
3890 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3891
3892 return dwError;
3893}
3894
3895
3896/* Function 26 */
3897DWORD
3898WINAPI
3901 DWORD dwServiceType,
3902 DWORD dwServiceState,
3904 DWORD dwBufSize,
3906 LPBOUNDED_DWORD_256K lpServicesReturned,
3907 LPBOUNDED_DWORD_256K lpResumeHandle)
3908{
3909 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3910 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
3911 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3912 LPWSTR lpStringPtrW;
3913 LPSTR lpStringPtrA;
3914 DWORD dwError;
3915 DWORD dwServiceCount;
3916
3917 DPRINT("REnumServicesStatusA() called\n");
3918
3919 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
3920 {
3921 return ERROR_INVALID_ADDRESS;
3922 }
3923
3924 if ((dwBufSize > 0) && (lpBuffer))
3925 {
3926 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3927 if (!lpStatusPtrW)
3928 {
3929 DPRINT("Failed to allocate buffer\n");
3931 }
3932 }
3933
3935 dwServiceType,
3936 dwServiceState,
3937 (LPBYTE)lpStatusPtrW,
3938 dwBufSize,
3940 lpServicesReturned,
3941 lpResumeHandle);
3942
3943 /* if no services were returned then we are Done */
3944 if (*lpServicesReturned == 0)
3945 goto Done;
3946
3947 lpStatusPtrIncrW = lpStatusPtrW;
3948 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3949 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3950 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3951 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3952 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3953
3954 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3955 {
3956 /* Copy the service name */
3958 0,
3959 lpStringPtrW,
3960 -1,
3961 lpStringPtrA,
3962 (int)wcslen(lpStringPtrW),
3963 0,
3964 0);
3965
3966 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3967 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3968 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3969
3970 /* Copy the display name */
3972 0,
3973 lpStringPtrW,
3974 -1,
3975 lpStringPtrA,
3976 (int)wcslen(lpStringPtrW),
3977 0,
3978 0);
3979
3980 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3981 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3982 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3983
3984 /* Copy the status information */
3985 memcpy(&lpStatusPtrA->ServiceStatus,
3986 &lpStatusPtrIncrW->ServiceStatus,
3987 sizeof(SERVICE_STATUS));
3988
3989 lpStatusPtrIncrW++;
3990 lpStatusPtrA++;
3991 }
3992
3993Done:
3994 if (lpStatusPtrW)
3995 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3996
3997 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3998
3999 return dwError;
4000}
4001
4002
4003/* Function 27 */
4004DWORD
4005WINAPI
4007 LPSTR lpMachineName,
4008 LPSTR lpDatabaseName,
4009 DWORD dwDesiredAccess,
4010 LPSC_RPC_HANDLE lpScHandle)
4011{
4013 UNICODE_STRING DatabaseName;
4014 DWORD dwError;
4015
4016 DPRINT("ROpenSCManagerA() called\n");
4017
4018 if (lpMachineName)
4020 lpMachineName);
4021
4022 if (lpDatabaseName)
4024 lpDatabaseName);
4025
4026 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
4027 lpDatabaseName ? DatabaseName.Buffer : NULL,
4028 dwDesiredAccess,
4029 lpScHandle);
4030
4031 if (lpMachineName)
4033
4034 if (lpDatabaseName)
4035 RtlFreeUnicodeString(&DatabaseName);
4036
4037 return dwError;
4038}
4039
4040
4041/* Function 28 */
4042DWORD
4043WINAPI
4046 LPSTR lpServiceName,
4047 DWORD dwDesiredAccess,
4048 LPSC_RPC_HANDLE lpServiceHandle)
4049{
4051 DWORD dwError;
4052
4053 DPRINT("ROpenServiceA() called\n");
4054
4055 if (lpServiceName)
4057 lpServiceName);
4058
4059 dwError = ROpenServiceW(hSCManager,
4060 lpServiceName ? ServiceName.Buffer : NULL,
4061 dwDesiredAccess,
4062 lpServiceHandle);
4063
4064 if (lpServiceName)
4066
4067 return dwError;
4068}
4069
4070
4071/* Function 29 */
4072DWORD
4073WINAPI
4075 SC_RPC_HANDLE hService,
4076 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4079{
4080 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
4081 DWORD dwError = ERROR_SUCCESS;
4082 PSERVICE_HANDLE hSvc;
4083 PSERVICE lpService = NULL;
4084 HKEY hServiceKey = NULL;
4085 LPWSTR lpImagePath = NULL;
4086 LPWSTR lpServiceStartName = NULL;
4087 LPWSTR lpDependencies = NULL;
4088 DWORD dwDependenciesLength = 0;
4089 DWORD dwRequiredSize;
4090 LPSTR lpStr;
4091
4092 DPRINT("RQueryServiceConfigA() called\n");
4093
4094 if (ScmShutdown)
4096
4097 hSvc = ScmGetServiceFromHandle(hService);
4098 if (hSvc == NULL)
4099 {
4100 DPRINT1("Invalid service handle\n");
4101 return ERROR_INVALID_HANDLE;
4102 }
4103
4106 {
4107 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4108 return ERROR_ACCESS_DENIED;
4109 }
4110
4111 lpService = hSvc->ServiceEntry;
4112 if (lpService == NULL)
4113 {
4114 DPRINT("lpService == NULL\n");
4115 return ERROR_INVALID_HANDLE;
4116 }
4117
4118 /* Lock the service database shared */
4120
4121 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4122 KEY_READ,
4123 &hServiceKey);
4124 if (dwError != ERROR_SUCCESS)
4125 goto Done;
4126
4127 /* Read the image path */
4128 dwError = ScmReadString(hServiceKey,
4129 L"ImagePath",
4130 &lpImagePath);
4131 if (dwError != ERROR_SUCCESS)
4132 goto Done;
4133
4134 /* Read the service start name */
4135 ScmReadString(hServiceKey,
4136 L"ObjectName",
4137 &lpServiceStartName);
4138
4139 /* Read the dependencies */
4140 ScmReadDependencies(hServiceKey,
4141 &lpDependencies,
4142 &dwDependenciesLength);
4143
4144 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA);
4145
4146 if (lpImagePath != NULL)
4147 dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
4148 else
4149 dwRequiredSize += 2 * sizeof(CHAR);
4150
4151 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
4152 dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
4153 else
4154 dwRequiredSize += 2 * sizeof(CHAR);
4155
4156 /* Add Dependencies length */
4157 if (lpDependencies != NULL)
4158 dwRequiredSize += dwDependenciesLength;
4159 else
4160 dwRequiredSize += 2 * sizeof(CHAR);
4161
4162 if (lpServiceStartName != NULL)
4163 dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
4164 else
4165 dwRequiredSize += 2 * sizeof(CHAR);
4166
4167 if (lpService->lpDisplayName != NULL)
4168 dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
4169 else
4170 dwRequiredSize += 2 * sizeof(CHAR);
4171
4172 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
4173 {
4174 dwError = ERROR_INSUFFICIENT_BUFFER;
4175 }
4176 else
4177 {
4178 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
4179 lpServiceConfig->dwStartType = lpService->dwStartType;
4180 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
4181 lpServiceConfig->dwTagId = lpService->dwTag;
4182
4183 lpStr = (LPSTR)(lpServiceConfig + 1);
4184
4185 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4186 Verified in WINXP */
4187
4188 if (lpImagePath)
4189 {
4191 0,
4192 lpImagePath,
4193 -1,
4194 lpStr,
4195 (int)(wcslen(lpImagePath) + 1),
4196 0,
4197 0);
4198 }
4199 else
4200 {
4201 *lpStr = 0;
4202 }
4203
4204 lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4205 lpStr += (strlen((LPSTR)lpStr) + 1);
4206
4207 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4208 {
4210 0,
4211 lpService->lpGroup->lpGroupName,
4212 -1,
4213 lpStr,
4214 (int)(wcslen(lpService->lpGroup->lpGroupName) + 1),
4215 0,
4216 0);
4217 }
4218 else
4219 {
4220 *lpStr = 0;
4221 }
4222
4223 lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4224 lpStr += (strlen(lpStr) + 1);
4225
4226 /* Append Dependencies */
4227 if (lpDependencies)
4228 {
4230 0,
4231 lpDependencies,
4232 dwDependenciesLength,
4233 lpStr,
4234 dwDependenciesLength,
4235 0,
4236 0);
4237 }
4238 else
4239 {
4240 *lpStr = 0;
4241 }
4242
4243 lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4244 if (lpDependencies)
4245 lpStr += dwDependenciesLength;
4246 else
4247 lpStr += (strlen(lpStr) + 1);
4248
4249 if (lpServiceStartName)
4250 {
4252 0,
4253 lpServiceStartName,
4254 -1,
4255 lpStr,
4256 (int)(wcslen(lpServiceStartName) + 1),
4257 0,
4258 0);
4259 }
4260 else
4261 {
4262 *lpStr = 0;
4263 }
4264
4265 lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4266 lpStr += (strlen(lpStr) + 1);
4267
4268 if (lpService->lpDisplayName)
4269 {
4271 0,
4272 lpService->lpDisplayName,
4273 -1,
4274 lpStr,
4275 (int)(wcslen(lpService->lpDisplayName) + 1),
4276 0,
4277 0);
4278 }
4279 else
4280 {
4281 *lpStr = 0;
4282 }
4283
4284 lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4285 }
4286
4287 if (pcbBytesNeeded != NULL)
4288 *pcbBytesNeeded = dwRequiredSize;
4289
4290Done:
4291 /* Unlock the service database */
4293
4294 if (lpImagePath != NULL)
4295 HeapFree(GetProcessHeap(), 0, lpImagePath);
4296
4297 if (lpServiceStartName != NULL)
4298 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4299
4300 if (lpDependencies != NULL)
4301 HeapFree(GetProcessHeap(), 0, lpDependencies);
4302
4303 if (hServiceKey != NULL)
4304 RegCloseKey(hServiceKey);
4305
4306 DPRINT("RQueryServiceConfigA() done\n");
4307
4308 return dwError;
4309}
4310
4311
4312/* Function 30 */
4313DWORD
4314WINAPI
4317 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4320{
4322 PMANAGER_HANDLE hMgr;
4323 DWORD dwRequiredSize;
4324
4325 if (!lpLockStatus || !pcbBytesNeeded)
4327
4329 if (hMgr == NULL)
4330 {
4331 DPRINT1("Invalid service manager handle\n");
4332 return ERROR_INVALID_HANDLE;
4333 }
4334
4337 {
4338 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
4339 return ERROR_ACCESS_DENIED;
4340 }
4341
4342 /* FIXME: we need to compute instead the real length of the owner name */
4343 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR);
4344 *pcbBytesNeeded = dwRequiredSize;
4345
4346 if (cbBufSize < dwRequiredSize)
4348
4349 ScmQueryServiceLockStatusA(lpLockStatus);
4350
4351 return ERROR_SUCCESS;
4352}
4353
4354
4355/* Function 31 */
4356DWORD
4357WINAPI
4359 SC_RPC_HANDLE hService,
4360 DWORD argc,
4362{
4363 DWORD dwError = ERROR_SUCCESS;
4364 PSERVICE_HANDLE hSvc;
4365 PSERVICE lpService = NULL;
4366 LPWSTR *lpVector = NULL;
4367 DWORD i;
4369
4370 DPRINT("RStartServiceA() called\n");
4371
4372 if (ScmShutdown)
4374
4375 hSvc = ScmGetServiceFromHandle(hService);
4376 if (hSvc == NULL)
4377 {
4378 DPRINT1("Invalid service handle\n");
4379 return ERROR_INVALID_HANDLE;
4380 }
4381
4384 {
4385 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4386 return ERROR_ACCESS_DENIED;
4387 }
4388
4389 lpService = hSvc->ServiceEntry;
4390 if (lpService == NULL)
4391 {
4392 DPRINT("lpService == NULL\n");
4393 return ERROR_INVALID_HANDLE;
4394 }
4395
4396 if (lpService->dwStartType == SERVICE_DISABLED)
4398
4399 if (lpService->bDeleted)
4401
4402 /* Build a Unicode argument vector */
4403 if (argc > 0)
4404 {
4405 lpVector = HeapAlloc(GetProcessHeap(),
4407 argc * sizeof(LPWSTR));
4408 if (lpVector == NULL)
4410
4411 for (i = 0; i < argc; i++)
4412 {
4414 0,
4415 ((LPSTR*)argv)[i],
4416 -1,
4417 NULL,
4418 0);
4419
4420 lpVector[i] = HeapAlloc(GetProcessHeap(),
4422 dwLength * sizeof(WCHAR));
4423 if (lpVector[i] == NULL)
4424 {
4425 dwError = ERROR_NOT_ENOUGH_MEMORY;
4426 goto done;
4427 }
4428
4430 0,
4431 ((LPSTR*)argv)[i],
4432 -1,
4433 lpVector[i],
4434 dwLength);
4435 }
4436 }
4437
4438 /* Start the service */
4439 dwError = ScmStartService(lpService, argc, lpVector);
4440
4441done:
4442 /* Free the Unicode argument vector */
4443 if (lpVector != NULL)
4444 {
4445 for (i = 0; i < argc; i++)
4446 {
4447 if (lpVector[i] != NULL)
4448 HeapFree(GetProcessHeap(), 0, lpVector[i]);
4449 }
4450 HeapFree(GetProcessHeap(), 0, lpVector);
4451 }
4452
4453 return dwError;
4454}
4455
4456
4457/* Function 32 */
4458DWORD
4459WINAPI
4462 LPCSTR lpServiceName,
4464 LPBOUNDED_DWORD_4K lpcchBuffer)
4465{
4466 // PMANAGER_HANDLE hManager;
4467 PSERVICE lpService = NULL;
4468 LPCWSTR lpSvcDisplayName;
4469 LPWSTR lpServiceNameW;
4471
4472 DPRINT("RGetServiceDisplayNameA() called\n");
4473 DPRINT("hSCManager = %p\n", hSCManager);
4474 DPRINT("lpServiceName: %s\n", lpServiceName);
4475 DPRINT("lpDisplayName: %p\n", lpDisplayName);
4476 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4477
4478#if 0
4479 hManager = (PMANAGER_HANDLE)hSCManager;
4480 if (hManager->Handle.Tag != MANAGER_TAG)
4481 {
4482 DPRINT("Invalid manager handle\n");
4483 return ERROR_INVALID_HANDLE;
4484 }
4485#endif
4486
4487 /* Get service database entry */
4488 if (lpServiceName != NULL)
4489 {
4490 dwLength = (DWORD)(strlen(lpServiceName) + 1);
4491 lpServiceNameW = HeapAlloc(GetProcessHeap(),
4493 dwLength * sizeof(WCHAR));
4494 if (!lpServiceNameW)
4496
4498 0,
4499 lpServiceName,
4500 -1,
4501 lpServiceNameW,
4502 dwLength);
4503
4504 lpService = ScmGetServiceEntryByName(lpServiceNameW);
4505
4506 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4507 }
4508
4509 if (lpService == NULL)
4510 {
4511 DPRINT("Could not find service\n");
4513 }
4514
4515 if (lpService->lpDisplayName)
4516 lpSvcDisplayName = lpService->lpDisplayName;
4517 else
4518 lpSvcDisplayName = lpService->lpServiceName;
4519
4520 /*
4521 * NOTE: On Windows the comparison on *lpcchBuffer is made against
4522 * the number of (wide) characters of the UNICODE display name, and
4523 * not against the number of bytes needed to store the ANSI string.
4524 */
4525 dwLength = (DWORD)wcslen(lpSvcDisplayName);
4526
4527 if (*lpcchBuffer > dwLength)
4528 {
4529 if (lpDisplayName != NULL &&
4531 0,
4532 lpSvcDisplayName,
4533 -1,
4535 (int)*lpcchBuffer,
4536 NULL,
4537 NULL) == 0)
4538 {
4539 /*
4540 * But then, if *lpcchBuffer was greater than the number of
4541 * (wide) characters of the UNICODE display name, yet smaller
4542 * than the number of bytes needed due to the possible presence
4543 * of DBCS characters, the *exact* number of bytes is returned
4544 * (without the NULL terminator).
4545 */
4547 0,
4548 lpSvcDisplayName,
4549 (int)dwLength,
4550 NULL,
4551 0,
4552 NULL,
4553 NULL);
4554 *lpDisplayName = 0;
4555 *lpcchBuffer = dwLength;
4557 }
4558
4559 /*
4560 * NOTE: On Windows, RGetServiceDisplayNameA() does not update
4561 * *lpcchBuffer on success, contrary to RGetServiceDisplayNameW().
4562 */
4563 return ERROR_SUCCESS;
4564 }
4565 else
4566 {
4567 /*
4568 * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4569 * (wide) characters of the UNICODE display name, only an upper
4570 * estimation is returned by doubling the string length, to account
4571 * for the presence of any possible DBCS characters.
4572 */
4573 *lpcchBuffer = dwLength * sizeof(WCHAR);
4575 }
4576}
4577
4578
4579/* Function 33 */
4580DWORD
4581WINAPI
4585 LPSTR lpServiceName,
4586 LPBOUNDED_DWORD_4K lpcchBuffer)
4587{
4588 // PMANAGER_HANDLE hManager;
4589 PSERVICE lpService;
4590 LPWSTR lpDisplayNameW;
4592
4593 DPRINT("RGetServiceKeyNameA() called\n");
4594 DPRINT("hSCManager = %p\n", hSCManager);
4595 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4596 DPRINT("lpServiceName: %p\n", lpServiceName);
4597 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4598
4599#if 0
4600 hManager = (PMANAGER_HANDLE)hSCManager;
4601 if (hManager->Handle.Tag != MANAGER_TAG)
4602 {
4603 DPRINT("Invalid manager handle\n");
4604 return ERROR_INVALID_HANDLE;
4605 }
4606#endif
4607
4608 /* Get service database entry */
4609
4611 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4613 dwLength * sizeof(WCHAR));
4614 if (!lpDisplayNameW)
4616
4618 0,
4620 -1,
4621 lpDisplayNameW,
4622 dwLength);
4623
4624 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4625
4626 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4627
4628 if (lpService == NULL)
4629 {
4630 DPRINT("Could not find service\n");
4632 }
4633
4634 /*
4635 * NOTE: On Windows the comparison on *lpcchBuffer is made against
4636 * the number of (wide) characters of the UNICODE service name, and
4637 * not against the number of bytes needed to store the ANSI string.
4638 */
4639 dwLength = (DWORD)wcslen(lpService->lpServiceName);
4640
4641 if (*lpcchBuffer > dwLength)
4642 {
4643 if (lpServiceName != NULL &&
4645 0,
4646 lpService->lpServiceName,
4647 -1,
4648 lpServiceName,
4649 (int)*lpcchBuffer,
4650 NULL,
4651 NULL) == 0)
4652 {
4653 /*
4654 * But then, if *lpcchBuffer was greater than the number of
4655 * (wide) characters of the UNICODE service name, yet smaller
4656 * than the number of bytes needed due to the possible presence
4657 * of DBCS characters, the *exact* number of bytes is returned
4658 * (without the NULL terminator).
4659 */
4661 0,
4662 lpService->lpServiceName,
4663 (int)dwLength,
4664 NULL,
4665 0,
4666 NULL,
4667 NULL);
4668 *lpServiceName = 0;
4669 *lpcchBuffer = dwLength;
4671 }
4672
4673 /*
4674 * NOTE: On Windows, RGetServiceKeyNameA() does not update
4675 * *lpcchBuffer on success, contrary to RGetServiceKeyNameW().
4676 */
4677 return ERROR_SUCCESS;
4678 }
4679 else
4680 {
4681 /*
4682 * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4683 * (wide) characters of the UNICODE service name, only an upper
4684 * estimation is returned by doubling the string length, to account
4685 * for the presence of any possible DBCS characters.
4686 */
4687 *lpcchBuffer = dwLength * sizeof(WCHAR);
4689 }
4690}
4691
4692
4693/* Function 34 */
4694DWORD
4695WINAPI
4698 LPWSTR lpLoadOrderGroup,
4699 LPDWORD lpState)
4700{
4701 PMANAGER_HANDLE hManager;
4702 PSERVICE_GROUP pServiceGroup;
4703 DWORD dwError = ERROR_SUCCESS;
4704
4705 DPRINT("RI_ScGetCurrentGroupStateW() called\n");
4706
4707 if (ScmShutdown)
4709
4711 if (hManager == NULL)
4712 {
4713 DPRINT1("Invalid service manager handle\n");
4714 return ERROR_INVALID_HANDLE;
4715 }
4716
4717 /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */
4720 {
4721 DPRINT("Insufficient access rights! 0x%lx\n",
4722 hManager->Handle.DesiredAccess);
4723 return ERROR_ACCESS_DENIED;
4724 }
4725
4726 /* Lock the service database shared */
4728
4729 /* Get the group list entry */
4730 pServiceGroup = ScmGetServiceGroupByName(lpLoadOrderGroup);
4731 if (pServiceGroup == NULL)
4732 {
4734 goto done;
4735 }
4736
4737 /* FIXME: Return the group state */
4738 *lpState = 0;
4739
4740done:
4741 /* Unlock the service database */
4743
4744 DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError);
4745
4746 return dwError;
4747}
4748
4749
4750/* Function 35 */
4751DWORD
4752WINAPI
4755 DWORD dwServiceType,
4756 DWORD dwServiceState,
4760 LPBOUNDED_DWORD_256K lpServicesReturned,
4761 LPBOUNDED_DWORD_256K lpResumeIndex,
4762 LPCWSTR pszGroupName)
4763{
4764 PMANAGER_HANDLE hManager;
4765 PSERVICE lpService;
4766 DWORD dwError = ERROR_SUCCESS;
4767 PLIST_ENTRY ServiceEntry;
4768 PSERVICE CurrentService;
4769 DWORD dwState;
4770 DWORD dwRequiredSize;
4771 DWORD dwServiceCount;
4772 DWORD dwSize;
4773 DWORD dwLastResumeCount = 0;
4774 LPENUM_SERVICE_STATUSW lpStatusPtr;
4775 LPWSTR lpStringPtr;
4776
4777 DPRINT("REnumServiceGroupW() called\n");
4778
4779 if (ScmShutdown)
4781
4783 if (hManager == NULL)
4784 {
4785 DPRINT1("Invalid service manager handle\n");
4786 return ERROR_INVALID_HANDLE;
4787 }
4788
4789 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
4790 {
4791 return ERROR_INVALID_ADDRESS;
4792 }
4793
4794 *pcbBytesNeeded = 0;
4795 *lpServicesReturned = 0;
4796
4797 if ((dwServiceType == 0) ||
4798 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
4799 {
4800 DPRINT("Invalid Service Type\n");
4802 }
4803
4804 if ((dwServiceState == 0) ||
4805 ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
4806 {
4807 DPRINT("Invalid Service State\n");
4809 }
4810
4811 /* Check access rights */
4814 {
4815 DPRINT("Insufficient access rights! 0x%lx\n",
4816 hManager->Handle.DesiredAccess);
4817 return ERROR_ACCESS_DENIED;
4818 }
4819
4820 if (lpResumeIndex)
4821 dwLastResumeCount = *lpResumeIndex;
4822
4823 /* Lock the service database shared */
4825
4826 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4827 if (lpService == NULL)
4828 {
4829 dwError = ERROR_SUCCESS;
4830 goto Done;
4831 }
4832
4833 dwRequiredSize = 0;
4834 dwServiceCount = 0;
4835
4836 for (ServiceEntry = &lpService->ServiceListEntry;
4837 ServiceEntry != &ServiceListHead;
4838 ServiceEntry = ServiceEntry->Flink)
4839 {
4840 CurrentService = CONTAINING_RECORD(ServiceEntry,
4841 SERVICE,
4842 ServiceListEntry);
4843
4844 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4845 continue;
4846
4847 dwState = SERVICE_ACTIVE;
4848 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4849 dwState = SERVICE_INACTIVE;
4850
4851 if ((dwState & dwServiceState) == 0)
4852 continue;
4853
4854 if (pszGroupName)
4855 {
4856 if (*pszGroupName == 0)
4857 {
4858 if (CurrentService->lpGroup != NULL)
4859 continue;
4860 }
4861 else
4862 {
4863 if ((CurrentService->lpGroup == NULL) ||
4864 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4865 continue;
4866 }
4867 }
4868
4869 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4870 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4871 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4872
4873 if (dwRequiredSize + dwSize > cbBufSize)
4874 {
4875 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4876 break;
4877 }
4878
4879 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4880 dwRequiredSize += dwSize;
4881 dwServiceCount++;
4882 dwLastResumeCount = CurrentService->dwResumeCount;
4883 }
4884
4885 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4886 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4887
4888 for (;
4889 ServiceEntry != &ServiceListHead;
4890 ServiceEntry = ServiceEntry->Flink)
4891 {
4892 CurrentService = CONTAINING_RECORD(ServiceEntry,
4893 SERVICE,
4894 ServiceListEntry);
4895
4896 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4897 continue;
4898
4899 dwState = SERVICE_ACTIVE;
4900 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4901 dwState = SERVICE_INACTIVE;
4902
4903 if ((dwState & dwServiceState) == 0)
4904 continue;
4905
4906 if (pszGroupName)
4907 {
4908 if (*pszGroupName == 0)
4909 {
4910 if (CurrentService->