ReactOS  0.4.14-dev-98-gb0d4763
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 #define NDEBUG
19 #include <debug.h>
20 
21 /* GLOBALS *****************************************************************/
22 
23 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
24 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
25 #define INVALID_TAG 0xAABBCCDD
26 
27 typedef struct _SCMGR_HANDLE
28 {
31 } SCMGR_HANDLE;
32 
33 
34 typedef struct _MANAGER_HANDLE
35 {
39 
40 
41 typedef struct _SERVICE_HANDLE
42 {
46 
47 
48 #define SC_MANAGER_READ \
49  (STANDARD_RIGHTS_READ | \
50  SC_MANAGER_QUERY_LOCK_STATUS | \
51  SC_MANAGER_ENUMERATE_SERVICE)
52 
53 #define SC_MANAGER_WRITE \
54  (STANDARD_RIGHTS_WRITE | \
55  SC_MANAGER_MODIFY_BOOT_CONFIG | \
56  SC_MANAGER_CREATE_SERVICE)
57 
58 #define SC_MANAGER_EXECUTE \
59  (STANDARD_RIGHTS_EXECUTE | \
60  SC_MANAGER_LOCK | \
61  SC_MANAGER_ENUMERATE_SERVICE | \
62  SC_MANAGER_CONNECT | \
63  SC_MANAGER_CREATE_SERVICE)
64 
65 
66 #define SERVICE_READ \
67  (STANDARD_RIGHTS_READ | \
68  SERVICE_INTERROGATE | \
69  SERVICE_ENUMERATE_DEPENDENTS | \
70  SERVICE_QUERY_STATUS | \
71  SERVICE_QUERY_CONFIG)
72 
73 #define SERVICE_WRITE \
74  (STANDARD_RIGHTS_WRITE | \
75  SERVICE_CHANGE_CONFIG)
76 
77 #define SERVICE_EXECUTE \
78  (STANDARD_RIGHTS_EXECUTE | \
79  SERVICE_USER_DEFINED_CONTROL | \
80  SERVICE_PAUSE_CONTINUE | \
81  SERVICE_STOP | \
82  SERVICE_START)
83 
84 #define TAG_ARRAY_SIZE 32
85 
86 /* VARIABLES ***************************************************************/
87 
88 static GENERIC_MAPPING
93 
94 static GENERIC_MAPPING
99 
101 
102 /* FUNCTIONS ***************************************************************/
103 
104 VOID
106 {
108 
109  DPRINT("ScmStartRpcServer() called\n");
110 
111  Status = RpcServerUseProtseqEpW(L"ncacn_np",
112  10,
113  L"\\pipe\\ntsvcs",
114  NULL);
115  if (Status != RPC_S_OK)
116  {
117  DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
118  return;
119  }
120 
121  Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
122  NULL,
123  NULL);
124  if (Status != RPC_S_OK)
125  {
126  DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
127  return;
128  }
129 
130  Status = RpcServerListen(1, 20, TRUE);
131  if (Status != RPC_S_OK)
132  {
133  DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
134  return;
135  }
136 
137  DPRINT("ScmStartRpcServer() done\n");
138 }
139 
140 
141 static DWORD
143  SC_HANDLE *Handle)
144 {
146 
147  if (lpDatabaseName == NULL)
148  lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
149 
150  if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
151  {
152  DPRINT("Database %S, does not exist\n", lpDatabaseName);
154  }
155  else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
156  {
157  DPRINT("Invalid Database name %S.\n", lpDatabaseName);
158  return ERROR_INVALID_NAME;
159  }
160 
163  FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1]));
164  if (Ptr == NULL)
166 
167  Ptr->Handle.Tag = MANAGER_TAG;
168 
169  wcscpy(Ptr->DatabaseName, lpDatabaseName);
170 
171  *Handle = (SC_HANDLE)Ptr;
172 
173  return ERROR_SUCCESS;
174 }
175 
176 
177 static DWORD
179  SC_HANDLE *Handle)
180 {
182 
185  sizeof(SERVICE_HANDLE));
186  if (Ptr == NULL)
188 
189  Ptr->Handle.Tag = SERVICE_TAG;
190 
191  Ptr->ServiceEntry = lpServiceEntry;
192 
193  *Handle = (SC_HANDLE)Ptr;
194 
195  return ERROR_SUCCESS;
196 }
197 
198 
199 static PMANAGER_HANDLE
201 {
202  PMANAGER_HANDLE pManager = NULL;
203 
204  _SEH2_TRY
205  {
206  if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
207  pManager = (PMANAGER_HANDLE)Handle;
208  }
210  {
211  DPRINT1("Exception: Invalid Service Manager handle!\n");
212  }
213  _SEH2_END;
214 
215  return pManager;
216 }
217 
218 
219 static PSERVICE_HANDLE
221 {
222  PSERVICE_HANDLE pService = NULL;
223 
224  _SEH2_TRY
225  {
226  if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
227  pService = (PSERVICE_HANDLE)Handle;
228  }
230  {
231  DPRINT1("Exception: Invalid Service handle!\n");
232  }
233  _SEH2_END;
234 
235  return pService;
236 }
237 
238 
239 static DWORD
241  DWORD dwDesiredAccess)
242 {
243  PMANAGER_HANDLE hMgr;
244 
245  hMgr = (PMANAGER_HANDLE)Handle;
246  if (hMgr->Handle.Tag == MANAGER_TAG)
247  {
248  RtlMapGenericMask(&dwDesiredAccess,
250 
251  hMgr->Handle.DesiredAccess = dwDesiredAccess;
252 
253  return ERROR_SUCCESS;
254  }
255  else if (hMgr->Handle.Tag == SERVICE_TAG)
256  {
257  RtlMapGenericMask(&dwDesiredAccess,
259 
260  hMgr->Handle.DesiredAccess = dwDesiredAccess;
261 
262  return ERROR_SUCCESS;
263  }
264 
265  return ERROR_INVALID_HANDLE;
266 }
267 
268 
269 DWORD
271 {
272  HKEY hKey = NULL;
273  DWORD dwError;
274  DWORD dwGroupTagCount = 0;
275  PDWORD pdwGroupTags = NULL;
276  DWORD dwFreeTag = 0;
277  DWORD dwTagUsedBase = 1;
278  BOOLEAN TagUsed[TAG_ARRAY_SIZE];
279  INT nTagOffset;
280  DWORD i;
281  DWORD cbDataSize;
282  PLIST_ENTRY ServiceEntry;
283  PSERVICE CurrentService;
284 
285  ASSERT(lpService != NULL);
286  ASSERT(lpService->lpGroup != NULL);
287 
289  L"System\\CurrentControlSet\\Control\\GroupOrderList",
290  0,
291  KEY_READ,
292  &hKey);
293 
294  if (dwError != ERROR_SUCCESS)
295  goto findFreeTag;
296 
297  /* query value length */
298  cbDataSize = 0;
299  dwError = RegQueryValueExW(hKey,
300  lpService->lpGroup->szGroupName,
301  NULL,
302  NULL,
303  NULL,
304  &cbDataSize);
305 
306  if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA)
307  goto findFreeTag;
308 
309  pdwGroupTags = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDataSize);
310  if (!pdwGroupTags)
311  {
312  dwError = ERROR_NOT_ENOUGH_MEMORY;
313  goto cleanup;
314  }
315 
316  dwError = RegQueryValueExW(hKey,
317  lpService->lpGroup->szGroupName,
318  NULL,
319  NULL,
320  (LPBYTE)pdwGroupTags,
321  &cbDataSize);
322 
323  if (dwError != ERROR_SUCCESS)
324  goto findFreeTag;
325 
326  if (cbDataSize < sizeof(pdwGroupTags[0]))
327  goto findFreeTag;
328 
329  dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1);
330 
331 findFreeTag:
332  do
333  {
334  /* mark all tags as unused */
335  for (i = 0; i < TAG_ARRAY_SIZE; i++)
336  TagUsed[i] = FALSE;
337 
338  /* mark tags in GroupOrderList as used */
339  for (i = 1; i <= dwGroupTagCount; i++)
340  {
341  nTagOffset = pdwGroupTags[i] - dwTagUsedBase;
342  if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
343  TagUsed[nTagOffset] = TRUE;
344  }
345 
346  /* mark tags in service list as used */
347  ServiceEntry = lpService->ServiceListEntry.Flink;
348  while (ServiceEntry != &lpService->ServiceListEntry)
349  {
350  ASSERT(ServiceEntry != NULL);
351  CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
352  if (CurrentService->lpGroup == lpService->lpGroup)
353  {
354  nTagOffset = CurrentService->dwTag - dwTagUsedBase;
355  if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
356  TagUsed[nTagOffset] = TRUE;
357  }
358 
359  ServiceEntry = ServiceEntry->Flink;
360  }
361 
362  /* find unused tag, if any */
363  for (i = 0; i < TAG_ARRAY_SIZE; i++)
364  {
365  if (!TagUsed[i])
366  {
367  dwFreeTag = dwTagUsedBase + i;
368  break;
369  }
370  }
371 
372  dwTagUsedBase += TAG_ARRAY_SIZE;
373  } while (!dwFreeTag);
374 
375 cleanup:
376  if (pdwGroupTags)
377  HeapFree(GetProcessHeap(), 0, pdwGroupTags);
378 
379  if (hKey)
380  RegCloseKey(hKey);
381 
382  if (dwFreeTag)
383  {
384  lpService->dwTag = dwFreeTag;
385  DPRINT("Assigning new tag %lu to service %S in group %S\n",
386  lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName);
387  dwError = ERROR_SUCCESS;
388  }
389  else
390  {
391  DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
392  lpService->lpServiceName, dwError);
393  }
394 
395  return dwError;
396 }
397 
398 
399 /* Create a path suitable for the bootloader out of the full path */
400 DWORD
401 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
402 {
403  SIZE_T ServiceNameLen, ExpandedLen;
405  WCHAR Dest;
406  WCHAR *Expanded;
407  UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
410  HANDLE SymbolicLinkHandle;
411 
412  DPRINT("ScmConvertToBootPathName %S\n", CanonName);
413 
414  if (!RelativeName)
416 
417  *RelativeName = NULL;
418 
419  ServiceNameLen = wcslen(CanonName);
420 
421  /* First check, if it's already good */
422  if (ServiceNameLen > 12 &&
423  !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
424  {
425  *RelativeName = HeapAlloc(GetProcessHeap(),
427  (ServiceNameLen + 1) * sizeof(WCHAR));
428  if (*RelativeName == NULL)
429  {
430  DPRINT("Error allocating memory for boot driver name!\n");
432  }
433 
434  /* Copy it */
435  wcscpy(*RelativeName, CanonName);
436 
437  DPRINT("Bootdriver name %S\n", *RelativeName);
438  return ERROR_SUCCESS;
439  }
440 
441  /* If it has %SystemRoot% prefix, substitute it to \System*/
442  if (ServiceNameLen > 13 &&
443  !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
444  {
445  /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
446  *RelativeName = HeapAlloc(GetProcessHeap(),
448  ServiceNameLen * sizeof(WCHAR));
449 
450  if (*RelativeName == NULL)
451  {
452  DPRINT("Error allocating memory for boot driver name!\n");
454  }
455 
456  /* Copy it */
457  wcscpy(*RelativeName, L"\\SystemRoot\\");
458  wcscat(*RelativeName, CanonName + 13);
459 
460  DPRINT("Bootdriver name %S\n", *RelativeName);
461  return ERROR_SUCCESS;
462  }
463 
464  /* Get buffer size needed for expanding env strings */
465  BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
466  if (BufferSize <= 1)
467  {
468  DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
470  }
471 
472  /* Allocate memory, since the size is known now */
473  Expanded = HeapAlloc(GetProcessHeap(),
475  (BufferSize + 1) * sizeof(WCHAR));
476  if (!Expanded)
477  {
478  DPRINT("Error allocating memory for boot driver name!\n");
480  }
481 
482  /* Expand it */
483  if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
484  BufferSize)
485  {
486  DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
487  HeapFree(GetProcessHeap(), 0, Expanded);
489  }
490 
491  /* Convert to NT-style path */
492  if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
493  {
494  DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
496  }
497 
498  DPRINT("Converted to NT-style %wZ\n", &NtPathName);
499 
500  /* No need to keep the dos-path anymore */
501  HeapFree(GetProcessHeap(), 0, Expanded);
502 
503  /* Copy it to the allocated place */
504  Expanded = HeapAlloc(GetProcessHeap(),
506  NtPathName.Length + sizeof(UNICODE_NULL));
507  if (!Expanded)
508  {
509  DPRINT("Error allocating memory for boot driver name!\n");
510  RtlFreeUnicodeString(&NtPathName);
512  }
513 
514  ExpandedLen = NtPathName.Length / sizeof(WCHAR);
515  wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
516  Expanded[ExpandedLen] = UNICODE_NULL;
517  RtlFreeUnicodeString(&NtPathName);
518 
519  if (ServiceNameLen > ExpandedLen &&
520  !_wcsnicmp(Expanded, CanonName, ExpandedLen))
521  {
522  HeapFree(GetProcessHeap(), 0, Expanded);
523 
524  /* Only \SystemRoot\ is missing */
525  *RelativeName = HeapAlloc(GetProcessHeap(),
527  (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
528  if (*RelativeName == NULL)
529  {
530  DPRINT("Error allocating memory for boot driver name!\n");
532  }
533 
534  wcscpy(*RelativeName, L"\\SystemRoot\\");
535  wcscat(*RelativeName, CanonName + ExpandedLen);
536 
537  return ERROR_SUCCESS;
538  }
539 
540  /* No longer need this */
541  HeapFree(GetProcessHeap(), 0, Expanded);
542 
543  /* The most complex case starts here */
544  RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
546  &SystemRoot,
548  NULL,
549  NULL);
550 
551  /* Open this symlink */
553  if (NT_SUCCESS(Status))
554  {
555  DPRINT("Opened symbolic link object\n");
556 
557  RtlInitEmptyUnicodeString(&LinkTarget, NULL, 0);
558  Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
560  {
561  /* Check if required buffer size is sane */
563  {
564  DPRINT("Too large buffer required\n");
565 
566  NtClose(SymbolicLinkHandle);
568  }
569 
570  /* Alloc the string */
576  if (!LinkTarget.Buffer)
577  {
578  DPRINT("Unable to alloc buffer\n");
579  NtClose(SymbolicLinkHandle);
581  }
582 
583  /* Do a real query now */
584  Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
585  NtClose(SymbolicLinkHandle);
586  if (NT_SUCCESS(Status))
587  {
588  DPRINT("LinkTarget: %wZ\n", &LinkTarget);
589 
590  ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
591  if ((ServiceNameLen > ExpandedLen) &&
592  !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
593  {
594  *RelativeName = HeapAlloc(GetProcessHeap(),
596  (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
597 
598  if (*RelativeName == NULL)
599  {
600  DPRINT("Unable to alloc buffer\n");
602  }
603 
604  /* Copy it over, substituting the first part
605  with SystemRoot */
606  wcscpy(*RelativeName, L"\\SystemRoot\\");
607  wcscat(*RelativeName, CanonName+ExpandedLen+1);
608 
609  /* Return success */
610  return ERROR_SUCCESS;
611  }
612  else
613  {
615  }
616  }
617  else
618  {
619  DPRINT("Error, Status = %08X\n", Status);
621  }
622  }
623  else
624  {
625  DPRINT("Error, Status = %08X\n", Status);
626  NtClose(SymbolicLinkHandle);
628  }
629  }
630  else
631  {
632  /* Failure */
633  DPRINT("Error, Status = %08X\n", Status);
635  }
636 }
637 
638 
639 DWORD
641  const wchar_t *lpServiceName,
642  wchar_t **lpCanonName)
643 {
644  DWORD Result;
645  SIZE_T ServiceNameLen;
646  UNICODE_STRING NtServiceName;
647  WCHAR *RelativeName;
648  const WCHAR *SourceName = lpServiceName;
649 
650  /* Calculate the length of the service's name */
651  ServiceNameLen = wcslen(lpServiceName);
652 
653  /* 12 is wcslen(L"\\SystemRoot\\") */
654  if (ServiceNameLen > 12 &&
655  !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
656  {
657  /* SystemRoot prefix is already included */
658  *lpCanonName = HeapAlloc(GetProcessHeap(),
660  (ServiceNameLen + 1) * sizeof(WCHAR));
661 
662  if (*lpCanonName == NULL)
663  {
664  DPRINT("Error allocating memory for canonized service name!\n");
666  }
667 
668  /* If it's a boot-time driver, it must be systemroot relative */
669  if (dwStartType == SERVICE_BOOT_START)
670  SourceName += 12;
671 
672  /* Copy it */
673  wcscpy(*lpCanonName, SourceName);
674 
675  DPRINT("Canonicalized name %S\n", *lpCanonName);
676  return NO_ERROR;
677  }
678 
679  /* Check if it has %SystemRoot% (len=13) */
680  if (ServiceNameLen > 13 &&
681  !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
682  {
683  /* Substitute %SystemRoot% with \\SystemRoot\\ */
684  *lpCanonName = HeapAlloc(GetProcessHeap(),
686  (ServiceNameLen + 1) * sizeof(WCHAR));
687 
688  if (*lpCanonName == NULL)
689  {
690  DPRINT("Error allocating memory for canonized service name!\n");
692  }
693 
694  /* If it's a boot-time driver, it must be systemroot relative */
695  if (dwStartType == SERVICE_BOOT_START)
696  wcscpy(*lpCanonName, L"\\SystemRoot\\");
697 
698  wcscat(*lpCanonName, lpServiceName + 13);
699 
700  DPRINT("Canonicalized name %S\n", *lpCanonName);
701  return NO_ERROR;
702  }
703 
704  /* Check if it's a relative path name */
705  if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
706  {
707  *lpCanonName = HeapAlloc(GetProcessHeap(),
709  (ServiceNameLen + 1) * sizeof(WCHAR));
710 
711  if (*lpCanonName == NULL)
712  {
713  DPRINT("Error allocating memory for canonized service name!\n");
715  }
716 
717  /* Just copy it over without changing */
718  wcscpy(*lpCanonName, lpServiceName);
719 
720  return NO_ERROR;
721  }
722 
723  /* It seems to be a DOS path, convert it */
724  if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
725  {
726  DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
728  }
729 
730  *lpCanonName = HeapAlloc(GetProcessHeap(),
732  NtServiceName.Length + sizeof(WCHAR));
733 
734  if (*lpCanonName == NULL)
735  {
736  DPRINT("Error allocating memory for canonized service name!\n");
737  RtlFreeUnicodeString(&NtServiceName);
739  }
740 
741  /* Copy the string */
742  wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
743 
744  /* The unicode string is not needed anymore */
745  RtlFreeUnicodeString(&NtServiceName);
746 
747  if (dwStartType != SERVICE_BOOT_START)
748  {
749  DPRINT("Canonicalized name %S\n", *lpCanonName);
750  return NO_ERROR;
751  }
752 
753  /* The service is boot-started, so must be relative */
754  Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
755  if (Result)
756  {
757  /* There is a problem, free name and return */
758  HeapFree(GetProcessHeap(), 0, *lpCanonName);
759  DPRINT("Error converting named!\n");
760  return Result;
761  }
762 
763  ASSERT(RelativeName);
764 
765  /* Copy that string */
766  wcscpy(*lpCanonName, RelativeName + 12);
767 
768  /* Free the allocated buffer */
769  HeapFree(GetProcessHeap(), 0, RelativeName);
770 
771  DPRINT("Canonicalized name %S\n", *lpCanonName);
772 
773  /* Success */
774  return NO_ERROR;
775 }
776 
777 
778 /* Internal recursive function */
779 /* Need to search for every dependency on every service */
780 static DWORD
782  PSERVICE lpService,
783  DWORD dwServiceState,
784  PSERVICE *lpServices,
786  LPDWORD lpServicesReturned)
787 {
788  DWORD dwError = ERROR_SUCCESS;
789  WCHAR szNameBuf[MAX_PATH];
790  WCHAR szValueBuf[MAX_PATH];
791  WCHAR *lpszNameBuf = szNameBuf;
792  WCHAR *lpszValueBuf = szValueBuf;
793  DWORD dwSize;
794  DWORD dwNumSubKeys;
795  DWORD dwIteration;
796  PSERVICE lpCurrentService;
797  HKEY hServiceEnumKey;
798  DWORD dwCurrentServiceState = SERVICE_ACTIVE;
799  DWORD dwDependServiceStrPtr = 0;
800  DWORD dwRequiredSize = 0;
801 
802  /* Get the number of service keys */
803  dwError = RegQueryInfoKeyW(hServicesKey,
804  NULL,
805  NULL,
806  NULL,
807  &dwNumSubKeys,
808  NULL,
809  NULL,
810  NULL,
811  NULL,
812  NULL,
813  NULL,
814  NULL);
815  if (dwError != ERROR_SUCCESS)
816  {
817  DPRINT("ERROR! Unable to get number of services keys.\n");
818  return dwError;
819  }
820 
821  /* Iterate the service keys to see if another service depends on the this service */
822  for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
823  {
824  dwSize = MAX_PATH;
825  dwError = RegEnumKeyExW(hServicesKey,
826  dwIteration,
827  lpszNameBuf,
828  &dwSize,
829  NULL,
830  NULL,
831  NULL,
832  NULL);
833  if (dwError != ERROR_SUCCESS)
834  return dwError;
835 
836  /* Open the Service key */
837  dwError = RegOpenKeyExW(hServicesKey,
838  lpszNameBuf,
839  0,
840  KEY_READ,
841  &hServiceEnumKey);
842  if (dwError != ERROR_SUCCESS)
843  return dwError;
844 
845  dwSize = MAX_PATH * sizeof(WCHAR);
846 
847  /* Check for the DependOnService Value */
848  dwError = RegQueryValueExW(hServiceEnumKey,
849  L"DependOnService",
850  NULL,
851  NULL,
852  (LPBYTE)lpszValueBuf,
853  &dwSize);
854 
855  /* FIXME: Handle load order. */
856 
857  /* If the service found has a DependOnService value */
858  if (dwError == ERROR_SUCCESS)
859  {
860  dwDependServiceStrPtr = 0;
861 
862  /* Can be more than one Dependencies in the DependOnService string */
863  while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
864  {
865  if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
866  {
867  /* Get the current enumed service pointer */
868  lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
869 
870  /* Check for valid Service */
871  if (!lpCurrentService)
872  {
873  /* This should never happen! */
874  DPRINT("This should not happen at this point, report to Developer\n");
875  return ERROR_NOT_FOUND;
876  }
877 
878  /* Determine state the service is in */
879  if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
880  dwCurrentServiceState = SERVICE_INACTIVE;
881 
882  /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
883  if ((dwCurrentServiceState == dwServiceState) ||
884  (dwServiceState == SERVICE_STATE_ALL))
885  {
886  /* Calculate the required size */
887  dwRequiredSize += sizeof(SERVICE_STATUS);
888  dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
889  dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
890 
891  /* Add the size for service name and display name pointers */
892  dwRequiredSize += (2 * sizeof(PVOID));
893 
894  /* increase the BytesNeeded size */
895  *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
896 
897  /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
898  comes first */
899 
900  /* Recursive call to check for its dependencies */
902  lpCurrentService,
903  dwServiceState,
904  lpServices,
906  lpServicesReturned);
907 
908  /* If the lpServices is valid set the service pointer */
909  if (lpServices)
910  lpServices[*lpServicesReturned] = lpCurrentService;
911 
912  *lpServicesReturned = *lpServicesReturned + 1;
913  }
914  }
915 
916  dwDependServiceStrPtr += (DWORD)(wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
917  }
918  }
919  else if (*pcbBytesNeeded)
920  {
921  dwError = ERROR_SUCCESS;
922  }
923 
924  RegCloseKey(hServiceEnumKey);
925  }
926 
927  return dwError;
928 }
929 
930 
931 /* Function 0 */
932 DWORD
933 WINAPI
935  LPSC_RPC_HANDLE hSCObject)
936 {
937  PMANAGER_HANDLE hManager;
938  PSERVICE_HANDLE hService;
939  PSERVICE lpService;
941  DWORD dwError;
942  DWORD pcbBytesNeeded = 0;
943  DWORD dwServicesReturned = 0;
944 
945  DPRINT("RCloseServiceHandle() called\n");
946 
947  DPRINT("hSCObject = %p\n", *hSCObject);
948 
949  if (*hSCObject == 0)
950  return ERROR_INVALID_HANDLE;
951 
952  hManager = ScmGetServiceManagerFromHandle(*hSCObject);
953  hService = ScmGetServiceFromHandle(*hSCObject);
954 
955  if (hManager != NULL)
956  {
957  DPRINT("Found manager handle\n");
958 
959  /* Make sure we don't access stale memory if someone tries to use this handle again. */
960  hManager->Handle.Tag = INVALID_TAG;
961 
962  HeapFree(GetProcessHeap(), 0, hManager);
963  hManager = NULL;
964 
965  *hSCObject = NULL;
966 
967  DPRINT("RCloseServiceHandle() done\n");
968  return ERROR_SUCCESS;
969  }
970  else if (hService != NULL)
971  {
972  DPRINT("Found service handle\n");
973 
974  /* Lock the service database exclusively */
976 
977  /* Get the pointer to the service record */
978  lpService = hService->ServiceEntry;
979 
980  /* Make sure we don't access stale memory if someone tries to use this handle again. */
981  hService->Handle.Tag = INVALID_TAG;
982 
983  /* Free the handle */
984  HeapFree(GetProcessHeap(), 0, hService);
985  hService = NULL;
986 
987  ASSERT(lpService->dwRefCount > 0);
988 
989  lpService->dwRefCount--;
990  DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
991  lpService->dwRefCount);
992 
993  if (lpService->dwRefCount == 0)
994  {
995  /* If this service has been marked for deletion */
996  if (lpService->bDeleted &&
997  lpService->Status.dwCurrentState == SERVICE_STOPPED)
998  {
999  /* Open the Services Reg key */
1001  L"System\\CurrentControlSet\\Services",
1002  0,
1004  &hServicesKey);
1005  if (dwError != ERROR_SUCCESS)
1006  {
1007  DPRINT("Failed to open services key\n");
1009  return dwError;
1010  }
1011 
1012  /* Call the internal function with NULL, just to get bytes we need */
1014  lpService,
1016  NULL,
1017  &pcbBytesNeeded,
1018  &dwServicesReturned);
1019 
1020  /* If pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1021  if (pcbBytesNeeded)
1022  {
1023  DPRINT("Deletion failed due to running dependencies.\n");
1026  return ERROR_SUCCESS;
1027  }
1028 
1029  /* There are no references and no running dependencies,
1030  it is now safe to delete the service */
1031 
1032  /* Delete the Service Key */
1033  dwError = ScmDeleteRegKey(hServicesKey,
1034  lpService->lpServiceName);
1035 
1037 
1038  if (dwError != ERROR_SUCCESS)
1039  {
1040  DPRINT("Failed to Delete the Service Registry key\n");
1042  return dwError;
1043  }
1044 
1045  /* Delete the Service */
1046  ScmDeleteServiceRecord(lpService);
1047  }
1048  }
1049 
1051 
1052  *hSCObject = NULL;
1053 
1054  DPRINT("RCloseServiceHandle() done\n");
1055  return ERROR_SUCCESS;
1056  }
1057 
1058  DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
1059 
1060  return ERROR_INVALID_HANDLE;
1061 }
1062 
1063 
1064 /* Function 1 */
1065 DWORD
1066 WINAPI
1068  SC_RPC_HANDLE hService,
1069  DWORD dwControl,
1070  LPSERVICE_STATUS lpServiceStatus)
1071 {
1072  PSERVICE_HANDLE hSvc;
1073  PSERVICE lpService;
1075  DWORD dwError = ERROR_SUCCESS;
1076  DWORD pcbBytesNeeded = 0;
1077  DWORD dwServicesReturned = 0;
1078  DWORD dwControlsAccepted;
1079  DWORD dwCurrentState;
1081  LPCWSTR lpLogStrings[2];
1082  WCHAR szLogBuffer[80];
1083  UINT uID;
1084 
1085  DPRINT("RControlService() called\n");
1086 
1087  if (ScmShutdown)
1089 
1090  /* Check the service handle */
1091  hSvc = ScmGetServiceFromHandle(hService);
1092  if (hSvc == NULL)
1093  {
1094  DPRINT1("Invalid service handle!\n");
1095  return ERROR_INVALID_HANDLE;
1096  }
1097 
1098  /* Check the service entry point */
1099  lpService = hSvc->ServiceEntry;
1100  if (lpService == NULL)
1101  {
1102  DPRINT1("lpService == NULL!\n");
1103  return ERROR_INVALID_HANDLE;
1104  }
1105 
1106  /* Check access rights */
1107  switch (dwControl)
1108  {
1109  case SERVICE_CONTROL_STOP:
1111  break;
1112 
1113  case SERVICE_CONTROL_PAUSE:
1121  break;
1122 
1125  break;
1126 
1127  default:
1128  if (dwControl >= 128 && dwControl <= 255)
1130  else
1131  return ERROR_INVALID_PARAMETER;
1132  break;
1133  }
1134 
1136  DesiredAccess))
1137  return ERROR_ACCESS_DENIED;
1138 
1139  /* Return the current service status information */
1140  RtlCopyMemory(lpServiceStatus,
1141  &lpService->Status,
1142  sizeof(SERVICE_STATUS));
1143 
1144  if (dwControl == SERVICE_CONTROL_STOP)
1145  {
1146  /* Check if the service has dependencies running as windows
1147  doesn't stop a service that does */
1148 
1149  /* Open the Services Reg key */
1151  L"System\\CurrentControlSet\\Services",
1152  0,
1153  KEY_READ,
1154  &hServicesKey);
1155  if (dwError != ERROR_SUCCESS)
1156  {
1157  DPRINT("Failed to open services key\n");
1158  return dwError;
1159  }
1160 
1161  /* Call the internal function with NULL, just to get bytes we need */
1163  lpService,
1165  NULL,
1166  &pcbBytesNeeded,
1167  &dwServicesReturned);
1168 
1170 
1171  /* If pcbBytesNeeded is not zero then there are services running that
1172  are dependent on this service */
1173  if (pcbBytesNeeded != 0)
1174  {
1175  DPRINT("Service has running dependencies. Failed to stop service.\n");
1177  }
1178  }
1179 
1180  if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1181  {
1182  /* Send control code to the driver */
1183  dwError = ScmControlDriver(lpService,
1184  dwControl,
1185  lpServiceStatus);
1186  }
1187  else
1188  {
1189  dwControlsAccepted = lpService->Status.dwControlsAccepted;
1190  dwCurrentState = lpService->Status.dwCurrentState;
1191 
1192  /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1193  if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1194  return ERROR_SERVICE_NOT_ACTIVE;
1195 
1196  /* Check the current state before sending a control request */
1197  switch (dwCurrentState)
1198  {
1199  case SERVICE_STOP_PENDING:
1200  case SERVICE_STOPPED:
1202 
1203  case SERVICE_START_PENDING:
1204  switch (dwControl)
1205  {
1206  case SERVICE_CONTROL_STOP:
1207  break;
1208 
1210  RtlCopyMemory(lpServiceStatus,
1211  &lpService->Status,
1212  sizeof(SERVICE_STATUS));
1213  return ERROR_SUCCESS;
1214 
1215  default:
1217  }
1218  break;
1219  }
1220 
1221  /* Check if the control code is acceptable to the service */
1222  switch (dwControl)
1223  {
1224  case SERVICE_CONTROL_STOP:
1225  if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1227  break;
1228 
1229  case SERVICE_CONTROL_PAUSE:
1231  if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1233  break;
1234 
1236  if ((dwControlsAccepted & SERVICE_ACCEPT_PARAMCHANGE) == 0)
1238  break;
1239 
1244  if ((dwControlsAccepted & SERVICE_ACCEPT_NETBINDCHANGE) == 0)
1246  break;
1247  }
1248 
1249  /* Send control code to the service */
1250  dwError = ScmControlService(lpService->lpImage->hControlPipe,
1251  lpService->lpServiceName,
1252  (SERVICE_STATUS_HANDLE)lpService,
1253  dwControl);
1254 
1255  /* Return service status information */
1256  RtlCopyMemory(lpServiceStatus,
1257  &lpService->Status,
1258  sizeof(SERVICE_STATUS));
1259  }
1260 
1261  if (dwError == ERROR_SUCCESS)
1262  {
1263  if (dwControl == SERVICE_CONTROL_STOP ||
1264  dwControl == SERVICE_CONTROL_PAUSE ||
1265  dwControl == SERVICE_CONTROL_CONTINUE)
1266  {
1267  /* Log a successful send control */
1268 
1269  switch (dwControl)
1270  {
1271  case SERVICE_CONTROL_STOP:
1272  uID = IDS_SERVICE_STOP;
1273  break;
1274 
1275  case SERVICE_CONTROL_PAUSE:
1276  uID = IDS_SERVICE_PAUSE;
1277  break;
1278 
1280  uID = IDS_SERVICE_RESUME;
1281  break;
1282  }
1283  LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1284 
1285  lpLogStrings[0] = lpService->lpDisplayName;
1286  lpLogStrings[1] = szLogBuffer;
1287 
1290  2,
1291  lpLogStrings);
1292  }
1293  }
1294 
1295  return dwError;
1296 }
1297 
1298 
1299 /* Function 2 */
1300 DWORD
1301 WINAPI
1303  SC_RPC_HANDLE hService)
1304 {
1305  PSERVICE_HANDLE hSvc;
1306  PSERVICE lpService;
1307  DWORD dwError;
1308 
1309  DPRINT("RDeleteService() called\n");
1310 
1311  if (ScmShutdown)
1313 
1314  hSvc = ScmGetServiceFromHandle(hService);
1315  if (hSvc == NULL)
1316  {
1317  DPRINT1("Invalid service handle!\n");
1318  return ERROR_INVALID_HANDLE;
1319  }
1320 
1322  DELETE))
1323  return ERROR_ACCESS_DENIED;
1324 
1325  lpService = hSvc->ServiceEntry;
1326  if (lpService == NULL)
1327  {
1328  DPRINT("lpService == NULL!\n");
1329  return ERROR_INVALID_HANDLE;
1330  }
1331 
1332  /* Lock the service database exclusively */
1334 
1335  if (lpService->bDeleted)
1336  {
1337  DPRINT("The service has already been marked for delete!\n");
1339  goto Done;
1340  }
1341 
1342  /* Mark service for delete */
1343  lpService->bDeleted = TRUE;
1344 
1345  dwError = ScmMarkServiceForDelete(lpService);
1346 
1347 Done:
1348  /* Unlock the service database */
1350 
1351  DPRINT("RDeleteService() done\n");
1352 
1353  return dwError;
1354 }
1355 
1356 
1357 /* Function 3 */
1358 DWORD
1359 WINAPI
1362  LPSC_RPC_LOCK lpLock)
1363 {
1364  PMANAGER_HANDLE hMgr;
1365 
1366  DPRINT("RLockServiceDatabase() called\n");
1367 
1368  *lpLock = NULL;
1369 
1371  if (hMgr == NULL)
1372  {
1373  DPRINT1("Invalid service manager handle!\n");
1374  return ERROR_INVALID_HANDLE;
1375  }
1376 
1378  SC_MANAGER_LOCK))
1379  return ERROR_ACCESS_DENIED;
1380 
1381  return ScmAcquireServiceStartLock(FALSE, lpLock);
1382 }
1383 
1384 
1385 /* Function 4 */
1386 DWORD
1387 WINAPI
1389  SC_RPC_HANDLE hService,
1390  SECURITY_INFORMATION dwSecurityInformation,
1391  LPBYTE lpSecurityDescriptor,
1392  DWORD cbBufSize,
1394 {
1395  PSERVICE_HANDLE hSvc;
1396  PSERVICE lpService;
1397  ULONG DesiredAccess = 0;
1398  NTSTATUS Status;
1399  DWORD dwBytesNeeded;
1400  DWORD dwError;
1401 
1402  DPRINT("RQueryServiceObjectSecurity() called\n");
1403 
1404  hSvc = ScmGetServiceFromHandle(hService);
1405  if (hSvc == NULL)
1406  {
1407  DPRINT1("Invalid service handle!\n");
1408  return ERROR_INVALID_HANDLE;
1409  }
1410 
1411  if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1415 
1416  if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1418 
1420  DesiredAccess))
1421  {
1422  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1423  return ERROR_ACCESS_DENIED;
1424  }
1425 
1426  lpService = hSvc->ServiceEntry;
1427  if (lpService == NULL)
1428  {
1429  DPRINT("lpService == NULL!\n");
1430  return ERROR_INVALID_HANDLE;
1431  }
1432 
1433  /* Lock the service database */
1435 
1436  /* Retrieve the security descriptor */
1438  dwSecurityInformation,
1439  (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1440  cbBufSize,
1441  &dwBytesNeeded);
1442 
1443  /* Unlock the service database */
1445 
1446  if (NT_SUCCESS(Status))
1447  {
1448  *pcbBytesNeeded = dwBytesNeeded;
1449  dwError = STATUS_SUCCESS;
1450  }
1451  else if (Status == STATUS_BUFFER_TOO_SMALL)
1452  {
1453  *pcbBytesNeeded = dwBytesNeeded;
1454  dwError = ERROR_INSUFFICIENT_BUFFER;
1455  }
1457  {
1458  dwError = ERROR_GEN_FAILURE;
1459  }
1460  else
1461  {
1462  dwError = RtlNtStatusToDosError(Status);
1463  }
1464 
1465  return dwError;
1466 }
1467 
1468 
1469 /* Function 5 */
1470 DWORD
1471 WINAPI
1473  SC_RPC_HANDLE hService,
1474  DWORD dwSecurityInformation,
1475  LPBYTE lpSecurityDescriptor,
1476  DWORD dwSecurityDescriptorSize)
1477 {
1478  PSERVICE_HANDLE hSvc;
1479  PSERVICE lpService;
1481  HANDLE hToken = NULL;
1482  HKEY hServiceKey = NULL;
1483  BOOL bDatabaseLocked = FALSE;
1484  NTSTATUS Status;
1485  DWORD dwError;
1486 
1487  DPRINT("RSetServiceObjectSecurity() called\n");
1488 
1489  hSvc = ScmGetServiceFromHandle(hService);
1490  if (hSvc == NULL)
1491  {
1492  DPRINT1("Invalid service handle!\n");
1493  return ERROR_INVALID_HANDLE;
1494  }
1495 
1496  if (dwSecurityInformation == 0 ||
1497  dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1499  {
1500  return ERROR_INVALID_PARAMETER;
1501  }
1502 
1503  if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1504  return ERROR_INVALID_PARAMETER;
1505 
1506  if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1508 
1509  if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1511 
1512  if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1514 
1515  if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1516  (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1517  {
1518  return ERROR_INVALID_PARAMETER;
1519  }
1520 
1521  if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1522  (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1523  {
1524  return ERROR_INVALID_PARAMETER;
1525  }
1526 
1528  DesiredAccess))
1529  {
1530  DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1531  return ERROR_ACCESS_DENIED;
1532  }
1533 
1534  lpService = hSvc->ServiceEntry;
1535  if (lpService == NULL)
1536  {
1537  DPRINT1("lpService == NULL!\n");
1538  return ERROR_INVALID_HANDLE;
1539  }
1540 
1541  if (lpService->bDeleted)
1543 
1544 #if 0
1546 
1548  8,
1549  TRUE,
1550  &hToken);
1551  if (!NT_SUCCESS(Status))
1552  return RtlNtStatusToDosError(Status);
1553 
1554  RpcRevertToSelf();
1555 #endif
1556 
1557  /* Build the new security descriptor */
1558  Status = RtlSetSecurityObject(dwSecurityInformation,
1559  (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1560  &lpService->pSecurityDescriptor,
1562  hToken);
1563  if (!NT_SUCCESS(Status))
1564  {
1565  dwError = RtlNtStatusToDosError(Status);
1566  goto Done;
1567  }
1568 
1569  /* Lock the service database exclusive */
1571  bDatabaseLocked = TRUE;
1572 
1573  /* Open the service key */
1574  dwError = ScmOpenServiceKey(lpService->lpServiceName,
1576  &hServiceKey);
1577  if (dwError != ERROR_SUCCESS)
1578  goto Done;
1579 
1580  /* Store the new security descriptor */
1581  dwError = ScmWriteSecurityDescriptor(hServiceKey,
1582  lpService->pSecurityDescriptor);
1583 
1584  RegFlushKey(hServiceKey);
1585 
1586 Done:
1587  if (hServiceKey != NULL)
1588  RegCloseKey(hServiceKey);
1589 
1590  /* Unlock service database */
1591  if (bDatabaseLocked == TRUE)
1593 
1594  if (hToken != NULL)
1595  NtClose(hToken);
1596 
1597  DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1598 
1599  return dwError;
1600 }
1601 
1602 
1603 /* Function 6 */
1604 DWORD
1605 WINAPI
1607  SC_RPC_HANDLE hService,
1608  LPSERVICE_STATUS lpServiceStatus)
1609 {
1610  PSERVICE_HANDLE hSvc;
1611  PSERVICE lpService;
1612 
1613  DPRINT("RQueryServiceStatus() called\n");
1614 
1615  if (ScmShutdown)
1617 
1618  hSvc = ScmGetServiceFromHandle(hService);
1619  if (hSvc == NULL)
1620  {
1621  DPRINT1("Invalid service handle!\n");
1622  return ERROR_INVALID_HANDLE;
1623  }
1624 
1627  {
1628  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1629  return ERROR_ACCESS_DENIED;
1630  }
1631 
1632  lpService = hSvc->ServiceEntry;
1633  if (lpService == NULL)
1634  {
1635  DPRINT("lpService == NULL!\n");
1636  return ERROR_INVALID_HANDLE;
1637  }
1638 
1639  /* Lock the service database shared */
1641 
1642  /* Return service status information */
1643  RtlCopyMemory(lpServiceStatus,
1644  &lpService->Status,
1645  sizeof(SERVICE_STATUS));
1646 
1647  /* Unlock the service database */
1649 
1650  return ERROR_SUCCESS;
1651 }
1652 
1653 
1654 static BOOL
1656 {
1657  switch (dwCurrentState)
1658  {
1659  case SERVICE_STOPPED:
1660  case SERVICE_START_PENDING:
1661  case SERVICE_STOP_PENDING:
1662  case SERVICE_RUNNING:
1664  case SERVICE_PAUSE_PENDING:
1665  case SERVICE_PAUSED:
1666  return TRUE;
1667 
1668  default:
1669  return FALSE;
1670  }
1671 }
1672 
1673 
1674 /* Function 7 */
1675 DWORD
1676 WINAPI
1679  LPSERVICE_STATUS lpServiceStatus)
1680 {
1681  PSERVICE lpService;
1682  DWORD dwPreviousState;
1683  DWORD dwPreviousType;
1684  LPCWSTR lpLogStrings[2];
1685  WCHAR szLogBuffer[80];
1686  UINT uID;
1687 
1688  DPRINT("RSetServiceStatus() called\n");
1689  DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1690  DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1691  DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1692  DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1693  DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1694  DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1695  DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1696  DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1697 
1698  if (hServiceStatus == 0)
1699  {
1700  DPRINT("hServiceStatus == NULL!\n");
1701  return ERROR_INVALID_HANDLE;
1702  }
1703 
1704  lpService = (PSERVICE)hServiceStatus;
1705 
1706  /* Check current state */
1707  if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1708  {
1709  DPRINT("Invalid service state!\n");
1710  return ERROR_INVALID_DATA;
1711  }
1712 
1713  /* Check service type */
1714  if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1715  (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1716  {
1717  DPRINT("Invalid service type!\n");
1718  return ERROR_INVALID_DATA;
1719  }
1720 
1721  /* Check accepted controls */
1722  if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1723  {
1724  DPRINT("Invalid controls accepted!\n");
1725  return ERROR_INVALID_DATA;
1726  }
1727 
1728  /* Set the wait hint and check point only if the service is in a pending state,
1729  otherwise they should be 0 */
1730  if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1731  lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1732  lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1733  {
1734  lpServiceStatus->dwWaitHint = 0;
1735  lpServiceStatus->dwCheckPoint = 0;
1736  }
1737 
1738  /* Lock the service database exclusively */
1740 
1741  /* Save the current service state */
1742  dwPreviousState = lpService->Status.dwCurrentState;
1743 
1744  /* Save the current service type */
1745  dwPreviousType = lpService->Status.dwServiceType;
1746 
1747  /* Update the service status */
1748  RtlCopyMemory(&lpService->Status,
1749  lpServiceStatus,
1750  sizeof(SERVICE_STATUS));
1751 
1752  /* Restore the previous service type */
1753  lpService->Status.dwServiceType = dwPreviousType;
1754 
1755  /* Dereference a stopped service */
1756  if ((lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1757  (lpServiceStatus->dwCurrentState == SERVICE_STOPPED))
1758  {
1759  /* Decrement the image run counter */
1760  lpService->lpImage->dwImageRunCount--;
1761 
1762  /* If we just stopped the last running service... */
1763  if (lpService->lpImage->dwImageRunCount == 0)
1764  {
1765  /* Stop the dispatcher thread */
1767  L"",
1768  (SERVICE_STATUS_HANDLE)lpService,
1770 
1771  /* Remove the service image */
1772  ScmRemoveServiceImage(lpService->lpImage);
1773  lpService->lpImage = NULL;
1774  }
1775  }
1776 
1777  /* Unlock the service database */
1779 
1780  if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1781  (dwPreviousState != SERVICE_STOPPED) &&
1782  (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
1783  {
1784  /* Log a failed service stop */
1785  StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
1786  L"%lu", lpServiceStatus->dwWin32ExitCode);
1787  lpLogStrings[0] = lpService->lpDisplayName;
1788  lpLogStrings[1] = szLogBuffer;
1789 
1792  2,
1793  lpLogStrings);
1794  }
1795  else if (lpServiceStatus->dwCurrentState != dwPreviousState &&
1796  (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1797  lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
1798  lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
1799  {
1800  /* Log a successful service status change */
1801  switch(lpServiceStatus->dwCurrentState)
1802  {
1803  case SERVICE_STOPPED:
1804  uID = IDS_SERVICE_STOPPED;
1805  break;
1806 
1807  case SERVICE_RUNNING:
1808  uID = IDS_SERVICE_RUNNING;
1809  break;
1810 
1811  case SERVICE_PAUSED:
1812  uID = IDS_SERVICE_PAUSED;
1813  break;
1814  }
1815 
1816  LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1817  lpLogStrings[0] = lpService->lpDisplayName;
1818  lpLogStrings[1] = szLogBuffer;
1819 
1822  2,
1823  lpLogStrings);
1824  }
1825 
1826  DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1827  DPRINT("RSetServiceStatus() done\n");
1828 
1829  return ERROR_SUCCESS;
1830 }
1831 
1832 
1833 /* Function 8 */
1834 DWORD
1835 WINAPI
1838 {
1839  DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1841 }
1842 
1843 
1844 /* Function 9 */
1845 DWORD
1846 WINAPI
1848  SVCCTL_HANDLEW lpMachineName,
1849  DWORD BootAcceptable)
1850 {
1851  DPRINT("RNotifyBootConfigStatus(%p %lu)\n",
1852  lpMachineName, BootAcceptable);
1853 
1854  if (BootAcceptable)
1855  return ScmAcceptBoot();
1856 
1857  return ScmRunLastKnownGood();
1858 }
1859 
1860 
1861 /* Function 10 */
1862 DWORD
1863 WINAPI
1867  int bSetBitsOn,
1868  int bUpdateImmediately,
1869  wchar_t *lpString)
1870 {
1871  PSERVICE pService;
1872 
1873  DPRINT("RI_ScSetServiceBitsW(%p %lx %d %d %S)\n",
1874  hServiceStatus, dwServiceBits, bSetBitsOn,
1875  bUpdateImmediately, lpString);
1876 
1877  if (ScmShutdown)
1879 
1880  if (lpString != NULL)
1881  return ERROR_INVALID_PARAMETER;
1882 
1883  if (hServiceStatus == 0)
1884  {
1885  DPRINT("hServiceStatus == NULL!\n");
1886  return ERROR_INVALID_HANDLE;
1887  }
1888 
1889  // FIXME: Validate the status handle
1890  pService = (PSERVICE)hServiceStatus;
1891 
1892  if (bSetBitsOn)
1893  {
1894  DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1895  DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1896  pService->dwServiceBits |= dwServiceBits;
1898  DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1899  DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1900  }
1901  else
1902  {
1903  DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1904  DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1905  pService->dwServiceBits &= ~dwServiceBits;
1907  DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1908  DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1909  }
1910 
1911  return ERROR_SUCCESS;
1912 }
1913 
1914 
1915 /* Function 11 */
1916 DWORD
1917 WINAPI
1919  SC_RPC_HANDLE hService,
1920  DWORD dwServiceType,
1921  DWORD dwStartType,
1922  DWORD dwErrorControl,
1923  LPWSTR lpBinaryPathName,
1924  LPWSTR lpLoadOrderGroup,
1925  LPDWORD lpdwTagId,
1926  LPBYTE lpDependencies,
1927  DWORD dwDependSize,
1928  LPWSTR lpServiceStartName,
1929  LPBYTE lpPassword,
1930  DWORD dwPwSize,
1932 {
1933  DWORD dwError = ERROR_SUCCESS;
1934  PSERVICE_HANDLE hSvc;
1935  PSERVICE lpService = NULL;
1936  HKEY hServiceKey = NULL;
1937  LPWSTR lpDisplayNameW = NULL;
1938  LPWSTR lpImagePathW = NULL;
1939  LPWSTR lpClearTextPassword = NULL;
1940 
1941  DPRINT("RChangeServiceConfigW() called\n");
1942  DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1943  DPRINT("dwStartType = %lu\n", dwStartType);
1944  DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1945  DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1946  DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1947  DPRINT("lpServiceStartName = %S\n", lpServiceStartName);
1948  DPRINT("lpPassword = %p\n", lpPassword);
1949  DPRINT("dwPwSite = %lu\n", dwPwSize);
1950  DPRINT("lpDisplayName = %S\n", lpDisplayName);
1951 
1952  if (ScmShutdown)
1954 
1955  hSvc = ScmGetServiceFromHandle(hService);
1956  if (hSvc == NULL)
1957  {
1958  DPRINT1("Invalid service handle!\n");
1959  return ERROR_INVALID_HANDLE;
1960  }
1961 
1964  {
1965  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1966  return ERROR_ACCESS_DENIED;
1967  }
1968 
1969  /* Check for invalid service type value */
1970  if ((dwServiceType != SERVICE_NO_CHANGE) &&
1971  (dwServiceType != SERVICE_KERNEL_DRIVER) &&
1972  (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
1973  ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
1975  {
1976  return ERROR_INVALID_PARAMETER;
1977  }
1978 
1979  /* Check for invalid start type value */
1980  if ((dwStartType != SERVICE_NO_CHANGE) &&
1981  (dwStartType != SERVICE_BOOT_START) &&
1982  (dwStartType != SERVICE_SYSTEM_START) &&
1983  (dwStartType != SERVICE_AUTO_START) &&
1984  (dwStartType != SERVICE_DEMAND_START) &&
1985  (dwStartType != SERVICE_DISABLED))
1986  {
1987  return ERROR_INVALID_PARAMETER;
1988  }
1989 
1990  /* Only drivers can be boot start or system start services */
1991  if ((dwStartType == SERVICE_BOOT_START) ||
1992  (dwStartType == SERVICE_SYSTEM_START))
1993  {
1994  if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
1995  (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
1996  return ERROR_INVALID_PARAMETER;
1997  }
1998 
1999  /* Check for invalid error control value */
2000  if ((dwErrorControl != SERVICE_NO_CHANGE) &&
2001  (dwErrorControl != SERVICE_ERROR_IGNORE) &&
2002  (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2003  (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2004  (dwErrorControl != SERVICE_ERROR_CRITICAL))
2005  {
2006  return ERROR_INVALID_PARAMETER;
2007  }
2008 
2009  if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2010  {
2011  return ERROR_INVALID_PARAMETER;
2012  }
2013 
2014  lpService = hSvc->ServiceEntry;
2015  if (lpService == NULL)
2016  {
2017  DPRINT("lpService == NULL!\n");
2018  return ERROR_INVALID_HANDLE;
2019  }
2020 
2021  /* Lock the service database exclusively */
2023 
2024  if (lpService->bDeleted)
2025  {
2026  DPRINT("The service has already been marked for delete!\n");
2028  goto done;
2029  }
2030 
2031  /* Open the service key */
2032  dwError = ScmOpenServiceKey(lpService->szServiceName,
2033  KEY_SET_VALUE,
2034  &hServiceKey);
2035  if (dwError != ERROR_SUCCESS)
2036  goto done;
2037 
2038  /* Write service data to the registry */
2039 
2040  /* Set the display name */
2041  if (lpDisplayName != NULL && *lpDisplayName != 0)
2042  {
2043  RegSetValueExW(hServiceKey,
2044  L"DisplayName",
2045  0,
2046  REG_SZ,
2048  (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2049 
2050  /* Update the display name */
2051  lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2053  (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2054  if (lpDisplayNameW == NULL)
2055  {
2056  dwError = ERROR_NOT_ENOUGH_MEMORY;
2057  goto done;
2058  }
2059 
2060  wcscpy(lpDisplayNameW, lpDisplayName);
2061  if (lpService->lpDisplayName != lpService->lpServiceName)
2062  HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2063 
2064  lpService->lpDisplayName = lpDisplayNameW;
2065  }
2066 
2067  if (dwServiceType != SERVICE_NO_CHANGE)
2068  {
2069  /* Set the service type */
2070  dwError = RegSetValueExW(hServiceKey,
2071  L"Type",
2072  0,
2073  REG_DWORD,
2074  (LPBYTE)&dwServiceType,
2075  sizeof(DWORD));
2076  if (dwError != ERROR_SUCCESS)
2077  goto done;
2078 
2079  lpService->Status.dwServiceType = dwServiceType;
2080  }
2081 
2082  if (dwStartType != SERVICE_NO_CHANGE)
2083  {
2084  /* Set the start value */
2085  dwError = RegSetValueExW(hServiceKey,
2086  L"Start",
2087  0,
2088  REG_DWORD,
2089  (LPBYTE)&dwStartType,
2090  sizeof(DWORD));
2091  if (dwError != ERROR_SUCCESS)
2092  goto done;
2093 
2094  lpService->dwStartType = dwStartType;
2095  }
2096 
2097  if (dwErrorControl != SERVICE_NO_CHANGE)
2098  {
2099  /* Set the error control value */
2100  dwError = RegSetValueExW(hServiceKey,
2101  L"ErrorControl",
2102  0,
2103  REG_DWORD,
2104  (LPBYTE)&dwErrorControl,
2105  sizeof(DWORD));
2106  if (dwError != ERROR_SUCCESS)
2107  goto done;
2108 
2109  lpService->dwErrorControl = dwErrorControl;
2110  }
2111 
2112  if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2113  {
2114  /* Set the image path */
2115  lpImagePathW = lpBinaryPathName;
2116 
2117  if (lpService->Status.dwServiceType & SERVICE_DRIVER)
2118  {
2119  dwError = ScmCanonDriverImagePath(lpService->dwStartType,
2120  lpBinaryPathName,
2121  &lpImagePathW);
2122 
2123  if (dwError != ERROR_SUCCESS)
2124  goto done;
2125  }
2126 
2127  dwError = RegSetValueExW(hServiceKey,
2128  L"ImagePath",
2129  0,
2130  REG_EXPAND_SZ,
2131  (LPBYTE)lpImagePathW,
2132  (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
2133 
2134  if (lpImagePathW != lpBinaryPathName)
2135  HeapFree(GetProcessHeap(), 0, lpImagePathW);
2136 
2137  if (dwError != ERROR_SUCCESS)
2138  goto done;
2139  }
2140 
2141  /* Set the group name */
2142  if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2143  {
2144  dwError = RegSetValueExW(hServiceKey,
2145  L"Group",
2146  0,
2147  REG_SZ,
2148  (LPBYTE)lpLoadOrderGroup,
2149  (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2150  if (dwError != ERROR_SUCCESS)
2151  goto done;
2152 
2153  dwError = ScmSetServiceGroup(lpService,
2154  lpLoadOrderGroup);
2155  if (dwError != ERROR_SUCCESS)
2156  goto done;
2157  }
2158 
2159  /* Set the tag */
2160  if (lpdwTagId != NULL)
2161  {
2162  dwError = ScmAssignNewTag(lpService);
2163  if (dwError != ERROR_SUCCESS)
2164  goto done;
2165 
2166  dwError = RegSetValueExW(hServiceKey,
2167  L"Tag",
2168  0,
2169  REG_DWORD,
2170  (LPBYTE)&lpService->dwTag,
2171  sizeof(DWORD));
2172  if (dwError != ERROR_SUCCESS)
2173  goto done;
2174 
2175  *lpdwTagId = lpService->dwTag;
2176  }
2177 
2178  /* Write dependencies */
2179  if (lpDependencies != NULL && *lpDependencies != 0)
2180  {
2181  dwError = ScmWriteDependencies(hServiceKey,
2182  (LPWSTR)lpDependencies,
2183  dwDependSize);
2184  if (dwError != ERROR_SUCCESS)
2185  goto done;
2186  }
2187 
2188  /* Start name and password are only used by Win32 services */
2189  if (lpService->Status.dwServiceType & SERVICE_WIN32)
2190  {
2191  /* Write service start name */
2192  if (lpServiceStartName != NULL && *lpServiceStartName != 0)
2193  {
2194  dwError = RegSetValueExW(hServiceKey,
2195  L"ObjectName",
2196  0,
2197  REG_SZ,
2198  (LPBYTE)lpServiceStartName,
2199  (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)));
2200  if (dwError != ERROR_SUCCESS)
2201  goto done;
2202  }
2203 
2204  if (lpPassword != NULL)
2205  {
2206  if (*(LPWSTR)lpPassword != 0)
2207  {
2208  /* Decrypt the password */
2209  dwError = ScmDecryptPassword(lpPassword,
2210  dwPwSize,
2211  &lpClearTextPassword);
2212  if (dwError != ERROR_SUCCESS)
2213  {
2214  DPRINT1("ScmDecryptPassword failed (Error %lu)\n", dwError);
2215  goto done;
2216  }
2217  DPRINT1("Clear text password: %S\n", lpClearTextPassword);
2218 
2219  /* Write the password */
2220  dwError = ScmSetServicePassword(lpService->szServiceName,
2221  lpClearTextPassword);
2222  if (dwError != ERROR_SUCCESS)
2223  {
2224  DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2225  goto done;
2226  }
2227  }
2228  else
2229  {
2230  /* Delete the password */
2231  dwError = ScmSetServicePassword(lpService->szServiceName,
2232  NULL);
2233  if (dwError == ERROR_FILE_NOT_FOUND)
2234  dwError = ERROR_SUCCESS;
2235 
2236  if (dwError != ERROR_SUCCESS)
2237  {
2238  DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2239  goto done;
2240  }
2241  }
2242  }
2243  }
2244 
2245 done:
2246  if (lpClearTextPassword != NULL)
2247  {
2248  /* Wipe and release the password buffer */
2249  SecureZeroMemory(lpClearTextPassword,
2250  (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2251  HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2252  }
2253 
2254  if (hServiceKey != NULL)
2255  RegCloseKey(hServiceKey);
2256 
2257  /* Unlock the service database */
2259 
2260  DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2261 
2262  return dwError;
2263 }
2264 
2265 
2266 /* Function 12 */
2267 DWORD
2268 WINAPI
2271  LPCWSTR lpServiceName,
2273  DWORD dwDesiredAccess,
2274  DWORD dwServiceType,
2275  DWORD dwStartType,
2276  DWORD dwErrorControl,
2277  LPCWSTR lpBinaryPathName,
2278  LPCWSTR lpLoadOrderGroup,
2279  LPDWORD lpdwTagId,
2280  LPBYTE lpDependencies,
2281  DWORD dwDependSize,
2282  LPCWSTR lpServiceStartName,
2283  LPBYTE lpPassword,
2284  DWORD dwPwSize,
2285  LPSC_RPC_HANDLE lpServiceHandle)
2286 {
2287  PMANAGER_HANDLE hManager;
2288  DWORD dwError = ERROR_SUCCESS;
2289  PSERVICE lpService = NULL;
2290  SC_HANDLE hServiceHandle = NULL;
2291  LPWSTR lpImagePath = NULL;
2292  LPWSTR lpClearTextPassword = NULL;
2293  HKEY hServiceKey = NULL;
2294  LPWSTR lpObjectName;
2295 
2296  DPRINT("RCreateServiceW() called\n");
2297  DPRINT("lpServiceName = %S\n", lpServiceName);
2298  DPRINT("lpDisplayName = %S\n", lpDisplayName);
2299  DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2300  DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2301  DPRINT("dwStartType = %lu\n", dwStartType);
2302  DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2303  DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2304  DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2305  DPRINT("lpdwTagId = %p\n", lpdwTagId);
2306 
2307  if (ScmShutdown)
2309 
2311  if (hManager == NULL)
2312  {
2313  DPRINT1("Invalid service manager handle!\n");
2314  return ERROR_INVALID_HANDLE;
2315  }
2316 
2317  /* Check access rights */
2320  {
2321  DPRINT("Insufficient access rights! 0x%lx\n",
2322  hManager->Handle.DesiredAccess);
2323  return ERROR_ACCESS_DENIED;
2324  }
2325 
2326  if (*lpServiceName == 0)
2327  return ERROR_INVALID_NAME;
2328 
2329  if (*lpBinaryPathName == 0)
2330  return ERROR_INVALID_PARAMETER;
2331 
2332  /* Check for invalid service type value */
2333  if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2334  (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2335  ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2337  {
2338  return ERROR_INVALID_PARAMETER;
2339  }
2340 
2341  /* Check for invalid start type value */
2342  if ((dwStartType != SERVICE_BOOT_START) &&
2343  (dwStartType != SERVICE_SYSTEM_START) &&
2344  (dwStartType != SERVICE_AUTO_START) &&
2345  (dwStartType != SERVICE_DEMAND_START) &&
2346  (dwStartType != SERVICE_DISABLED))
2347  {
2348  return ERROR_INVALID_PARAMETER;
2349  }
2350 
2351  /* Only drivers can be boot start or system start services */
2352  if ((dwStartType == SERVICE_BOOT_START) ||
2353  (dwStartType == SERVICE_SYSTEM_START))
2354  {
2355  if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2356  (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2357  {
2358  return ERROR_INVALID_PARAMETER;
2359  }
2360  }
2361 
2362  /* Check for invalid error control value */
2363  if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2364  (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2365  (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2366  (dwErrorControl != SERVICE_ERROR_CRITICAL))
2367  {
2368  return ERROR_INVALID_PARAMETER;
2369  }
2370 
2371  if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2372  (lpServiceStartName))
2373  {
2374  /* We allow LocalSystem to run interactive. */
2375  if (wcsicmp(lpServiceStartName, L"LocalSystem"))
2376  {
2377  return ERROR_INVALID_PARAMETER;
2378  }
2379  }
2380 
2381  if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2382  {
2383  return ERROR_INVALID_PARAMETER;
2384  }
2385 
2386  /* Lock the service database exclusively */
2388 
2389  lpService = ScmGetServiceEntryByName(lpServiceName);
2390  if (lpService)
2391  {
2392  /* Unlock the service database */
2394 
2395  /* Check if it is marked for deletion */
2396  if (lpService->bDeleted)
2398 
2399  /* Return service-exists error */
2400  return ERROR_SERVICE_EXISTS;
2401  }
2402 
2403  if (lpDisplayName != NULL &&
2405  {
2406  /* Unlock the service database */
2408 
2410  }
2411 
2412  if (dwServiceType & SERVICE_DRIVER)
2413  {
2414  dwError = ScmCanonDriverImagePath(dwStartType,
2415  lpBinaryPathName,
2416  &lpImagePath);
2417  if (dwError != ERROR_SUCCESS)
2418  goto done;
2419  }
2420  else
2421  {
2422  if (dwStartType == SERVICE_BOOT_START ||
2423  dwStartType == SERVICE_SYSTEM_START)
2424  {
2425  /* Unlock the service database */
2427 
2428  return ERROR_INVALID_PARAMETER;
2429  }
2430  }
2431 
2432  /* Allocate a new service entry */
2433  dwError = ScmCreateNewServiceRecord(lpServiceName,
2434  &lpService,
2435  dwServiceType,
2436  dwStartType);
2437  if (dwError != ERROR_SUCCESS)
2438  goto done;
2439 
2440  /* Fill the new service entry */
2441  lpService->dwErrorControl = dwErrorControl;
2442 
2443  /* Fill the display name */
2444  if (lpDisplayName != NULL &&
2445  *lpDisplayName != 0 &&
2446  _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2447  {
2448  lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2450  (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2451  if (lpService->lpDisplayName == NULL)
2452  {
2453  dwError = ERROR_NOT_ENOUGH_MEMORY;
2454  goto done;
2455  }
2456  wcscpy(lpService->lpDisplayName, lpDisplayName);
2457  }
2458 
2459  /* Assign the service to a group */
2460  if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2461  {
2462  dwError = ScmSetServiceGroup(lpService,
2463  lpLoadOrderGroup);
2464  if (dwError != ERROR_SUCCESS)
2465  goto done;
2466  }
2467 
2468  /* Assign a new tag */
2469  if (lpdwTagId != NULL)
2470  {
2471  dwError = ScmAssignNewTag(lpService);
2472  if (dwError != ERROR_SUCCESS)
2473  goto done;
2474  }
2475 
2476  /* Assign the default security descriptor */
2477  if (dwServiceType & SERVICE_WIN32)
2478  {
2479  dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
2480  if (dwError != ERROR_SUCCESS)
2481  goto done;
2482  }
2483 
2484  /* Write service data to the registry */
2485  /* Create the service key */
2486  dwError = ScmCreateServiceKey(lpServiceName,
2487  KEY_WRITE,
2488  &hServiceKey);
2489  if (dwError != ERROR_SUCCESS)
2490  goto done;
2491 
2492  /* Set the display name */
2493  if (lpDisplayName != NULL && *lpDisplayName != 0)
2494  {
2495  RegSetValueExW(hServiceKey,
2496  L"DisplayName",
2497  0,
2498  REG_SZ,
2500  (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2501  }
2502 
2503  /* Set the service type */
2504  dwError = RegSetValueExW(hServiceKey,
2505  L"Type",
2506  0,
2507  REG_DWORD,
2508  (LPBYTE)&dwServiceType,
2509  sizeof(DWORD));
2510  if (dwError != ERROR_SUCCESS)
2511  goto done;
2512 
2513  /* Set the start value */
2514  dwError = RegSetValueExW(hServiceKey,
2515  L"Start",
2516  0,
2517  REG_DWORD,
2518  (LPBYTE)&dwStartType,
2519  sizeof(DWORD));
2520  if (dwError != ERROR_SUCCESS)
2521  goto done;
2522 
2523  /* Set the error control value */
2524  dwError = RegSetValueExW(hServiceKey,
2525  L"ErrorControl",
2526  0,
2527  REG_DWORD,
2528  (LPBYTE)&dwErrorControl,
2529  sizeof(DWORD));
2530  if (dwError != ERROR_SUCCESS)
2531  goto done;
2532 
2533  /* Set the image path */
2534  if (dwServiceType & SERVICE_WIN32)
2535  {
2536  dwError = RegSetValueExW(hServiceKey,
2537  L"ImagePath",
2538  0,
2539  REG_EXPAND_SZ,
2540  (LPBYTE)lpBinaryPathName,
2541  (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2542  if (dwError != ERROR_SUCCESS)
2543  goto done;
2544  }
2545  else if (dwServiceType & SERVICE_DRIVER)
2546  {
2547  dwError = RegSetValueExW(hServiceKey,
2548  L"ImagePath",
2549  0,
2550  REG_EXPAND_SZ,
2551  (LPBYTE)lpImagePath,
2552  (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2553  if (dwError != ERROR_SUCCESS)
2554  goto done;
2555  }
2556 
2557  /* Set the group name */
2558  if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2559  {
2560  dwError = RegSetValueExW(hServiceKey,
2561  L"Group",
2562  0,
2563  REG_SZ,
2564  (LPBYTE)lpLoadOrderGroup,
2565  (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2566  if (dwError != ERROR_SUCCESS)
2567  goto done;
2568  }
2569 
2570  /* Set the service tag */
2571  if (lpdwTagId != NULL)
2572  {
2573  dwError = RegSetValueExW(hServiceKey,
2574  L"Tag",
2575  0,
2576  REG_DWORD,
2577  (LPBYTE)&lpService->dwTag,
2578  sizeof(DWORD));
2579  if (dwError != ERROR_SUCCESS)
2580  goto done;
2581  }
2582 
2583  /* Write dependencies */
2584  if (lpDependencies != NULL && *lpDependencies != 0)
2585  {
2586  dwError = ScmWriteDependencies(hServiceKey,
2587  (LPCWSTR)lpDependencies,
2588  dwDependSize);
2589  if (dwError != ERROR_SUCCESS)
2590  goto done;
2591  }
2592 
2593  /* Start name and password are only used by Win32 services */
2594  if (dwServiceType & SERVICE_WIN32)
2595  {
2596  /* Write service start name */
2597  lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2598  dwError = RegSetValueExW(hServiceKey,
2599  L"ObjectName",
2600  0,
2601  REG_SZ,
2602  (LPBYTE)lpObjectName,
2603  (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2604  if (dwError != ERROR_SUCCESS)
2605  goto done;
2606 
2607  if (lpPassword != NULL && *(LPWSTR)lpPassword != 0)
2608  {
2609  /* Decrypt the password */
2610  dwError = ScmDecryptPassword(lpPassword,
2611  dwPwSize,
2612  &lpClearTextPassword);
2613  if (dwError != ERROR_SUCCESS)
2614  goto done;
2615 
2616  /* Write the password */
2617  dwError = ScmSetServicePassword(lpServiceName,
2618  lpClearTextPassword);
2619  if (dwError != ERROR_SUCCESS)
2620  goto done;
2621  }
2622 
2623  /* Write the security descriptor */
2624  dwError = ScmWriteSecurityDescriptor(hServiceKey,
2625  lpService->pSecurityDescriptor);
2626  if (dwError != ERROR_SUCCESS)
2627  goto done;
2628  }
2629 
2630  dwError = ScmCreateServiceHandle(lpService,
2631  &hServiceHandle);
2632  if (dwError != ERROR_SUCCESS)
2633  goto done;
2634 
2635  dwError = ScmCheckAccess(hServiceHandle,
2636  dwDesiredAccess);
2637  if (dwError != ERROR_SUCCESS)
2638  goto done;
2639 
2640  lpService->dwRefCount = 1;
2641 
2642  /* Get the service tag (if Win32) */
2643  ScmGenerateServiceTag(lpService);
2644 
2645  DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2646 
2647 done:
2648  /* Unlock the service database */
2650 
2651  if (hServiceKey != NULL)
2652  RegCloseKey(hServiceKey);
2653 
2654  if (lpClearTextPassword != NULL)
2655  {
2656  /* Wipe and release the password buffer */
2657  SecureZeroMemory(lpClearTextPassword,
2658  (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2659  HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2660  }
2661 
2662  if (dwError == ERROR_SUCCESS)
2663  {
2664  DPRINT("hService %p\n", hServiceHandle);
2665  *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2666 
2667  if (lpdwTagId != NULL)
2668  *lpdwTagId = lpService->dwTag;
2669  }
2670  else
2671  {
2672  if (lpService != NULL &&
2673  lpService->lpServiceName != NULL)
2674  {
2675  /* Release the display name buffer */
2676  HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2677  }
2678 
2679  if (hServiceHandle)
2680  {
2681  /* Remove the service handle */
2682  HeapFree(GetProcessHeap(), 0, hServiceHandle);
2683  }
2684 
2685  if (lpService != NULL)
2686  {
2687  /* FIXME: remove the service entry */
2688  }
2689  }
2690 
2691  if (lpImagePath != NULL)
2692  HeapFree(GetProcessHeap(), 0, lpImagePath);
2693 
2694  DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2695 
2696  return dwError;
2697 }
2698 
2699 
2700 /* Function 13 */
2701 DWORD
2702 WINAPI
2704  SC_RPC_HANDLE hService,
2705  DWORD dwServiceState,
2706  LPBYTE lpServices,
2707  DWORD cbBufSize,
2709  LPBOUNDED_DWORD_256K lpServicesReturned)
2710 {
2711  DWORD dwError = ERROR_SUCCESS;
2712  DWORD dwServicesReturned = 0;
2713  DWORD dwServiceCount;
2715  PSERVICE_HANDLE hSvc;
2716  PSERVICE lpService = NULL;
2717  PSERVICE *lpServicesArray = NULL;
2718  LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2719  LPWSTR lpStr;
2720 
2721  *pcbBytesNeeded = 0;
2722  *lpServicesReturned = 0;
2723 
2724  DPRINT("REnumDependentServicesW() called\n");
2725 
2726  hSvc = ScmGetServiceFromHandle(hService);
2727  if (hSvc == NULL)
2728  {
2729  DPRINT1("Invalid service handle!\n");
2730  return ERROR_INVALID_HANDLE;
2731  }
2732 
2733  lpService = hSvc->ServiceEntry;
2734 
2735  /* Check access rights */
2738  {
2739  DPRINT("Insufficient access rights! 0x%lx\n",
2740  hSvc->Handle.DesiredAccess);
2741  return ERROR_ACCESS_DENIED;
2742  }
2743 
2744  /* Open the Services Reg key */
2746  L"System\\CurrentControlSet\\Services",
2747  0,
2748  KEY_READ,
2749  &hServicesKey);
2750  if (dwError != ERROR_SUCCESS)
2751  return dwError;
2752 
2753  /* First determine the bytes needed and get the number of dependent services */
2755  lpService,
2756  dwServiceState,
2757  NULL,
2759  &dwServicesReturned);
2760  if (dwError != ERROR_SUCCESS)
2761  goto Done;
2762 
2763  /* If buffer size is less than the bytes needed or pointer is null */
2764  if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2765  {
2766  dwError = ERROR_MORE_DATA;
2767  goto Done;
2768  }
2769 
2770  /* Allocate memory for array of service pointers */
2771  lpServicesArray = HeapAlloc(GetProcessHeap(),
2773  (dwServicesReturned + 1) * sizeof(PSERVICE));
2774  if (!lpServicesArray)
2775  {
2776  DPRINT1("Could not allocate a buffer!!\n");
2777  dwError = ERROR_NOT_ENOUGH_MEMORY;
2778  goto Done;
2779  }
2780 
2781  dwServicesReturned = 0;
2782  *pcbBytesNeeded = 0;
2783 
2785  lpService,
2786  dwServiceState,
2787  lpServicesArray,
2789  &dwServicesReturned);
2790  if (dwError != ERROR_SUCCESS)
2791  {
2792  goto Done;
2793  }
2794 
2795  lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2796  lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2797 
2798  /* Copy EnumDepenedentService to Buffer */
2799  for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2800  {
2801  lpService = lpServicesArray[dwServiceCount];
2802 
2803  /* Copy status info */
2804  memcpy(&lpServicesPtr->ServiceStatus,
2805  &lpService->Status,
2806  sizeof(SERVICE_STATUS));
2807 
2808  /* Copy display name */
2809  wcscpy(lpStr, lpService->lpDisplayName);
2810  lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2811  lpStr += (wcslen(lpService->lpDisplayName) + 1);
2812 
2813  /* Copy service name */
2814  wcscpy(lpStr, lpService->lpServiceName);
2815  lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2816  lpStr += (wcslen(lpService->lpServiceName) + 1);
2817 
2818  lpServicesPtr++;
2819  }
2820 
2821  *lpServicesReturned = dwServicesReturned;
2822 
2823 Done:
2824  if (lpServicesArray != NULL)
2825  HeapFree(GetProcessHeap(), 0, lpServicesArray);
2826 
2828 
2829  DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2830 
2831  return dwError;
2832 }
2833 
2834 
2835 /* Function 14 */
2836 DWORD
2837 WINAPI
2840  DWORD dwServiceType,
2841  DWORD dwServiceState,
2842  LPBYTE lpBuffer,
2843  DWORD dwBufSize,
2845  LPBOUNDED_DWORD_256K lpServicesReturned,
2846  LPBOUNDED_DWORD_256K lpResumeHandle)
2847 {
2848  /* Enumerate all the services, not regarding of their group */
2850  dwServiceType,
2851  dwServiceState,
2852  lpBuffer,
2853  dwBufSize,
2855  lpServicesReturned,
2856  lpResumeHandle,
2857  NULL);
2858 }
2859 
2860 
2861 /* Function 15 */
2862 DWORD
2863 WINAPI
2865  LPWSTR lpMachineName,
2866  LPWSTR lpDatabaseName,
2867  DWORD dwDesiredAccess,
2868  LPSC_RPC_HANDLE lpScHandle)
2869 {
2870  DWORD dwError;
2871  SC_HANDLE hHandle;
2872 
2873  DPRINT("ROpenSCManagerW() called\n");
2874  DPRINT("lpMachineName = %p\n", lpMachineName);
2875  DPRINT("lpMachineName: %S\n", lpMachineName);
2876  DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2877  DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2878  DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2879 
2880  if (ScmShutdown)
2882 
2883  if (!lpScHandle)
2884  return ERROR_INVALID_PARAMETER;
2885 
2886  dwError = ScmCreateManagerHandle(lpDatabaseName,
2887  &hHandle);
2888  if (dwError != ERROR_SUCCESS)
2889  {
2890  DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2891  return dwError;
2892  }
2893 
2894  /* Check the desired access */
2895  dwError = ScmCheckAccess(hHandle,
2896  dwDesiredAccess | SC_MANAGER_CONNECT);
2897  if (dwError != ERROR_SUCCESS)
2898  {
2899  DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2900  HeapFree(GetProcessHeap(), 0, hHandle);
2901  return dwError;
2902  }
2903 
2904  *lpScHandle = (SC_RPC_HANDLE)hHandle;
2905  DPRINT("*hScm = %p\n", *lpScHandle);
2906 
2907  DPRINT("ROpenSCManagerW() done\n");
2908 
2909  return ERROR_SUCCESS;
2910 }
2911 
2912 
2913 /* Function 16 */
2914 DWORD
2915 WINAPI
2918  LPWSTR lpServiceName,
2919  DWORD dwDesiredAccess,
2920  LPSC_RPC_HANDLE lpServiceHandle)
2921 {
2922  PSERVICE lpService;
2923  PMANAGER_HANDLE hManager;
2924  SC_HANDLE hHandle;
2925  DWORD dwError = ERROR_SUCCESS;
2926 
2927  DPRINT("ROpenServiceW() called\n");
2928  DPRINT("hSCManager = %p\n", hSCManager);
2929  DPRINT("lpServiceName = %p\n", lpServiceName);
2930  DPRINT("lpServiceName: %S\n", lpServiceName);
2931  DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2932 
2933  if (ScmShutdown)
2935 
2937  if (hManager == NULL)
2938  {
2939  DPRINT1("Invalid service manager handle!\n");
2940  return ERROR_INVALID_HANDLE;
2941  }
2942 
2943  if (!lpServiceHandle)
2944  return ERROR_INVALID_PARAMETER;
2945 
2946  if (!lpServiceName)
2947  return ERROR_INVALID_ADDRESS;
2948 
2949  /* Lock the service database exclusive */
2951 
2952  /* Get service database entry */
2953  lpService = ScmGetServiceEntryByName(lpServiceName);
2954  if (lpService == NULL)
2955  {
2956  DPRINT("Could not find the service!\n");
2957  dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2958  goto Done;
2959  }
2960 
2961  /* Create a service handle */
2962  dwError = ScmCreateServiceHandle(lpService,
2963  &hHandle);
2964  if (dwError != ERROR_SUCCESS)
2965  {
2966  DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2967  goto Done;
2968  }
2969 
2970  /* Check the desired access */
2971  dwError = ScmCheckAccess(hHandle,
2972  dwDesiredAccess);
2973  if (dwError != ERROR_SUCCESS)
2974  {
2975  DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2976  HeapFree(GetProcessHeap(), 0, hHandle);
2977  goto Done;
2978  }
2979 
2980  lpService->dwRefCount++;
2981  DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2982 
2983  *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2984  DPRINT("*hService = %p\n", *lpServiceHandle);
2985 
2986 Done:
2987  /* Unlock the service database */
2989 
2990  DPRINT("ROpenServiceW() done\n");
2991 
2992  return dwError;
2993 }
2994 
2995 
2996 /* Function 17 */
2997 DWORD
2998 WINAPI
3000  SC_RPC_HANDLE hService,
3001  LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
3002  DWORD cbBufSize,
3004 {
3005  LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
3006  DWORD dwError = ERROR_SUCCESS;
3007  PSERVICE_HANDLE hSvc;
3008  PSERVICE lpService = NULL;
3009  HKEY hServiceKey = NULL;
3010  LPWSTR lpImagePath = NULL;
3011  LPWSTR lpServiceStartName = NULL;
3012  LPWSTR lpDependencies = NULL;
3013  DWORD dwDependenciesLength = 0;
3014  DWORD dwRequiredSize;
3015  LPWSTR lpStr;
3016 
3017  DPRINT("RQueryServiceConfigW() called\n");
3018 
3019  if (ScmShutdown)
3021 
3022  hSvc = ScmGetServiceFromHandle(hService);
3023  if (hSvc == NULL)
3024  {
3025  DPRINT1("Invalid service handle!\n");
3026  return ERROR_INVALID_HANDLE;
3027  }
3028 
3031  {
3032  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3033  return ERROR_ACCESS_DENIED;
3034  }
3035 
3036  lpService = hSvc->ServiceEntry;
3037  if (lpService == NULL)
3038  {
3039  DPRINT("lpService == NULL!\n");
3040  return ERROR_INVALID_HANDLE;
3041  }
3042 
3043  /* Lock the service database shared */
3045 
3046  dwError = ScmOpenServiceKey(lpService->lpServiceName,
3047  KEY_READ,
3048  &hServiceKey);
3049  if (dwError != ERROR_SUCCESS)
3050  goto Done;
3051 
3052  /* Read the image path */
3053  dwError = ScmReadString(hServiceKey,
3054  L"ImagePath",
3055  &lpImagePath);
3056  if (dwError != ERROR_SUCCESS)
3057  goto Done;
3058 
3059  /* Read the service start name */
3060  ScmReadString(hServiceKey,
3061  L"ObjectName",
3062  &lpServiceStartName);
3063 
3064  /* Read the dependencies */
3065  ScmReadDependencies(hServiceKey,
3066  &lpDependencies,
3067  &dwDependenciesLength);
3068 
3069  dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3070 
3071  if (lpImagePath != NULL)
3072  dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
3073  else
3074  dwRequiredSize += 2 * sizeof(WCHAR);
3075 
3076  if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3077  dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
3078  else
3079  dwRequiredSize += 2 * sizeof(WCHAR);
3080 
3081  if (lpDependencies != NULL)
3082  dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
3083  else
3084  dwRequiredSize += 2 * sizeof(WCHAR);
3085 
3086  if (lpServiceStartName != NULL)
3087  dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
3088  else
3089  dwRequiredSize += 2 * sizeof(WCHAR);
3090 
3091  if (lpService->lpDisplayName != NULL)
3092  dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
3093  else
3094  dwRequiredSize += 2 * sizeof(WCHAR);
3095 
3096  if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3097  {
3098  dwError = ERROR_INSUFFICIENT_BUFFER;
3099  }
3100  else
3101  {
3102  lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
3103  lpServiceConfig->dwStartType = lpService->dwStartType;
3104  lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
3105  lpServiceConfig->dwTagId = lpService->dwTag;
3106 
3107  lpStr = (LPWSTR)(lpServiceConfig + 1);
3108 
3109  /* Append the image path */
3110  if (lpImagePath != NULL)
3111  {
3112  wcscpy(lpStr, lpImagePath);
3113  }
3114  else
3115  {
3116  *lpStr = 0;
3117  }
3118 
3119  lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3120  lpStr += (wcslen(lpStr) + 1);
3121 
3122  /* Append the group name */
3123  if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3124  {
3125  wcscpy(lpStr, lpService->lpGroup->lpGroupName);
3126  }
3127  else
3128  {
3129  *lpStr = 0;
3130  }
3131 
3132  lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3133  lpStr += (wcslen(lpStr) + 1);
3134 
3135  /* Append Dependencies */
3136  if (lpDependencies != NULL)
3137  {
3138  memcpy(lpStr,
3139  lpDependencies,
3140  dwDependenciesLength * sizeof(WCHAR));
3141  }
3142  else
3143  {
3144  *lpStr = 0;
3145  }
3146 
3147  lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3148  if (lpDependencies != NULL)
3149  lpStr += dwDependenciesLength;
3150  else
3151  lpStr += (wcslen(lpStr) + 1);
3152 
3153  /* Append the service start name */
3154  if (lpServiceStartName != NULL)
3155  {
3156  wcscpy(lpStr, lpServiceStartName);
3157  }
3158  else
3159  {
3160  *lpStr = 0;
3161  }
3162 
3163  lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3164  lpStr += (wcslen(lpStr) + 1);
3165 
3166  /* Append the display name */
3167  if (lpService->lpDisplayName != NULL)
3168  {
3169  wcscpy(lpStr, lpService->lpDisplayName);
3170  }
3171  else
3172  {
3173  *lpStr = 0;
3174  }
3175 
3176  lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3177  }
3178 
3179  if (pcbBytesNeeded != NULL)
3180  *pcbBytesNeeded = dwRequiredSize;
3181 
3182 Done:
3183  /* Unlock the service database */
3185 
3186  if (lpImagePath != NULL)
3187  HeapFree(GetProcessHeap(), 0, lpImagePath);
3188 
3189  if (lpServiceStartName != NULL)
3190  HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3191 
3192  if (lpDependencies != NULL)
3193  HeapFree(GetProcessHeap(), 0, lpDependencies);
3194 
3195  if (hServiceKey != NULL)
3196  RegCloseKey(hServiceKey);
3197 
3198  DPRINT("RQueryServiceConfigW() done\n");
3199 
3200  return dwError;
3201 }
3202 
3203 
3204 /* Function 18 */
3205 DWORD
3206 WINAPI
3209  LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3210  DWORD cbBufSize,
3212 {
3214  PMANAGER_HANDLE hMgr;
3215  DWORD dwRequiredSize;
3216 
3217  if (!lpLockStatus || !pcbBytesNeeded)
3218  return ERROR_INVALID_PARAMETER;
3219 
3221  if (hMgr == NULL)
3222  {
3223  DPRINT1("Invalid service manager handle!\n");
3224  return ERROR_INVALID_HANDLE;
3225  }
3226 
3229  {
3230  DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
3231  return ERROR_ACCESS_DENIED;
3232  }
3233 
3234  /* FIXME: we need to compute instead the real length of the owner name */
3235  dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
3236  *pcbBytesNeeded = dwRequiredSize;
3237 
3238  if (cbBufSize < dwRequiredSize)
3240 
3241  ScmQueryServiceLockStatusW(lpLockStatus);
3242 
3243  return ERROR_SUCCESS;
3244 }
3245 
3246 
3247 /* Function 19 */
3248 DWORD
3249 WINAPI
3251  SC_RPC_HANDLE hService,
3252  DWORD argc,
3254 {
3255  DWORD dwError = ERROR_SUCCESS;
3256  PSERVICE_HANDLE hSvc;
3257  PSERVICE lpService = NULL;
3258 
3259 #ifndef NDEBUG
3260  DWORD i;
3261 
3262  DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3263  DPRINT(" argc: %lu\n", argc);
3264  if (argv != NULL)
3265  {
3266  for (i = 0; i < argc; i++)
3267  {
3268  DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
3269  }
3270  }
3271 #endif
3272 
3273  if (ScmShutdown)
3275 
3276  hSvc = ScmGetServiceFromHandle(hService);
3277  if (hSvc == NULL)
3278  {
3279  DPRINT1("Invalid service handle!\n");
3280  return ERROR_INVALID_HANDLE;
3281  }
3282 
3284  SERVICE_START))
3285  {
3286  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3287  return ERROR_ACCESS_DENIED;
3288  }
3289 
3290  lpService = hSvc->ServiceEntry;
3291  if (lpService == NULL)
3292  {
3293  DPRINT("lpService == NULL!\n");
3294  return ERROR_INVALID_HANDLE;
3295  }
3296 
3297  if (lpService->dwStartType == SERVICE_DISABLED)
3298  return ERROR_SERVICE_DISABLED;
3299 
3300  if (lpService->bDeleted)
3302 
3303  /* Start the service */
3304  dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3305 
3306  return dwError;
3307 }
3308 
3309 
3310 /* Function 20 */
3311 DWORD
3312 WINAPI
3315  LPCWSTR lpServiceName,
3317  DWORD *lpcchBuffer)
3318 {
3319  // PMANAGER_HANDLE hManager;
3320  PSERVICE lpService;
3321  LPCWSTR lpSvcDisplayName;
3322  DWORD dwLength;
3323  DWORD dwError;
3324 
3325  DPRINT("RGetServiceDisplayNameW() called\n");
3326  DPRINT("hSCManager = %p\n", hSCManager);
3327  DPRINT("lpServiceName: %S\n", lpServiceName);
3328  DPRINT("lpDisplayName: %p\n", lpDisplayName);
3329  DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3330 
3331 #if 0
3332  hManager = (PMANAGER_HANDLE)hSCManager;
3333  if (hManager->Handle.Tag != MANAGER_TAG)
3334  {
3335  DPRINT("Invalid manager handle!\n");
3336  return ERROR_INVALID_HANDLE;
3337  }
3338 #endif
3339 
3340  /* Get service database entry */
3341  lpService = ScmGetServiceEntryByName(lpServiceName);
3342  if (lpService == NULL)
3343  {
3344  DPRINT("Could not find the service!\n");
3346  }
3347 
3348  if (lpService->lpDisplayName)
3349  lpSvcDisplayName = lpService->lpDisplayName;
3350  else
3351  lpSvcDisplayName = lpService->lpServiceName;
3352 
3353  dwLength = (DWORD)wcslen(lpSvcDisplayName);
3354 
3355  if (*lpcchBuffer > dwLength)
3356  {
3357  if (lpDisplayName != NULL)
3358  wcscpy(lpDisplayName, lpSvcDisplayName);
3359 
3360  dwError = ERROR_SUCCESS;
3361  }
3362  else
3363  {
3364  dwError = ERROR_INSUFFICIENT_BUFFER;
3365  }
3366 
3367  *lpcchBuffer = dwLength;
3368 
3369  return dwError;
3370 }
3371 
3372 
3373 /* Function 21 */
3374 DWORD
3375 WINAPI
3379  LPWSTR lpServiceName,
3380  DWORD *lpcchBuffer)
3381 {
3382  // PMANAGER_HANDLE hManager;
3383  PSERVICE lpService;
3384  DWORD dwLength;
3385  DWORD dwError;
3386 
3387  DPRINT("RGetServiceKeyNameW() called\n");
3388  DPRINT("hSCManager = %p\n", hSCManager);
3389  DPRINT("lpDisplayName: %S\n", lpDisplayName);
3390  DPRINT("lpServiceName: %p\n", lpServiceName);
3391  DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3392 
3393 #if 0
3394  hManager = (PMANAGER_HANDLE)hSCManager;
3395  if (hManager->Handle.Tag != MANAGER_TAG)
3396  {
3397  DPRINT("Invalid manager handle!\n");
3398  return ERROR_INVALID_HANDLE;
3399  }
3400 #endif
3401 
3402  /* Get service database entry */
3404  if (lpService == NULL)
3405  {
3406  DPRINT("Could not find the service!\n");
3408  }
3409 
3410  dwLength = (DWORD)wcslen(lpService->lpServiceName);
3411 
3412  if (*lpcchBuffer > dwLength)
3413  {
3414  if (lpServiceName != NULL)
3415  wcscpy(lpServiceName, lpService->lpServiceName);
3416 
3417  dwError = ERROR_SUCCESS;
3418  }
3419  else
3420  {
3421  dwError = ERROR_INSUFFICIENT_BUFFER;
3422  }
3423 
3424  *lpcchBuffer = dwLength;
3425 
3426  return dwError;
3427 }
3428 
3429 
3430 /* Function 22 */
3431 DWORD
3432 WINAPI
3436  int bSetBitsOn,
3437  int bUpdateImmediately,
3438  char *lpString)
3439 {
3440  if (ScmShutdown)
3442 
3443  if (lpString != NULL)
3444  return ERROR_INVALID_PARAMETER;
3445 
3447  dwServiceBits,
3448  bSetBitsOn,
3449  bUpdateImmediately,
3450  NULL);
3451 }
3452 
3453 
3454 /* Function 23 */
3455 DWORD
3456 WINAPI
3458  SC_RPC_HANDLE hService,
3459  DWORD dwServiceType,
3460  DWORD dwStartType,
3461  DWORD dwErrorControl,
3462  LPSTR lpBinaryPathName,
3463  LPSTR lpLoadOrderGroup,
3464  LPDWORD lpdwTagId,
3465  LPBYTE lpDependencies,
3466  DWORD dwDependSize,
3467  LPSTR lpServiceStartName,
3468  LPBYTE lpPassword,
3469  DWORD dwPwSize,
3471 {
3472  DWORD dwError = ERROR_SUCCESS;
3473  LPWSTR lpBinaryPathNameW = NULL;
3474  LPWSTR lpLoadOrderGroupW = NULL;
3475  LPWSTR lpDependenciesW = NULL;
3476  LPWSTR lpServiceStartNameW = NULL;
3477  LPWSTR lpDisplayNameW = NULL;
3478  DWORD dwDependenciesLength = 0;
3479  SIZE_T cchLength;
3480  int len;
3481  LPCSTR lpStr;
3482 
3483  if (lpBinaryPathName)
3484  {
3485  len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3486  lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3487  if (!lpBinaryPathNameW)
3488  {
3490  goto cleanup;
3491  }
3492  MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3493  }
3494 
3495  if (lpLoadOrderGroup)
3496  {
3497  len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3498  lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3499  if (!lpLoadOrderGroupW)
3500  {
3502  goto cleanup;
3503  }
3504  MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3505  }
3506 
3507  if (lpDependencies)
3508  {
3509  lpStr = (LPCSTR)lpDependencies;
3510  while (*lpStr)
3511  {
3512  cchLength = strlen(lpStr) + 1;
3513  dwDependenciesLength += (DWORD)cchLength;
3514  lpStr = lpStr + cchLength;
3515  }
3516  dwDependenciesLength++;
3517 
3518  lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3519  if (!lpDependenciesW)
3520  {
3522  goto cleanup;
3523  }
3524  MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3525  }
3526 
3527  if (lpServiceStartName)
3528  {
3529  len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3530  lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3531  if (!lpServiceStartNameW)
3532  {
3534  goto cleanup;
3535  }
3536  MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3537  }
3538 
3539  if (lpDisplayName)
3540  {
3542  lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3543  if (!lpDisplayNameW)
3544  {
3546  goto cleanup;
3547  }
3548  MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3549  }
3550 
3551  dwError = RChangeServiceConfigW(hService,
3552  dwServiceType,
3553  dwStartType,
3554  dwErrorControl,
3555  lpBinaryPathNameW,
3556  lpLoadOrderGroupW,
3557  lpdwTagId,
3558  (LPBYTE)lpDependenciesW,
3559  dwDependenciesLength,
3560  lpServiceStartNameW,
3561  lpPassword,
3562  dwPwSize,
3563  lpDisplayNameW);
3564 
3565 cleanup:
3566  if (lpBinaryPathNameW != NULL)
3567  HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3568 
3569  if (lpLoadOrderGroupW != NULL)
3570  HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3571 
3572  if (lpDependenciesW != NULL)
3573  HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3574 
3575  if (lpServiceStartNameW != NULL)
3576  HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3577 
3578  if (lpDisplayNameW != NULL)
3579  HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3580 
3581  return dwError;
3582 }
3583 
3584 
3585 /* Function 24 */
3586 DWORD
3587 WINAPI
3590  LPSTR lpServiceName,
3592  DWORD dwDesiredAccess,
3593  DWORD dwServiceType,
3594  DWORD dwStartType,
3595  DWORD dwErrorControl,
3596  LPSTR lpBinaryPathName,
3597  LPSTR lpLoadOrderGroup,
3598  LPDWORD lpdwTagId,
3599  LPBYTE lpDependencies,
3600  DWORD dwDependSize,
3601  LPSTR lpServiceStartName,
3602  LPBYTE lpPassword,
3603  DWORD dwPwSize,
3604  LPSC_RPC_HANDLE lpServiceHandle)
3605 {
3606  DWORD dwError = ERROR_SUCCESS;
3607  LPWSTR lpServiceNameW = NULL;
3608  LPWSTR lpDisplayNameW = NULL;
3609  LPWSTR lpBinaryPathNameW = NULL;
3610  LPWSTR lpLoadOrderGroupW = NULL;
3611  LPWSTR lpDependenciesW = NULL;
3612  LPWSTR lpServiceStartNameW = NULL;
3613  DWORD dwDependenciesLength = 0;
3614  SIZE_T cchLength;
3615  int len;
3616  LPCSTR lpStr;
3617 
3618  if (lpServiceName)
3619  {
3620  len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3621  lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3622  if (!lpServiceNameW)
3623  {
3625  goto cleanup;
3626  }
3627  MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3628  }
3629 
3630  if (lpDisplayName)
3631  {
3633  lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3634  if (!lpDisplayNameW)
3635  {
3637  goto cleanup;
3638  }
3639  MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3640  }
3641 
3642  if (lpBinaryPathName)
3643  {
3644  len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3645  lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3646  if (!lpBinaryPathNameW)
3647  {
3649  goto cleanup;
3650  }
3651  MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3652  }
3653 
3654  if (lpLoadOrderGroup)
3655  {
3656  len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3657  lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3658  if (!lpLoadOrderGroupW)
3659  {
3661  goto cleanup;
3662  }
3663  MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3664  }
3665 
3666  if (lpDependencies)
3667  {
3668  lpStr = (LPCSTR)lpDependencies;
3669  while (*lpStr)
3670  {
3671  cchLength = strlen(lpStr) + 1;
3672  dwDependenciesLength += (DWORD)cchLength;
3673  lpStr = lpStr + cchLength;
3674  }
3675  dwDependenciesLength++;
3676 
3677  lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3678  if (!lpDependenciesW)
3679  {
3681  goto cleanup;
3682  }
3683  MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3684  }
3685 
3686  if (lpServiceStartName)
3687  {
3688  len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3689  lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3690  if (!lpServiceStartNameW)
3691  {
3693  goto cleanup;
3694  }
3695  MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3696  }
3697 
3698  dwError = RCreateServiceW(hSCManager,
3699  lpServiceNameW,
3700  lpDisplayNameW,
3701  dwDesiredAccess,
3702  dwServiceType,
3703  dwStartType,
3704  dwErrorControl,
3705  lpBinaryPathNameW,
3706  lpLoadOrderGroupW,
3707  lpdwTagId,
3708  (LPBYTE)lpDependenciesW,
3709  dwDependenciesLength,
3710  lpServiceStartNameW,
3711  lpPassword,
3712  dwPwSize,
3713  lpServiceHandle);
3714 
3715 cleanup:
3716  if (lpServiceNameW !=NULL)
3717  HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3718 
3719  if (lpDisplayNameW != NULL)
3720  HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3721 
3722  if (lpBinaryPathNameW != NULL)
3723  HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3724 
3725  if (lpLoadOrderGroupW != NULL)
3726  HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3727 
3728  if (lpDependenciesW != NULL)
3729  HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3730 
3731  if (lpServiceStartNameW != NULL)
3732  HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3733 
3734  return dwError;
3735 }
3736 
3737 
3738 /* Function 25 */
3739 DWORD
3740 WINAPI
3742  SC_RPC_HANDLE hService,
3743  DWORD dwServiceState,
3744  LPBYTE lpServices,
3745  DWORD cbBufSize,
3747  LPBOUNDED_DWORD_256K lpServicesReturned)
3748 {
3749  DWORD dwError = ERROR_SUCCESS;
3750  DWORD dwServicesReturned = 0;
3751  DWORD dwServiceCount;
3753  PSERVICE_HANDLE hSvc;
3754  PSERVICE lpService = NULL;
3755  PSERVICE *lpServicesArray = NULL;
3756  LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3757  LPSTR lpStr;
3758 
3759  *pcbBytesNeeded = 0;
3760  *lpServicesReturned = 0;
3761 
3762  DPRINT("REnumDependentServicesA() called\n");
3763 
3764  hSvc = ScmGetServiceFromHandle(hService);
3765  if (hSvc == NULL)
3766  {
3767  DPRINT1("Invalid service handle!\n");
3768  return ERROR_INVALID_HANDLE;
3769  }
3770 
3771  lpService = hSvc->ServiceEntry;
3772 
3773  /* Check access rights */
3776  {
3777  DPRINT("Insufficient access rights! 0x%lx\n",
3778  hSvc->Handle.DesiredAccess);
3779  return ERROR_ACCESS_DENIED;
3780  }
3781 
3782  /* Open the Services Reg key */
3784  L"System\\CurrentControlSet\\Services",
3785  0,
3786  KEY_READ,
3787  &hServicesKey);
3788 
3789  if (dwError != ERROR_SUCCESS)
3790  return dwError;
3791 
3792  /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3793  both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3794  are the same for both. Verified in WINXP. */
3795 
3796  /* First determine the bytes needed and get the number of dependent services*/
3798  lpService,
3799  dwServiceState,
3800  NULL,
3802  &dwServicesReturned);
3803  if (dwError != ERROR_SUCCESS)
3804  goto Done;
3805 
3806  /* If buffer size is less than the bytes needed or pointer is null*/
3807  if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3808  {
3809  dwError = ERROR_MORE_DATA;
3810  goto Done;
3811  }
3812 
3813  /* Allocate memory for array of service pointers */
3814  lpServicesArray = HeapAlloc(GetProcessHeap(),
3816  (dwServicesReturned + 1) * sizeof(PSERVICE));
3817  if (!lpServicesArray)
3818  {
3819  DPRINT("Could not allocate a buffer!!\n");
3820  dwError = ERROR_NOT_ENOUGH_MEMORY;
3821  goto Done;
3822  }
3823 
3824  dwServicesReturned = 0;
3825  *pcbBytesNeeded = 0;
3826 
3828  lpService,
3829  dwServiceState,
3830  lpServicesArray,
3832  &dwServicesReturned);
3833  if (dwError != ERROR_SUCCESS)
3834  {
3835  goto Done;
3836  }
3837 
3838  lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3839  lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3840 
3841  /* Copy EnumDepenedentService to Buffer */
3842  for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3843  {
3844  lpService = lpServicesArray[dwServiceCount];
3845 
3846  /* Copy the status info */
3847  memcpy(&lpServicesPtr->ServiceStatus,
3848  &lpService->Status,
3849  sizeof(SERVICE_STATUS));
3850 
3851  /* Copy display name */
3853  0,
3854  lpService->lpDisplayName,
3855  -1,
3856  lpStr,
3857  (int)wcslen(lpService->lpDisplayName),
3858  0,
3859  0);
3860  lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3861  lpStr += strlen(lpStr) + 1;
3862 
3863  /* Copy service name */
3865  0,
3866  lpService->lpServiceName,
3867  -1,
3868  lpStr,
3869  (int)wcslen(lpService->lpServiceName),
3870  0,
3871  0);
3872  lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3873  lpStr += strlen(lpStr) + 1;
3874 
3875  lpServicesPtr++;
3876  }
3877 
3878  *lpServicesReturned = dwServicesReturned;
3879 
3880 Done:
3881  if (lpServicesArray)
3882  HeapFree(GetProcessHeap(), 0, lpServicesArray);
3883 
3885 
3886  DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3887 
3888  return dwError;
3889 }
3890 
3891 
3892 /* Function 26 */
3893 DWORD
3894 WINAPI
3897  DWORD dwServiceType,
3898  DWORD dwServiceState,
3899  LPBYTE lpBuffer,
3900  DWORD dwBufSize,
3902  LPBOUNDED_DWORD_256K lpServicesReturned,
3903  LPBOUNDED_DWORD_256K lpResumeHandle)
3904 {
3905  LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3906  LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
3907  LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3908  LPWSTR lpStringPtrW;
3909  LPSTR lpStringPtrA;
3910  DWORD dwError;
3911  DWORD dwServiceCount;
3912 
3913  DPRINT("REnumServicesStatusA() called\n");
3914 
3915  if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
3916  {
3917  return ERROR_INVALID_ADDRESS;
3918  }
3919 
3920  if ((dwBufSize > 0) && (lpBuffer))
3921  {
3922  lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3923  if (!lpStatusPtrW)
3924  {
3925  DPRINT("Failed to allocate buffer!\n");
3926  return ERROR_NOT_ENOUGH_MEMORY;
3927  }
3928  }
3929 
3930  dwError = REnumServicesStatusW(hSCManager,
3931  dwServiceType,
3932  dwServiceState,
3933  (LPBYTE)lpStatusPtrW,
3934  dwBufSize,
3936  lpServicesReturned,
3937  lpResumeHandle);
3938 
3939  /* if no services were returned then we are Done */
3940  if (*lpServicesReturned == 0)
3941  goto Done;
3942 
3943  lpStatusPtrIncrW = lpStatusPtrW;
3944  lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3945  lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3946  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3947  lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3948  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3949 
3950  for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3951  {
3952  /* Copy the service name */
3954  0,
3955  lpStringPtrW,
3956  -1,
3957  lpStringPtrA,
3958  (int)wcslen(lpStringPtrW),
3959  0,
3960  0);
3961 
3962  lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3963  lpStringPtrA += wcslen(lpStringPtrW) + 1;
3964  lpStringPtrW += wcslen(lpStringPtrW) + 1;
3965 
3966  /* Copy the display name */
3968  0,
3969  lpStringPtrW,
3970  -1,
3971  lpStringPtrA,
3972  (int)wcslen(lpStringPtrW),
3973  0,
3974  0);
3975 
3976  lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3977  lpStringPtrA += wcslen(lpStringPtrW) + 1;
3978  lpStringPtrW += wcslen(lpStringPtrW) + 1;
3979 
3980  /* Copy the status information */
3981  memcpy(&lpStatusPtrA->ServiceStatus,
3982  &lpStatusPtrIncrW->ServiceStatus,
3983  sizeof(SERVICE_STATUS));
3984 
3985  lpStatusPtrIncrW++;
3986  lpStatusPtrA++;
3987  }
3988 
3989 Done:
3990  if (lpStatusPtrW)
3991  HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3992 
3993  DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3994 
3995  return dwError;
3996 }
3997 
3998 
3999 /* Function 27 */
4000 DWORD
4001 WINAPI
4003  LPSTR lpMachineName,
4004  LPSTR lpDatabaseName,
4005  DWORD dwDesiredAccess,
4006  LPSC_RPC_HANDLE lpScHandle)
4007 {
4009  UNICODE_STRING DatabaseName;
4010  DWORD dwError;
4011 
4012  DPRINT("ROpenSCManagerA() called\n");
4013 
4014  if (lpMachineName)
4016  lpMachineName);
4017 
4018  if (lpDatabaseName)
4019  RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
4020  lpDatabaseName);
4021 
4022  dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
4023  lpDatabaseName ? DatabaseName.Buffer : NULL,
4024  dwDesiredAccess,
4025  lpScHandle);
4026 
4027  if (lpMachineName)
4029 
4030  if (lpDatabaseName)
4031  RtlFreeUnicodeString(&DatabaseName);
4032 
4033  return dwError;
4034 }
4035 
4036 
4037 /* Function 28 */
4038 DWORD
4039 WINAPI
4042  LPSTR lpServiceName,
4043  DWORD dwDesiredAccess,
4044  LPSC_RPC_HANDLE lpServiceHandle)
4045 {
4047  DWORD dwError;
4048 
4049  DPRINT("ROpenServiceA() called\n");
4050 
4051  if (lpServiceName)
4053  lpServiceName);
4054 
4055  dwError = ROpenServiceW(hSCManager,
4056  lpServiceName ? ServiceName.Buffer : NULL,
4057  dwDesiredAccess,
4058  lpServiceHandle);
4059 
4060  if (lpServiceName)
4062 
4063  return dwError;
4064 }
4065 
4066 
4067 /* Function 29 */
4068 DWORD
4069 WINAPI
4071  SC_RPC_HANDLE hService,
4072  LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4073  DWORD cbBufSize,
4075 {
4076  LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
4077  DWORD dwError = ERROR_SUCCESS;
4078  PSERVICE_HANDLE hSvc;
4079  PSERVICE lpService = NULL;
4080  HKEY hServiceKey = NULL;
4081  LPWSTR lpImagePath = NULL;
4082  LPWSTR lpServiceStartName = NULL;
4083  LPWSTR lpDependencies = NULL;
4084  DWORD dwDependenciesLength = 0;
4085  DWORD dwRequiredSize;
4086  LPSTR lpStr;
4087 
4088  DPRINT("RQueryServiceConfigA() called\n");
4089 
4090  if (ScmShutdown)
4092 
4093  hSvc = ScmGetServiceFromHandle(hService);
4094  if (hSvc == NULL)
4095  {
4096  DPRINT1("Invalid service handle!\n");
4097  return ERROR_INVALID_HANDLE;
4098  }
4099 
4102  {
4103  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4104  return ERROR_ACCESS_DENIED;
4105  }
4106 
4107  lpService = hSvc->ServiceEntry;
4108  if (lpService == NULL)
4109  {
4110  DPRINT("lpService == NULL!\n");
4111  return ERROR_INVALID_HANDLE;
4112  }
4113 
4114  /* Lock the service database shared */
4116 
4117  dwError = ScmOpenServiceKey(lpService->lpServiceName,
4118  KEY_READ,
4119  &hServiceKey);
4120  if (dwError != ERROR_SUCCESS)
4121  goto Done;
4122 
4123  /* Read the image path */
4124  dwError = ScmReadString(hServiceKey,
4125  L"ImagePath",
4126  &lpImagePath);
4127  if (dwError != ERROR_SUCCESS)
4128  goto Done;
4129 
4130  /* Read the service start name */
4131  ScmReadString(hServiceKey,
4132  L"ObjectName",
4133  &lpServiceStartName);
4134 
4135  /* Read the dependencies */
4136  ScmReadDependencies(hServiceKey,
4137  &lpDependencies,
4138  &dwDependenciesLength);
4139 
4140  dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA);
4141 
4142  if (lpImagePath != NULL)
4143  dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
4144  else
4145  dwRequiredSize += 2 * sizeof(CHAR);
4146 
4147  if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
4148  dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
4149  else
4150  dwRequiredSize += 2 * sizeof(CHAR);
4151 
4152  /* Add Dependencies length */
4153  if (lpDependencies != NULL)
4154  dwRequiredSize += dwDependenciesLength;
4155  else
4156  dwRequiredSize += 2 * sizeof(CHAR);
4157 
4158  if (lpServiceStartName != NULL)
4159  dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
4160  else
4161  dwRequiredSize += 2 * sizeof(CHAR);
4162 
4163  if (lpService->lpDisplayName != NULL)
4164  dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
4165  else
4166  dwRequiredSize += 2 * sizeof(CHAR);
4167 
4168  if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
4169  {
4170  dwError = ERROR_INSUFFICIENT_BUFFER;
4171  }
4172  else
4173  {
4174  lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
4175  lpServiceConfig->dwStartType = lpService->dwStartType;
4176  lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
4177  lpServiceConfig->dwTagId = lpService->dwTag;
4178 
4179  lpStr = (LPSTR)(lpServiceConfig + 1);
4180 
4181  /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4182  Verified in WINXP */
4183 
4184  if (lpImagePath)
4185  {
4187  0,
4188  lpImagePath,
4189  -1,
4190  lpStr,
4191  (int)(wcslen(lpImagePath) + 1),
4192  0,
4193  0);
4194  }
4195  else
4196  {
4197  *lpStr = 0;
4198  }
4199 
4200  lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4201  lpStr += (strlen((LPSTR)lpStr) + 1);
4202 
4203  if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4204  {
4206  0,
4207  lpService->lpGroup->lpGroupName,
4208  -1,
4209  lpStr,
4210  (int)(wcslen(lpService->lpGroup->lpGroupName) + 1),
4211  0,
4212  0);
4213  }
4214  else
4215  {
4216  *lpStr = 0;
4217  }
4218 
4219  lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4220  lpStr += (strlen(lpStr) + 1);
4221 
4222  /* Append Dependencies */
4223  if (lpDependencies)
4224  {
4226  0,
4227  lpDependencies,
4228  dwDependenciesLength,
4229  lpStr,
4230  dwDependenciesLength,
4231  0,
4232  0);
4233  }
4234  else
4235  {
4236  *lpStr = 0;
4237  }
4238 
4239  lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4240  if (lpDependencies)
4241  lpStr += dwDependenciesLength;
4242  else
4243  lpStr += (strlen(lpStr) + 1);
4244 
4245  if (lpServiceStartName)
4246  {
4248  0,
4249  lpServiceStartName,
4250  -1,
4251  lpStr,
4252  (int)(wcslen(lpServiceStartName) + 1),
4253  0,
4254  0);
4255  }
4256  else
4257  {
4258  *lpStr = 0;
4259  }
4260 
4261  lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4262  lpStr += (strlen(lpStr) + 1);
4263 
4264  if (lpService->lpDisplayName)
4265  {
4267  0,
4268  lpService->lpDisplayName,
4269  -1,
4270  lpStr,
4271  (int)(wcslen(lpService->lpDisplayName) + 1),
4272  0,
4273  0);
4274  }
4275  else
4276  {
4277  *lpStr = 0;
4278  }
4279 
4280  lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4281  }
4282 
4283  if (pcbBytesNeeded != NULL)
4284  *pcbBytesNeeded = dwRequiredSize;
4285 
4286 Done:
4287  /* Unlock the service database */
4289 
4290  if (lpImagePath != NULL)
4291  HeapFree(GetProcessHeap(), 0, lpImagePath);
4292 
4293  if (lpServiceStartName != NULL)
4294  HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4295 
4296  if (lpDependencies != NULL)
4297  HeapFree(GetProcessHeap(), 0, lpDependencies);
4298 
4299  if (hServiceKey != NULL)
4300  RegCloseKey(hServiceKey);
4301 
4302  DPRINT("RQueryServiceConfigA() done\n");
4303 
4304  return dwError;
4305 }
4306 
4307 
4308 /* Function 30 */
4309 DWORD
4310 WINAPI
4313  LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4314  DWORD cbBufSize,
4316 {
4318  PMANAGER_HANDLE hMgr;
4319  DWORD dwRequiredSize;
4320 
4321  if (!lpLockStatus || !pcbBytesNeeded)
4322  return ERROR_INVALID_PARAMETER;
4323 
4325  if (hMgr == NULL)
4326  {
4327  DPRINT1("Invalid service manager handle!\n");
4328  return ERROR_INVALID_HANDLE;
4329  }
4330 
4333  {
4334  DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
4335  return ERROR_ACCESS_DENIED;
4336  }
4337 
4338  /* FIXME: we need to compute instead the real length of the owner name */
4339  dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR);
4340  *pcbBytesNeeded = dwRequiredSize;
4341 
4342  if (cbBufSize < dwRequiredSize)
4344 
4345  ScmQueryServiceLockStatusA(lpLockStatus);
4346 
4347  return ERROR_SUCCESS;
4348 }
4349 
4350 
4351 /* Function 31 */
4352 DWORD
4353 WINAPI
4355  SC_RPC_HANDLE hService,
4356  DWORD argc,
4358 {
4359  DWORD dwError = ERROR_SUCCESS;
4360  PSERVICE_HANDLE hSvc;
4361  PSERVICE lpService = NULL;
4362  LPWSTR *lpVector = NULL;
4363  DWORD i;
4364  DWORD dwLength;
4365 
4366  DPRINT("RStartServiceA() called\n");
4367 
4368  if (ScmShutdown)
4370 
4371  hSvc = ScmGetServiceFromHandle(hService);
4372  if (hSvc == NULL)
4373  {
4374  DPRINT1("Invalid service handle!\n");
4375  return ERROR_INVALID_HANDLE;
4376  }
4377 
4379  SERVICE_START))
4380  {
4381  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4382  return ERROR_ACCESS_DENIED;
4383  }
4384 
4385  lpService = hSvc->ServiceEntry;
4386  if (lpService == NULL)
4387  {
4388  DPRINT("lpService == NULL!\n");
4389  return ERROR_INVALID_HANDLE;
4390  }
4391 
4392  if (lpService->dwStartType == SERVICE_DISABLED)
4393  return ERROR_SERVICE_DISABLED;
4394 
4395  if (lpService->bDeleted)
4397 
4398  /* Build a Unicode argument vector */
4399  if (argc > 0)
4400  {
4401  lpVector = HeapAlloc(GetProcessHeap(),
4403  argc * sizeof(LPWSTR));
4404  if (lpVector == NULL)
4405  return ERROR_NOT_ENOUGH_MEMORY;
4406 
4407  for (i = 0; i < argc; i++)
4408  {
4410  0,
4411  ((LPSTR*)argv)[i],
4412  -1,
4413  NULL,
4414  0);
4415 
4416  lpVector[i] = HeapAlloc(GetProcessHeap(),
4418  dwLength * sizeof(WCHAR));
4419  if (lpVector[i] == NULL)
4420  {
4421  dwError = ERROR_NOT_ENOUGH_MEMORY;
4422  goto done;
4423  }
4424 
4426  0,
4427  ((LPSTR*)argv)[i],
4428  -1,
4429  lpVector[i],
4430  dwLength);
4431  }
4432  }
4433 
4434  /* Start the service */
4435  dwError = ScmStartService(lpService, argc, lpVector);
4436 
4437 done:
4438  /* Free the Unicode argument vector */
4439  if (lpVector != NULL)
4440  {
4441  for (i = 0; i < argc; i++)
4442  {
4443  if (lpVector[i] != NULL)
4444  HeapFree(GetProcessHeap(), 0, lpVector[i]);
4445  }
4446  HeapFree(GetProcessHeap(), 0, lpVector);
4447  }
4448 
4449  return dwError;
4450 }
4451 
4452 
4453 /* Function 32 */
4454 DWORD
4455 WINAPI
4458  LPCSTR lpServiceName,
4460  LPBOUNDED_DWORD_4K lpcchBuffer)
4461 {
4462  // PMANAGER_HANDLE hManager;
4463  PSERVICE lpService = NULL;
4464  LPCWSTR lpSvcDisplayName;
4465  LPWSTR lpServiceNameW;
4466  DWORD dwLength;
4467 
4468  DPRINT("RGetServiceDisplayNameA() called\n");
4469  DPRINT("hSCManager = %p\n", hSCManager);
4470  DPRINT("lpServiceName: %s\n", lpServiceName);
4471  DPRINT("lpDisplayName: %p\n", lpDisplayName);
4472  DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4473 
4474 #if 0
4475  hManager = (PMANAGER_HANDLE)hSCManager;
4476  if (hManager->Handle.Tag != MANAGER_TAG)
4477  {
4478  DPRINT("Invalid manager handle!\n");
4479  return ERROR_INVALID_HANDLE;
4480  }
4481 #endif
4482 
4483  /* Get service database entry */
4484  if (lpServiceName != NULL)
4485  {
4486  dwLength = (DWORD)(strlen(lpServiceName) + 1);
4487  lpServiceNameW = HeapAlloc(GetProcessHeap(),
4489  dwLength * sizeof(WCHAR));
4490  if (!lpServiceNameW)
4491  return ERROR_NOT_ENOUGH_MEMORY;
4492 
4494  0,
4495  lpServiceName,
4496  -1,
4497  lpServiceNameW,
4498  dwLength);
4499 
4500  lpService = ScmGetServiceEntryByName(lpServiceNameW);
4501 
4502  HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4503  }
4504 
4505  if (lpService == NULL)
4506  {
4507  DPRINT("Could not find the service!\n");
4509  }
4510 
4511  if (lpService->lpDisplayName)
4512  lpSvcDisplayName = lpService->lpDisplayName;
4513  else
4514  lpSvcDisplayName = lpService->lpServiceName;
4515 
4516  /*
4517  * NOTE: On Windows the comparison on *lpcchBuffer is made against
4518  * the number of (wide) characters of the UNICODE display name, and
4519  * not against the number of bytes needed to store the ANSI string.
4520  */
4521  dwLength = (DWORD)wcslen(lpSvcDisplayName);
4522 
4523  if (*lpcchBuffer > dwLength)
4524  {
4525  if (lpDisplayName != NULL &&
4527  0,
4528  lpSvcDisplayName,
4529  -1,
4530  lpDisplayName,
4531  (int)*lpcchBuffer,
4532  NULL,
4533  NULL) == 0)
4534  {
4535  /*
4536  * But then, if *lpcchBuffer was greater than the number of
4537  * (wide) characters of the UNICODE display name, yet smaller
4538  * than the number of bytes needed due to the possible presence
4539  * of DBCS characters, the *exact* number of bytes is returned
4540  * (without the NULL terminator).
4541  */
4543  0,
4544  lpSvcDisplayName,
4545  (int)dwLength,
4546  NULL,
4547  0,
4548  NULL,
4549  NULL);
4550  *lpDisplayName = 0;
4551  *lpcchBuffer = dwLength;
4553  }
4554 
4555  /*
4556  * NOTE: On Windows, RGetServiceDisplayNameA() does not update
4557  * *lpcchBuffer on success, contrary to RGetServiceDisplayNameW().
4558  */
4559  return ERROR_SUCCESS;
4560  }
4561  else
4562  {
4563  /*
4564  * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4565  * (wide) characters of the UNICODE display name, only an upper
4566  * estimation is returned by doubling the string length, to account
4567  * for the presence of any possible DBCS characters.
4568  */
4569  *lpcchBuffer = dwLength * sizeof(WCHAR);
4571  }
4572 }
4573 
4574 
4575 /* Function 33 */
4576 DWORD
4577 WINAPI
4581  LPSTR lpServiceName,
4582  LPBOUNDED_DWORD_4K lpcchBuffer)
4583 {
4584  // PMANAGER_HANDLE hManager;
4585  PSERVICE lpService;
4586  LPWSTR lpDisplayNameW;
4587  DWORD dwLength;
4588 
4589  DPRINT("RGetServiceKeyNameA() called\n");
4590  DPRINT("hSCManager = %p\n", hSCManager);
4591  DPRINT("lpDisplayName: %s\n", lpDisplayName);
4592  DPRINT("lpServiceName: %p\n", lpServiceName);
4593  DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4594 
4595 #if 0
4596  hManager = (PMANAGER_HANDLE)hSCManager;
4597  if (hManager->Handle.Tag != MANAGER_TAG)
4598  {
4599  DPRINT("Invalid manager handle!\n");
4600  return ERROR_INVALID_HANDLE;
4601  }
4602 #endif
4603 
4604  /* Get service database entry */
4605 
4606  dwLength = (DWORD)(strlen(lpDisplayName) + 1);
4607  lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4609  dwLength * sizeof(WCHAR));
4610  if (!lpDisplayNameW)
4611  return ERROR_NOT_ENOUGH_MEMORY;
4612 
4614  0,
4615  lpDisplayName,
4616  -1,
4617  lpDisplayNameW,
4618  dwLength);
4619 
4620  lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4621 
4622  HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4623 
4624  if (lpService == NULL)
4625  {
4626  DPRINT("Could not find the service!\n");
4628  }
4629 
4630  /*
4631  * NOTE: On Windows the comparison on *lpcchBuffer is made against
4632  * the number of (wide) characters of the UNICODE service name, and
4633  * not against the number of bytes needed to store the ANSI string.
4634  */
4635  dwLength = (DWORD)wcslen(lpService->lpServiceName);
4636 
4637  if (*lpcchBuffer > dwLength)
4638  {
4639  if (lpServiceName != NULL &&
4641  0,
4642  lpService->lpServiceName,
4643  -1,
4644  lpServiceName,
4645  (int)*lpcchBuffer,
4646  NULL,
4647  NULL) == 0)
4648  {
4649  /*
4650  * But then, if *lpcchBuffer was greater than the number of
4651  * (wide) characters of the UNICODE service name, yet smaller
4652  * than the number of bytes needed due to the possible presence
4653  * of DBCS characters, the *exact* number of bytes is returned
4654  * (without the NULL terminator).
4655  */
4657  0,
4658  lpService->lpServiceName,
4659  (int)dwLength,
4660  NULL,
4661  0,
4662  NULL,
4663  NULL);
4664  *lpServiceName = 0;
4665  *lpcchBuffer = dwLength;
4667  }
4668 
4669  /*
4670  * NOTE: On Windows, RGetServiceKeyNameA() does not update
4671  * *lpcchBuffer on success, contrary to RGetServiceKeyNameW().
4672  */
4673  return ERROR_SUCCESS;
4674  }
4675  else
4676  {
4677  /*
4678  * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4679  * (wide) characters of the UNICODE service name, only an upper
4680  * estimation is returned by doubling the string length, to account
4681  * for the presence of any possible DBCS characters.
4682  */
4683  *lpcchBuffer = dwLength * sizeof(WCHAR);
4685  }
4686 }
4687 
4688 
4689 /* Function 34 */
4690 DWORD
4691 WINAPI
4694  LPWSTR lpLoadOrderGroup,
4695  LPDWORD lpState)
4696 {
4697  PMANAGER_HANDLE hManager;
4698  PSERVICE_GROUP pServiceGroup;
4699  DWORD dwError = ERROR_SUCCESS;
4700 
4701  DPRINT("RI_ScGetCurrentGroupStateW() called\n");
4702 
4703  if (ScmShutdown)
4705 
4707  if (hManager == NULL)
4708  {
4709  DPRINT1("Invalid service manager handle!\n");
4710  return ERROR_INVALID_HANDLE;
4711  }
4712 
4713  /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */
4716  {
4717  DPRINT("Insufficient access rights! 0x%lx\n",
4718  hManager->Handle.DesiredAccess);
4719  return ERROR_ACCESS_DENIED;
4720  }
4721 
4722  /* Lock the service database shared */
4724 
4725  /* Get the group list entry */
4726  pServiceGroup = ScmGetServiceGroupByName(lpLoadOrderGroup);
4727  if (pServiceGroup == NULL)
4728  {
4729  dwError = ERROR_SERVICE_DOES_NOT_EXIST;
4730  goto done;
4731  }
4732 
4733  /* FIXME: Return the group state */
4734  *lpState = 0;
4735 
4736 done:
4737  /* Unlock the service database */
4739 
4740  DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError);
4741 
4742  return dwError;
4743 }
4744 
4745 
4746 /* Function 35 */
4747 DWORD
4748 WINAPI
4751  DWORD dwServiceType,
4752  DWORD dwServiceState,
4753  LPBYTE lpBuffer,
4754  DWORD cbBufSize,
4756  LPBOUNDED_DWORD_256K lpServicesReturned,
4757  LPBOUNDED_DWORD_256K lpResumeIndex,
4758  LPCWSTR pszGroupName)
4759 {
4760  PMANAGER_HANDLE hManager;
4761  PSERVICE lpService;
4762  DWORD dwError = ERROR_SUCCESS;
4763  PLIST_ENTRY ServiceEntry;
4764  PSERVICE CurrentService;
4765  DWORD dwState;
4766  DWORD dwRequiredSize;
4767  DWORD dwServiceCount;
4768  DWORD dwSize;
4769  DWORD dwLastResumeCount = 0;
4770  LPENUM_SERVICE_STATUSW lpStatusPtr;
4771  LPWSTR lpStringPtr;
4772 
4773  DPRINT("REnumServiceGroupW() called\n");
4774 
4775  if (ScmShutdown)
4777 
4779  if (hManager == NULL)
4780  {
4781  DPRINT1("Invalid service manager handle!\n");
4782  return ERROR_INVALID_HANDLE;
4783  }
4784 
4785  if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
4786  {
4787  return ERROR_INVALID_ADDRESS;
4788  }
4789 
4790  *pcbBytesNeeded = 0;
4791  *lpServicesReturned = 0;
4792 
4793  if ((dwServiceType == 0) ||
4794  ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
4795  {
4796  DPRINT("Not a valid Service Type!\n");
4797  return ERROR_INVALID_PARAMETER;
4798  }
4799 
4800  if ((dwServiceState == 0) ||
4801  ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
4802  {
4803  DPRINT("Not a valid Service State!\n");
4804  return ERROR_INVALID_PARAMETER;
4805  }
4806 
4807  /* Check access rights */
4810  {
4811  DPRINT("Insufficient access rights! 0x%lx\n",
4812  hManager->Handle.DesiredAccess);
4813  return ERROR_ACCESS_DENIED;
4814  }
4815 
4816  if (lpResumeIndex)
4817  dwLastResumeCount = *lpResumeIndex;
4818 
4819  /* Lock the service database shared */
4821 
4822  lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4823  if (lpService == NULL)
4824  {
4825  dwError = ERROR_SUCCESS;
4826  goto Done;
4827  }
4828 
4829  dwRequiredSize = 0;
4830  dwServiceCount = 0;
4831 
4832  for (ServiceEntry = &lpService->ServiceListEntry;
4833  ServiceEntry != &ServiceListHead;
4834  ServiceEntry = ServiceEntry->Flink)
4835  {
4836  CurrentService = CONTAINING_RECORD(ServiceEntry,
4837  SERVICE,
4838  ServiceListEntry);
4839 
4840  if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4841  continue;
4842 
4843  dwState = SERVICE_ACTIVE;
4844  if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4845  dwState = SERVICE_INACTIVE;
4846 
4847  if ((dwState & dwServiceState) == 0)
4848  continue;
4849 
4850  if (pszGroupName)
4851  {
4852  if (*pszGroupName == 0)
4853  {
4854  if (CurrentService->lpGroup != NULL)
4855  continue;
4856  }
4857  else
4858  {
4859  if ((CurrentService->lpGroup == NULL) ||
4860  _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4861  continue;
4862  }
4863  }
4864 
4865  dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4866  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4867  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4868 
4869  if (dwRequiredSize + dwSize > cbBufSize)
4870  {
4871  DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4872  break;
4873  }
4874 
4875  DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4876  dwRequiredSize += dwSize;
4877  dwServiceCount++;
4878  dwLastResumeCount = CurrentService->dwResumeCount;
4879  }
4880 
4881  DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4882  DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4883 
4884  for (;
4885  ServiceEntry != &ServiceListHead;
4886  ServiceEntry = ServiceEntry->Flink)
4887  {
4888  CurrentService = CONTAINING_RECORD(ServiceEntry,
4889  SERVICE,
4890  ServiceListEntry);
4891 
4892  if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4893  continue;
4894 
4895  dwState = SERVICE_ACTIVE;
4896  if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4897  dwState = SERVICE_INACTIVE;
4898 
4899  if ((dwState & dwServiceState) == 0)
4900  continue;
4901 
4902  if (pszGroupName)
4903  {
4904  if (*pszGroupName == 0)
4905  {
4906  if (CurrentService->lpGroup != NULL)
4907  continue;
4908  }
4909  else
4910  {
4911  if ((CurrentService->lpGroup == NULL) ||
4912  _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4913  continue;
4914  }
4915  }
4916 
4917  dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
4918  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4919  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4920 
4921  dwError = ERROR_MORE_DATA;
4922  }
4923 
4924  DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4925 
4926  if (lpResumeIndex)
4927  *lpResumeIndex = dwLastResumeCount;
4928 
4929  *lpServicesReturned = dwServiceCount;
4930  *pcbBytesNeeded = dwRequiredSize;
4931 
4932  lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
4933  lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
4934  dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
4935 
4936  dwRequiredSize = 0;
4937  for (ServiceEntry = &lpService->ServiceListEntry;
4938  ServiceEntry != &ServiceListHead;
4939  ServiceEntry = ServiceEntry->Flink)
4940  {
4941  CurrentService = CONTAINING_RECORD(ServiceEntry,
4942  SERVICE,
4943  ServiceListEntry);
4944 
4945  if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4946  continue;
4947 
4948  dwState = SERVICE_ACTIVE;
4949  if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4950  dwState = SERVICE_INACTIVE;
4951 
4952  if ((dwState & dwServiceState) == 0)
4953  continue;
4954 
4955  if (pszGroupName)
4956  {
4957  if (*pszGroupName == 0)
4958  {
4959  if (CurrentService->lpGroup != NULL)
4960  continue;
4961  }
4962  else
4963  {
4964  if ((CurrentService->lpGroup == NULL) ||
4965  _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4966  continue;
4967  }
4968  }
4969 
4970  dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4971  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4972  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4973 
4974  if (dwRequiredSize + dwSize > cbBufSize)
4975  break;
4976 
4977  /* Copy the service name */
4978  wcscpy(lpStringPtr, CurrentService->lpServiceName);
4979  lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4980  lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
4981 
4982  /* Copy the display name */
4983  wcscpy(lpStringPtr, CurrentService->lpDisplayName);
4984  lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4985  lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
4986 
4987  /* Copy the status information */
4988  memcpy(&lpStatusPtr->ServiceStatus,
4989  &CurrentService->Status,
4990  sizeof(SERVICE_STATUS));
4991 
4992  lpStatusPtr++;
4993  dwRequiredSize += dwSize;
4994  }
4995 
4996  if (dwError == ERROR_SUCCESS)
4997  {
4998  *pcbBytesNeeded = 0;
4999  if (lpResumeIndex) *lpResumeIndex = 0;
5000  }
5001 
5002 Done:
5003  /* Unlock the service database */
5005 
5006  DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError);
5007 
5008  return dwError;
5009 }
5010 
5011 
5012 /* Function 36 */
5013 DWORD
5014 WINAPI
5016  SC_RPC_HANDLE hService,
5018 {
5019  SC_RPC_CONFIG_INFOW InfoW = { 0 };
5020  DWORD dwRet, dwLength;
5021  PVOID ptr = NULL;
5022 
5023  DPRINT("RChangeServiceConfig2A() called\n");
5024  DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
5025 
5026  if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
5027  (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
5028  {
5029  return ERROR_INVALID_LEVEL;
5030  }
5031 
5032  InfoW.dwInfoLevel = Info.dwInfoLevel;
5033 
5035  {
5036  LPSERVICE_DESCRIPTIONW lpServiceDescriptionW;
5037  LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
5038 
5039  lpServiceDescriptionA = Info.psd;
5040 
5041  if (lpServiceDescriptionA &&
5042  lpServiceDescriptionA->lpDescription)
5043  {
5044  dwLength = (DWORD)((strlen(lpServiceDescriptionA->lpDescription) + 1) * sizeof(WCHAR));
5045 
5046  lpServiceDescriptionW = HeapAlloc(GetProcessHeap(),
5048  dwLength + sizeof(SERVICE_DESCRIPTIONW));
5049  if (!lpServiceDescriptionW)
5050  {
5051  return ERROR_NOT_ENOUGH_MEMORY;
5052  }
5053 
5054  lpServiceDescriptionW->lpDescription = (LPWSTR)(lpServiceDescriptionW + 1);
5055 
5057  0,
5058  lpServiceDescriptionA->lpDescription,
5059  -1,
5060  lpServiceDescriptionW->lpDescription,
5061  dwLength);
5062 
5063  ptr = lpServiceDescriptionW;
5064  InfoW.psd = lpServiceDescriptionW;
5065  }
5066  }
5067  else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5068  {
5069  LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
5070  LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
5071  DWORD dwRebootLen = 0;
5072  DWORD dwCommandLen = 0;
5073  DWORD dwActionArrayLen = 0;
5074  LPWSTR lpStr = NULL;
5075 
5076  lpServiceFailureActionsA = Info.psfa;
5077 
5078  if (lpServiceFailureActionsA)
5079  {
5080  /*
5081  * The following code is inspired by the
5082  * SERVICE_CONFIG_FAILURE_ACTIONS case of
5083  * the RQueryServiceConfig2W function.
5084  */
5085 
5086  /* Retrieve the needed length for the two data strings */
5087  if (lpServiceFailureActionsA->lpRebootMsg)
5088  {
5089  dwRebootLen = (DWORD)((strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR));
5090  }
5091  if (lpServiceFailureActionsA->lpCommand)
5092  {
5093  dwCommandLen = (DWORD)((strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR));
5094  }
5095 
5096  /*
5097  * Retrieve the size of the lpsaActions array if needed.
5098  * We will copy the lpsaActions array only if there is at
5099  * least one action AND that the original array is valid.
5100  */
5101  if (lpServiceFailureActionsA->cActions > 0 && lpServiceFailureActionsA->lpsaActions)
5102  {
5103  dwActionArrayLen = lpServiceFailureActionsA->cActions * sizeof(SC_ACTION);
5104  }
5105 
5106  /* Compute the total length for the UNICODE structure, including data */
5108  dwActionArrayLen + dwRebootLen + dwCommandLen;
5109 
5110  /* Allocate the structure */
5111  lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
5113  dwLength);
5114  if (!lpServiceFailureActionsW)
5115  {
5116  return ERROR_NOT_ENOUGH_MEMORY;
5117  }
5118 
5119  /* Copy the members */
5120  lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
5121  lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
5122 
5123  /* Copy the lpsaActions array if needed */
5124  if (dwActionArrayLen > 0)
5125  {
5126  /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
5127  lpServiceFailureActionsW->lpsaActions = (LPSC_ACTION)((ULONG_PTR)(lpServiceFailureActionsW + 1));
5128 
5129  /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
5130  RtlCopyMemory(lpServiceFailureActionsW->lpsaActions,
5131  lpServiceFailureActionsA->lpsaActions,
5132  dwActionArrayLen);
5133  }
5134  else
5135  {
5136  /* No lpsaActions array */
5137  lpServiceFailureActionsW->lpsaActions = NULL;
5138  }
5139  /* The data strings are stored just after the lpsaActions array */
5140  lpStr = (LPWSTR)((ULONG_PTR)(lpServiceFailureActionsW + 1) + dwActionArrayLen);
5141 
5142  /*
5143  * Convert the data strings to UNICODE
5144  */
5145 
5146  lpServiceFailureActionsW->lpRebootMsg = NULL;
5147  lpServiceFailureActionsW->lpCommand = NULL;
5148 
5149  if (dwRebootLen)
5150  {
5151  /* lpRebootMsg points just after the lpsaActions array */
5152  lpServiceFailureActionsW->lpRebootMsg = lpStr;
5153 
5155  0,
5156  lpServiceFailureActionsA->lpRebootMsg,
5157  -1,
5158  lpServiceFailureActionsW->lpRebootMsg,
5159  dwRebootLen);
5160 
5161  lpStr += dwRebootLen / sizeof(WCHAR);
5162  }
5163 
5164  if (dwCommandLen)
5165  {
5166  /* lpRebootMsg points just after the lpRebootMsg data string */
5167  lpServiceFailureActionsW->lpCommand = lpStr;
5168 
5170  0,
5171  lpServiceFailureActionsA->lpCommand,
5172  -1,
5173  lpServiceFailureActionsW->lpCommand,
5174  dwCommandLen);
5175  }
5176 
5177  /* Set the pointers */
5178  ptr = lpServiceFailureActionsW;
5179  InfoW.psfa = lpServiceFailureActionsW;
5180  }
5181  }
5182 
5183  dwRet = RChangeServiceConfig2W(hService, InfoW);
5184 
5185  HeapFree(GetProcessHeap(), 0, ptr);
5186 
5187  return dwRet;
5188 }
5189 
5190 
5191 static DWORD
5193  LPSERVICE_FAILURE_ACTIONSW lpFailureActions)
5194 {
5195  LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL;
5196  LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL;
5197  DWORD dwRequiredSize = 0;
5198  DWORD dwType = 0;
5199  DWORD dwError;
5200 
5201  /* There is nothing to be done if we have no failure actions */
5202  if (lpFailureActions == NULL)
5203  return ERROR_SUCCESS;
5204 
5205  /*
5206  * 1- Retrieve the original value of FailureActions.
5207  */
5208 
5209  /* Query value length */
5210  dwError = RegQueryValueExW(hServiceKey,
5211  L"FailureActions",
5212  NULL,
5213  &dwType,
5214  NULL,
5215  &dwRequiredSize);
5216  if (dwError != ERROR_SUCCESS &&
5217  dwError != ERROR_MORE_DATA &&
5218  dwError != ERROR_FILE_NOT_FOUND)
5219  {
5220  return dwError;
5221  }
5222 
5223  dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
5224  : sizeof(SERVICE_FAILURE_ACTIONSW);
5225 
5226  /* Initialize the read buffer */
5227  lpReadBuffer = HeapAlloc(GetProcessHeap(),
5229  dwRequiredSize);
5230  if (lpReadBuffer == NULL)
5231  return ERROR_NOT_ENOUGH_MEMORY;
5232 
5233  /* Now we can fill the read buffer */
5234  if (dwError != ERROR_FILE_NOT_FOUND &&
5235  dwType == REG_BINARY)
5236  {
5237  dwError = RegQueryValueExW(hServiceKey,
5238  L"FailureActions",
5239  NULL,
5240  NULL,
5241  (LPBYTE)lpReadBuffer,
5242  &dwRequiredSize);
5243  if (dwError != ERROR_SUCCESS &&
5244  dwError != ERROR_FILE_NOT_FOUND)
5245  goto done;
5246 
5247  if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
5248  dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5249  }
5250  else
5251  {
5252  /*
5253  * The value of the error doesn't really matter, the only
5254  * important thing is that it must be != ERROR_SUCCESS.
5255  */
5256  dwError = ERROR_INVALID_DATA;
5257  }
5258 
5259  if (dwError == ERROR_SUCCESS)
5260  {
5261  lpReadBuffer->cActions = min(lpReadBuffer->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
5262  lpReadBuffer->lpsaActions = (lpReadBuffer->cActions > 0 ? (LPSC_ACTION)(lpReadBuffer + 1) : NULL);
5263  }
5264  else
5265  {
5266  lpReadBuffer->dwResetPeriod = 0;
5267  lpReadBuffer->cActions = 0;
5268  lpReadBuffer->lpsaActions = NULL;
5269  }
5270 
5271  lpReadBuffer->lpRebootMsg = NULL;
5272  lpReadBuffer->lpCommand = NULL;
5273 
5274  /*
5275  * 2- Initialize the new value to set.
5276  */
5277 
5278  dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5279 
5280  if (lpFailureActions->lpsaActions == NULL)
5281  {
5282  /*
5283  * lpFailureActions->cActions is ignored.
5284  * Therefore we use the original values
5285  * of cActions and lpsaActions.
5286  */
5287  dwRequiredSize += lpReadBuffer->cActions * sizeof(SC_ACTION);
5288  }
5289  else
5290  {
5291  /*
5292  * The reset period and array of failure actions
5293  * are deleted if lpFailureActions->cActions == 0 .
5294  */
5295  dwRequiredSize += lpFailureActions->cActions * sizeof(SC_ACTION);
5296  }
5297 
5298  lpWriteBuffer = HeapAlloc(GetProcessHeap(),
5300  dwRequiredSize);
5301  if (lpWriteBuffer == NULL)
5302  {
5303  dwError = ERROR_NOT_ENOUGH_MEMORY;
5304  goto done;
5305  }
5306 
5307  /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5308  lpWriteBuffer->lpRebootMsg = NULL;
5309  lpWriteBuffer->lpCommand = NULL;
5310  lpWriteBuffer->lpsaActions = NULL;
5311 
5312  /* Set the members */
5313  if (lpFailureActions->lpsaActions == NULL)
5314  {
5315  /*
5316  * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5317  * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5318  */
5319  lpWriteBuffer->dwResetPeriod = lpReadBuffer->dwResetPeriod;
5320  lpWriteBuffer->cActions = lpReadBuffer->cActions;
5321 
5322  if (lpReadBuffer->