ReactOS  0.4.13-dev-79-gcd489d8
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  DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1852  return ERROR_SUCCESS;
1853 
1854 // UNIMPLEMENTED;
1855 // return ERROR_CALL_NOT_IMPLEMENTED;
1856 }
1857 
1858 
1859 /* Function 10 */
1860 DWORD
1861 WINAPI
1865  int bSetBitsOn,
1866  int bUpdateImmediately,
1867  wchar_t *lpString)
1868 {
1869  PSERVICE pService;
1870 
1871  DPRINT("RI_ScSetServiceBitsW(%p %lx %d %d %S)\n",
1872  hServiceStatus, dwServiceBits, bSetBitsOn,
1873  bUpdateImmediately, lpString);
1874 
1875  if (ScmShutdown)
1877 
1878  if (lpString != NULL)
1879  return ERROR_INVALID_PARAMETER;
1880 
1881  if (hServiceStatus == 0)
1882  {
1883  DPRINT("hServiceStatus == NULL!\n");
1884  return ERROR_INVALID_HANDLE;
1885  }
1886 
1887  // FIXME: Validate the status handle
1888  pService = (PSERVICE)hServiceStatus;
1889 
1890  if (bSetBitsOn)
1891  {
1892  DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1893  DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1894  pService->dwServiceBits |= dwServiceBits;
1896  DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1897  DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1898  }
1899  else
1900  {
1901  DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1902  DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1903  pService->dwServiceBits &= ~dwServiceBits;
1905  DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1906  DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1907  }
1908 
1909  return ERROR_SUCCESS;
1910 }
1911 
1912 
1913 /* Function 11 */
1914 DWORD
1915 WINAPI
1917  SC_RPC_HANDLE hService,
1918  DWORD dwServiceType,
1919  DWORD dwStartType,
1920  DWORD dwErrorControl,
1921  LPWSTR lpBinaryPathName,
1922  LPWSTR lpLoadOrderGroup,
1923  LPDWORD lpdwTagId,
1924  LPBYTE lpDependencies,
1925  DWORD dwDependSize,
1926  LPWSTR lpServiceStartName,
1927  LPBYTE lpPassword,
1928  DWORD dwPwSize,
1930 {
1931  DWORD dwError = ERROR_SUCCESS;
1932  PSERVICE_HANDLE hSvc;
1933  PSERVICE lpService = NULL;
1934  HKEY hServiceKey = NULL;
1935  LPWSTR lpDisplayNameW = NULL;
1936  LPWSTR lpImagePathW = NULL;
1937  LPWSTR lpClearTextPassword = NULL;
1938 
1939  DPRINT("RChangeServiceConfigW() called\n");
1940  DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1941  DPRINT("dwStartType = %lu\n", dwStartType);
1942  DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1943  DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1944  DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1945  DPRINT("lpServiceStartName = %S\n", lpServiceStartName);
1946  DPRINT("lpPassword = %p\n", lpPassword);
1947  DPRINT("dwPwSite = %lu\n", dwPwSize);
1948  DPRINT("lpDisplayName = %S\n", lpDisplayName);
1949 
1950  if (ScmShutdown)
1952 
1953  hSvc = ScmGetServiceFromHandle(hService);
1954  if (hSvc == NULL)
1955  {
1956  DPRINT1("Invalid service handle!\n");
1957  return ERROR_INVALID_HANDLE;
1958  }
1959 
1962  {
1963  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1964  return ERROR_ACCESS_DENIED;
1965  }
1966 
1967  /* Check for invalid service type value */
1968  if ((dwServiceType != SERVICE_NO_CHANGE) &&
1969  (dwServiceType != SERVICE_KERNEL_DRIVER) &&
1970  (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
1971  ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
1973  {
1974  return ERROR_INVALID_PARAMETER;
1975  }
1976 
1977  /* Check for invalid start type value */
1978  if ((dwStartType != SERVICE_NO_CHANGE) &&
1979  (dwStartType != SERVICE_BOOT_START) &&
1980  (dwStartType != SERVICE_SYSTEM_START) &&
1981  (dwStartType != SERVICE_AUTO_START) &&
1982  (dwStartType != SERVICE_DEMAND_START) &&
1983  (dwStartType != SERVICE_DISABLED))
1984  {
1985  return ERROR_INVALID_PARAMETER;
1986  }
1987 
1988  /* Only drivers can be boot start or system start services */
1989  if ((dwStartType == SERVICE_BOOT_START) ||
1990  (dwStartType == SERVICE_SYSTEM_START))
1991  {
1992  if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
1993  (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
1994  return ERROR_INVALID_PARAMETER;
1995  }
1996 
1997  /* Check for invalid error control value */
1998  if ((dwErrorControl != SERVICE_NO_CHANGE) &&
1999  (dwErrorControl != SERVICE_ERROR_IGNORE) &&
2000  (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2001  (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2002  (dwErrorControl != SERVICE_ERROR_CRITICAL))
2003  {
2004  return ERROR_INVALID_PARAMETER;
2005  }
2006 
2007  if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2008  {
2009  return ERROR_INVALID_PARAMETER;
2010  }
2011 
2012  lpService = hSvc->ServiceEntry;
2013  if (lpService == NULL)
2014  {
2015  DPRINT("lpService == NULL!\n");
2016  return ERROR_INVALID_HANDLE;
2017  }
2018 
2019  /* Lock the service database exclusively */
2021 
2022  if (lpService->bDeleted)
2023  {
2024  DPRINT("The service has already been marked for delete!\n");
2026  goto done;
2027  }
2028 
2029  /* Open the service key */
2030  dwError = ScmOpenServiceKey(lpService->szServiceName,
2031  KEY_SET_VALUE,
2032  &hServiceKey);
2033  if (dwError != ERROR_SUCCESS)
2034  goto done;
2035 
2036  /* Write service data to the registry */
2037 
2038  /* Set the display name */
2039  if (lpDisplayName != NULL && *lpDisplayName != 0)
2040  {
2041  RegSetValueExW(hServiceKey,
2042  L"DisplayName",
2043  0,
2044  REG_SZ,
2046  (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2047 
2048  /* Update the display name */
2049  lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2051  (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2052  if (lpDisplayNameW == NULL)
2053  {
2054  dwError = ERROR_NOT_ENOUGH_MEMORY;
2055  goto done;
2056  }
2057 
2058  wcscpy(lpDisplayNameW, lpDisplayName);
2059  if (lpService->lpDisplayName != lpService->lpServiceName)
2060  HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2061 
2062  lpService->lpDisplayName = lpDisplayNameW;
2063  }
2064 
2065  if (dwServiceType != SERVICE_NO_CHANGE)
2066  {
2067  /* Set the service type */
2068  dwError = RegSetValueExW(hServiceKey,
2069  L"Type",
2070  0,
2071  REG_DWORD,
2072  (LPBYTE)&dwServiceType,
2073  sizeof(DWORD));
2074  if (dwError != ERROR_SUCCESS)
2075  goto done;
2076 
2077  lpService->Status.dwServiceType = dwServiceType;
2078  }
2079 
2080  if (dwStartType != SERVICE_NO_CHANGE)
2081  {
2082  /* Set the start value */
2083  dwError = RegSetValueExW(hServiceKey,
2084  L"Start",
2085  0,
2086  REG_DWORD,
2087  (LPBYTE)&dwStartType,
2088  sizeof(DWORD));
2089  if (dwError != ERROR_SUCCESS)
2090  goto done;
2091 
2092  lpService->dwStartType = dwStartType;
2093  }
2094 
2095  if (dwErrorControl != SERVICE_NO_CHANGE)
2096  {
2097  /* Set the error control value */
2098  dwError = RegSetValueExW(hServiceKey,
2099  L"ErrorControl",
2100  0,
2101  REG_DWORD,
2102  (LPBYTE)&dwErrorControl,
2103  sizeof(DWORD));
2104  if (dwError != ERROR_SUCCESS)
2105  goto done;
2106 
2107  lpService->dwErrorControl = dwErrorControl;
2108  }
2109 
2110  if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2111  {
2112  /* Set the image path */
2113  lpImagePathW = lpBinaryPathName;
2114 
2115  if (lpService->Status.dwServiceType & SERVICE_DRIVER)
2116  {
2117  dwError = ScmCanonDriverImagePath(lpService->dwStartType,
2118  lpBinaryPathName,
2119  &lpImagePathW);
2120 
2121  if (dwError != ERROR_SUCCESS)
2122  goto done;
2123  }
2124 
2125  dwError = RegSetValueExW(hServiceKey,
2126  L"ImagePath",
2127  0,
2128  REG_EXPAND_SZ,
2129  (LPBYTE)lpImagePathW,
2130  (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
2131 
2132  if (lpImagePathW != lpBinaryPathName)
2133  HeapFree(GetProcessHeap(), 0, lpImagePathW);
2134 
2135  if (dwError != ERROR_SUCCESS)
2136  goto done;
2137  }
2138 
2139  /* Set the group name */
2140  if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2141  {
2142  dwError = RegSetValueExW(hServiceKey,
2143  L"Group",
2144  0,
2145  REG_SZ,
2146  (LPBYTE)lpLoadOrderGroup,
2147  (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2148  if (dwError != ERROR_SUCCESS)
2149  goto done;
2150 
2151  dwError = ScmSetServiceGroup(lpService,
2152  lpLoadOrderGroup);
2153  if (dwError != ERROR_SUCCESS)
2154  goto done;
2155  }
2156 
2157  /* Set the tag */
2158  if (lpdwTagId != NULL)
2159  {
2160  dwError = ScmAssignNewTag(lpService);
2161  if (dwError != ERROR_SUCCESS)
2162  goto done;
2163 
2164  dwError = RegSetValueExW(hServiceKey,
2165  L"Tag",
2166  0,
2167  REG_DWORD,
2168  (LPBYTE)&lpService->dwTag,
2169  sizeof(DWORD));
2170  if (dwError != ERROR_SUCCESS)
2171  goto done;
2172 
2173  *lpdwTagId = lpService->dwTag;
2174  }
2175 
2176  /* Write dependencies */
2177  if (lpDependencies != NULL && *lpDependencies != 0)
2178  {
2179  dwError = ScmWriteDependencies(hServiceKey,
2180  (LPWSTR)lpDependencies,
2181  dwDependSize);
2182  if (dwError != ERROR_SUCCESS)
2183  goto done;
2184  }
2185 
2186  /* Start name and password are only used by Win32 services */
2187  if (lpService->Status.dwServiceType & SERVICE_WIN32)
2188  {
2189  /* Write service start name */
2190  if (lpServiceStartName != NULL && *lpServiceStartName != 0)
2191  {
2192  dwError = RegSetValueExW(hServiceKey,
2193  L"ObjectName",
2194  0,
2195  REG_SZ,
2196  (LPBYTE)lpServiceStartName,
2197  (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)));
2198  if (dwError != ERROR_SUCCESS)
2199  goto done;
2200  }
2201 
2202  if (lpPassword != NULL)
2203  {
2204  if (*(LPWSTR)lpPassword != 0)
2205  {
2206  /* Decrypt the password */
2207  dwError = ScmDecryptPassword(lpPassword,
2208  dwPwSize,
2209  &lpClearTextPassword);
2210  if (dwError != ERROR_SUCCESS)
2211  {
2212  DPRINT1("ScmDecryptPassword failed (Error %lu)\n", dwError);
2213  goto done;
2214  }
2215  DPRINT1("Clear text password: %S\n", lpClearTextPassword);
2216 
2217  /* Write the password */
2218  dwError = ScmSetServicePassword(lpService->szServiceName,
2219  lpClearTextPassword);
2220  if (dwError != ERROR_SUCCESS)
2221  {
2222  DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2223  goto done;
2224  }
2225  }
2226  else
2227  {
2228  /* Delete the password */
2229  dwError = ScmSetServicePassword(lpService->szServiceName,
2230  NULL);
2231  if (dwError == ERROR_FILE_NOT_FOUND)
2232  dwError = ERROR_SUCCESS;
2233 
2234  if (dwError != ERROR_SUCCESS)
2235  {
2236  DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2237  goto done;
2238  }
2239  }
2240  }
2241  }
2242 
2243 done:
2244  if (lpClearTextPassword != NULL)
2245  {
2246  /* Wipe and release the password buffer */
2247  SecureZeroMemory(lpClearTextPassword,
2248  (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2249  HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2250  }
2251 
2252  if (hServiceKey != NULL)
2253  RegCloseKey(hServiceKey);
2254 
2255  /* Unlock the service database */
2257 
2258  DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2259 
2260  return dwError;
2261 }
2262 
2263 
2264 /* Function 12 */
2265 DWORD
2266 WINAPI
2269  LPCWSTR lpServiceName,
2271  DWORD dwDesiredAccess,
2272  DWORD dwServiceType,
2273  DWORD dwStartType,
2274  DWORD dwErrorControl,
2275  LPCWSTR lpBinaryPathName,
2276  LPCWSTR lpLoadOrderGroup,
2277  LPDWORD lpdwTagId,
2278  LPBYTE lpDependencies,
2279  DWORD dwDependSize,
2280  LPCWSTR lpServiceStartName,
2281  LPBYTE lpPassword,
2282  DWORD dwPwSize,
2283  LPSC_RPC_HANDLE lpServiceHandle)
2284 {
2285  PMANAGER_HANDLE hManager;
2286  DWORD dwError = ERROR_SUCCESS;
2287  PSERVICE lpService = NULL;
2288  SC_HANDLE hServiceHandle = NULL;
2289  LPWSTR lpImagePath = NULL;
2290  LPWSTR lpClearTextPassword = NULL;
2291  HKEY hServiceKey = NULL;
2292  LPWSTR lpObjectName;
2293 
2294  DPRINT("RCreateServiceW() called\n");
2295  DPRINT("lpServiceName = %S\n", lpServiceName);
2296  DPRINT("lpDisplayName = %S\n", lpDisplayName);
2297  DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2298  DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2299  DPRINT("dwStartType = %lu\n", dwStartType);
2300  DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2301  DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2302  DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2303  DPRINT("lpdwTagId = %p\n", lpdwTagId);
2304 
2305  if (ScmShutdown)
2307 
2309  if (hManager == NULL)
2310  {
2311  DPRINT1("Invalid service manager handle!\n");
2312  return ERROR_INVALID_HANDLE;
2313  }
2314 
2315  /* Check access rights */
2318  {
2319  DPRINT("Insufficient access rights! 0x%lx\n",
2320  hManager->Handle.DesiredAccess);
2321  return ERROR_ACCESS_DENIED;
2322  }
2323 
2324  if (*lpServiceName == 0)
2325  return ERROR_INVALID_NAME;
2326 
2327  if (*lpBinaryPathName == 0)
2328  return ERROR_INVALID_PARAMETER;
2329 
2330  /* Check for invalid service type value */
2331  if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2332  (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2333  ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2335  {
2336  return ERROR_INVALID_PARAMETER;
2337  }
2338 
2339  /* Check for invalid start type value */
2340  if ((dwStartType != SERVICE_BOOT_START) &&
2341  (dwStartType != SERVICE_SYSTEM_START) &&
2342  (dwStartType != SERVICE_AUTO_START) &&
2343  (dwStartType != SERVICE_DEMAND_START) &&
2344  (dwStartType != SERVICE_DISABLED))
2345  {
2346  return ERROR_INVALID_PARAMETER;
2347  }
2348 
2349  /* Only drivers can be boot start or system start services */
2350  if ((dwStartType == SERVICE_BOOT_START) ||
2351  (dwStartType == SERVICE_SYSTEM_START))
2352  {
2353  if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2354  (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2355  {
2356  return ERROR_INVALID_PARAMETER;
2357  }
2358  }
2359 
2360  /* Check for invalid error control value */
2361  if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2362  (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2363  (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2364  (dwErrorControl != SERVICE_ERROR_CRITICAL))
2365  {
2366  return ERROR_INVALID_PARAMETER;
2367  }
2368 
2369  if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2370  (lpServiceStartName))
2371  {
2372  /* We allow LocalSystem to run interactive. */
2373  if (wcsicmp(lpServiceStartName, L"LocalSystem"))
2374  {
2375  return ERROR_INVALID_PARAMETER;
2376  }
2377  }
2378 
2379  if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2380  {
2381  return ERROR_INVALID_PARAMETER;
2382  }
2383 
2384  /* Lock the service database exclusively */
2386 
2387  lpService = ScmGetServiceEntryByName(lpServiceName);
2388  if (lpService)
2389  {
2390  /* Unlock the service database */
2392 
2393  /* Check if it is marked for deletion */
2394  if (lpService->bDeleted)
2396 
2397  /* Return service-exists error */
2398  return ERROR_SERVICE_EXISTS;
2399  }
2400 
2401  if (lpDisplayName != NULL &&
2403  {
2404  /* Unlock the service database */
2406 
2408  }
2409 
2410  if (dwServiceType & SERVICE_DRIVER)
2411  {
2412  dwError = ScmCanonDriverImagePath(dwStartType,
2413  lpBinaryPathName,
2414  &lpImagePath);
2415  if (dwError != ERROR_SUCCESS)
2416  goto done;
2417  }
2418  else
2419  {
2420  if (dwStartType == SERVICE_BOOT_START ||
2421  dwStartType == SERVICE_SYSTEM_START)
2422  {
2423  /* Unlock the service database */
2425 
2426  return ERROR_INVALID_PARAMETER;
2427  }
2428  }
2429 
2430  /* Allocate a new service entry */
2431  dwError = ScmCreateNewServiceRecord(lpServiceName,
2432  &lpService,
2433  dwServiceType,
2434  dwStartType);
2435  if (dwError != ERROR_SUCCESS)
2436  goto done;
2437 
2438  /* Fill the new service entry */
2439  lpService->dwErrorControl = dwErrorControl;
2440 
2441  /* Fill the display name */
2442  if (lpDisplayName != NULL &&
2443  *lpDisplayName != 0 &&
2444  _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2445  {
2446  lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2448  (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2449  if (lpService->lpDisplayName == NULL)
2450  {
2451  dwError = ERROR_NOT_ENOUGH_MEMORY;
2452  goto done;
2453  }
2454  wcscpy(lpService->lpDisplayName, lpDisplayName);
2455  }
2456 
2457  /* Assign the service to a group */
2458  if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2459  {
2460  dwError = ScmSetServiceGroup(lpService,
2461  lpLoadOrderGroup);
2462  if (dwError != ERROR_SUCCESS)
2463  goto done;
2464  }
2465 
2466  /* Assign a new tag */
2467  if (lpdwTagId != NULL)
2468  {
2469  dwError = ScmAssignNewTag(lpService);
2470  if (dwError != ERROR_SUCCESS)
2471  goto done;
2472  }
2473 
2474  /* Assign the default security descriptor */
2475  if (dwServiceType & SERVICE_WIN32)
2476  {
2477  dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
2478  if (dwError != ERROR_SUCCESS)
2479  goto done;
2480  }
2481 
2482  /* Write service data to the registry */
2483  /* Create the service key */
2484  dwError = ScmCreateServiceKey(lpServiceName,
2485  KEY_WRITE,
2486  &hServiceKey);
2487  if (dwError != ERROR_SUCCESS)
2488  goto done;
2489 
2490  /* Set the display name */
2491  if (lpDisplayName != NULL && *lpDisplayName != 0)
2492  {
2493  RegSetValueExW(hServiceKey,
2494  L"DisplayName",
2495  0,
2496  REG_SZ,
2498  (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2499  }
2500 
2501  /* Set the service type */
2502  dwError = RegSetValueExW(hServiceKey,
2503  L"Type",
2504  0,
2505  REG_DWORD,
2506  (LPBYTE)&dwServiceType,
2507  sizeof(DWORD));
2508  if (dwError != ERROR_SUCCESS)
2509  goto done;
2510 
2511  /* Set the start value */
2512  dwError = RegSetValueExW(hServiceKey,
2513  L"Start",
2514  0,
2515  REG_DWORD,
2516  (LPBYTE)&dwStartType,
2517  sizeof(DWORD));
2518  if (dwError != ERROR_SUCCESS)
2519  goto done;
2520 
2521  /* Set the error control value */
2522  dwError = RegSetValueExW(hServiceKey,
2523  L"ErrorControl",
2524  0,
2525  REG_DWORD,
2526  (LPBYTE)&dwErrorControl,
2527  sizeof(DWORD));
2528  if (dwError != ERROR_SUCCESS)
2529  goto done;
2530 
2531  /* Set the image path */
2532  if (dwServiceType & SERVICE_WIN32)
2533  {
2534  dwError = RegSetValueExW(hServiceKey,
2535  L"ImagePath",
2536  0,
2537  REG_EXPAND_SZ,
2538  (LPBYTE)lpBinaryPathName,
2539  (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2540  if (dwError != ERROR_SUCCESS)
2541  goto done;
2542  }
2543  else if (dwServiceType & SERVICE_DRIVER)
2544  {
2545  dwError = RegSetValueExW(hServiceKey,
2546  L"ImagePath",
2547  0,
2548  REG_EXPAND_SZ,
2549  (LPBYTE)lpImagePath,
2550  (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2551  if (dwError != ERROR_SUCCESS)
2552  goto done;
2553  }
2554 
2555  /* Set the group name */
2556  if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2557  {
2558  dwError = RegSetValueExW(hServiceKey,
2559  L"Group",
2560  0,
2561  REG_SZ,
2562  (LPBYTE)lpLoadOrderGroup,
2563  (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2564  if (dwError != ERROR_SUCCESS)
2565  goto done;
2566  }
2567 
2568  /* Set the service tag */
2569  if (lpdwTagId != NULL)
2570  {
2571  dwError = RegSetValueExW(hServiceKey,
2572  L"Tag",
2573  0,
2574  REG_DWORD,
2575  (LPBYTE)&lpService->dwTag,
2576  sizeof(DWORD));
2577  if (dwError != ERROR_SUCCESS)
2578  goto done;
2579  }
2580 
2581  /* Write dependencies */
2582  if (lpDependencies != NULL && *lpDependencies != 0)
2583  {
2584  dwError = ScmWriteDependencies(hServiceKey,
2585  (LPCWSTR)lpDependencies,
2586  dwDependSize);
2587  if (dwError != ERROR_SUCCESS)
2588  goto done;
2589  }
2590 
2591  /* Start name and password are only used by Win32 services */
2592  if (dwServiceType & SERVICE_WIN32)
2593  {
2594  /* Write service start name */
2595  lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2596  dwError = RegSetValueExW(hServiceKey,
2597  L"ObjectName",
2598  0,
2599  REG_SZ,
2600  (LPBYTE)lpObjectName,
2601  (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2602  if (dwError != ERROR_SUCCESS)
2603  goto done;
2604 
2605  if (lpPassword != NULL && *(LPWSTR)lpPassword != 0)
2606  {
2607  /* Decrypt the password */
2608  dwError = ScmDecryptPassword(lpPassword,
2609  dwPwSize,
2610  &lpClearTextPassword);
2611  if (dwError != ERROR_SUCCESS)
2612  goto done;
2613 
2614  /* Write the password */
2615  dwError = ScmSetServicePassword(lpServiceName,
2616  lpClearTextPassword);
2617  if (dwError != ERROR_SUCCESS)
2618  goto done;
2619  }
2620 
2621  /* Write the security descriptor */
2622  dwError = ScmWriteSecurityDescriptor(hServiceKey,
2623  lpService->pSecurityDescriptor);
2624  if (dwError != ERROR_SUCCESS)
2625  goto done;
2626  }
2627 
2628  dwError = ScmCreateServiceHandle(lpService,
2629  &hServiceHandle);
2630  if (dwError != ERROR_SUCCESS)
2631  goto done;
2632 
2633  dwError = ScmCheckAccess(hServiceHandle,
2634  dwDesiredAccess);
2635  if (dwError != ERROR_SUCCESS)
2636  goto done;
2637 
2638  lpService->dwRefCount = 1;
2639 
2640  /* Get the service tag (if Win32) */
2641  ScmGenerateServiceTag(lpService);
2642 
2643  DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2644 
2645 done:
2646  /* Unlock the service database */
2648 
2649  if (hServiceKey != NULL)
2650  RegCloseKey(hServiceKey);
2651 
2652  if (lpClearTextPassword != NULL)
2653  {
2654  /* Wipe and release the password buffer */
2655  SecureZeroMemory(lpClearTextPassword,
2656  (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2657  HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2658  }
2659 
2660  if (dwError == ERROR_SUCCESS)
2661  {
2662  DPRINT("hService %p\n", hServiceHandle);
2663  *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2664 
2665  if (lpdwTagId != NULL)
2666  *lpdwTagId = lpService->dwTag;
2667  }
2668  else
2669  {
2670  if (lpService != NULL &&
2671  lpService->lpServiceName != NULL)
2672  {
2673  /* Release the display name buffer */
2674  HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2675  }
2676 
2677  if (hServiceHandle)
2678  {
2679  /* Remove the service handle */
2680  HeapFree(GetProcessHeap(), 0, hServiceHandle);
2681  }
2682 
2683  if (lpService != NULL)
2684  {
2685  /* FIXME: remove the service entry */
2686  }
2687  }
2688 
2689  if (lpImagePath != NULL)
2690  HeapFree(GetProcessHeap(), 0, lpImagePath);
2691 
2692  DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2693 
2694  return dwError;
2695 }
2696 
2697 
2698 /* Function 13 */
2699 DWORD
2700 WINAPI
2702  SC_RPC_HANDLE hService,
2703  DWORD dwServiceState,
2704  LPBYTE lpServices,
2705  DWORD cbBufSize,
2707  LPBOUNDED_DWORD_256K lpServicesReturned)
2708 {
2709  DWORD dwError = ERROR_SUCCESS;
2710  DWORD dwServicesReturned = 0;
2711  DWORD dwServiceCount;
2713  PSERVICE_HANDLE hSvc;
2714  PSERVICE lpService = NULL;
2715  PSERVICE *lpServicesArray = NULL;
2716  LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2717  LPWSTR lpStr;
2718 
2719  *pcbBytesNeeded = 0;
2720  *lpServicesReturned = 0;
2721 
2722  DPRINT("REnumDependentServicesW() called\n");
2723 
2724  hSvc = ScmGetServiceFromHandle(hService);
2725  if (hSvc == NULL)
2726  {
2727  DPRINT1("Invalid service handle!\n");
2728  return ERROR_INVALID_HANDLE;
2729  }
2730 
2731  lpService = hSvc->ServiceEntry;
2732 
2733  /* Check access rights */
2736  {
2737  DPRINT("Insufficient access rights! 0x%lx\n",
2738  hSvc->Handle.DesiredAccess);
2739  return ERROR_ACCESS_DENIED;
2740  }
2741 
2742  /* Open the Services Reg key */
2744  L"System\\CurrentControlSet\\Services",
2745  0,
2746  KEY_READ,
2747  &hServicesKey);
2748  if (dwError != ERROR_SUCCESS)
2749  return dwError;
2750 
2751  /* First determine the bytes needed and get the number of dependent services */
2753  lpService,
2754  dwServiceState,
2755  NULL,
2757  &dwServicesReturned);
2758  if (dwError != ERROR_SUCCESS)
2759  goto Done;
2760 
2761  /* If buffer size is less than the bytes needed or pointer is null */
2762  if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2763  {
2764  dwError = ERROR_MORE_DATA;
2765  goto Done;
2766  }
2767 
2768  /* Allocate memory for array of service pointers */
2769  lpServicesArray = HeapAlloc(GetProcessHeap(),
2771  (dwServicesReturned + 1) * sizeof(PSERVICE));
2772  if (!lpServicesArray)
2773  {
2774  DPRINT1("Could not allocate a buffer!!\n");
2775  dwError = ERROR_NOT_ENOUGH_MEMORY;
2776  goto Done;
2777  }
2778 
2779  dwServicesReturned = 0;
2780  *pcbBytesNeeded = 0;
2781 
2783  lpService,
2784  dwServiceState,
2785  lpServicesArray,
2787  &dwServicesReturned);
2788  if (dwError != ERROR_SUCCESS)
2789  {
2790  goto Done;
2791  }
2792 
2793  lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2794  lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2795 
2796  /* Copy EnumDepenedentService to Buffer */
2797  for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2798  {
2799  lpService = lpServicesArray[dwServiceCount];
2800 
2801  /* Copy status info */
2802  memcpy(&lpServicesPtr->ServiceStatus,
2803  &lpService->Status,
2804  sizeof(SERVICE_STATUS));
2805 
2806  /* Copy display name */
2807  wcscpy(lpStr, lpService->lpDisplayName);
2808  lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2809  lpStr += (wcslen(lpService->lpDisplayName) + 1);
2810 
2811  /* Copy service name */
2812  wcscpy(lpStr, lpService->lpServiceName);
2813  lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2814  lpStr += (wcslen(lpService->lpServiceName) + 1);
2815 
2816  lpServicesPtr++;
2817  }
2818 
2819  *lpServicesReturned = dwServicesReturned;
2820 
2821 Done:
2822  if (lpServicesArray != NULL)
2823  HeapFree(GetProcessHeap(), 0, lpServicesArray);
2824 
2826 
2827  DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2828 
2829  return dwError;
2830 }
2831 
2832 
2833 /* Function 14 */
2834 DWORD
2835 WINAPI
2838  DWORD dwServiceType,
2839  DWORD dwServiceState,
2840  LPBYTE lpBuffer,
2841  DWORD dwBufSize,
2843  LPBOUNDED_DWORD_256K lpServicesReturned,
2844  LPBOUNDED_DWORD_256K lpResumeHandle)
2845 {
2846  /* Enumerate all the services, not regarding of their group */
2848  dwServiceType,
2849  dwServiceState,
2850  lpBuffer,
2851  dwBufSize,
2853  lpServicesReturned,
2854  lpResumeHandle,
2855  NULL);
2856 }
2857 
2858 
2859 /* Function 15 */
2860 DWORD
2861 WINAPI
2863  LPWSTR lpMachineName,
2864  LPWSTR lpDatabaseName,
2865  DWORD dwDesiredAccess,
2866  LPSC_RPC_HANDLE lpScHandle)
2867 {
2868  DWORD dwError;
2869  SC_HANDLE hHandle;
2870 
2871  DPRINT("ROpenSCManagerW() called\n");
2872  DPRINT("lpMachineName = %p\n", lpMachineName);
2873  DPRINT("lpMachineName: %S\n", lpMachineName);
2874  DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2875  DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2876  DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2877 
2878  if (ScmShutdown)
2880 
2881  if (!lpScHandle)
2882  return ERROR_INVALID_PARAMETER;
2883 
2884  dwError = ScmCreateManagerHandle(lpDatabaseName,
2885  &hHandle);
2886  if (dwError != ERROR_SUCCESS)
2887  {
2888  DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2889  return dwError;
2890  }
2891 
2892  /* Check the desired access */
2893  dwError = ScmCheckAccess(hHandle,
2894  dwDesiredAccess | SC_MANAGER_CONNECT);
2895  if (dwError != ERROR_SUCCESS)
2896  {
2897  DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2898  HeapFree(GetProcessHeap(), 0, hHandle);
2899  return dwError;
2900  }
2901 
2902  *lpScHandle = (SC_RPC_HANDLE)hHandle;
2903  DPRINT("*hScm = %p\n", *lpScHandle);
2904 
2905  DPRINT("ROpenSCManagerW() done\n");
2906 
2907  return ERROR_SUCCESS;
2908 }
2909 
2910 
2911 /* Function 16 */
2912 DWORD
2913 WINAPI
2916  LPWSTR lpServiceName,
2917  DWORD dwDesiredAccess,
2918  LPSC_RPC_HANDLE lpServiceHandle)
2919 {
2920  PSERVICE lpService;
2921  PMANAGER_HANDLE hManager;
2922  SC_HANDLE hHandle;
2923  DWORD dwError = ERROR_SUCCESS;
2924 
2925  DPRINT("ROpenServiceW() called\n");
2926  DPRINT("hSCManager = %p\n", hSCManager);
2927  DPRINT("lpServiceName = %p\n", lpServiceName);
2928  DPRINT("lpServiceName: %S\n", lpServiceName);
2929  DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2930 
2931  if (ScmShutdown)
2933 
2935  if (hManager == NULL)
2936  {
2937  DPRINT1("Invalid service manager handle!\n");
2938  return ERROR_INVALID_HANDLE;
2939  }
2940 
2941  if (!lpServiceHandle)
2942  return ERROR_INVALID_PARAMETER;
2943 
2944  if (!lpServiceName)
2945  return ERROR_INVALID_ADDRESS;
2946 
2947  /* Lock the service database exclusive */
2949 
2950  /* Get service database entry */
2951  lpService = ScmGetServiceEntryByName(lpServiceName);
2952  if (lpService == NULL)
2953  {
2954  DPRINT("Could not find the service!\n");
2955  dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2956  goto Done;
2957  }
2958 
2959  /* Create a service handle */
2960  dwError = ScmCreateServiceHandle(lpService,
2961  &hHandle);
2962  if (dwError != ERROR_SUCCESS)
2963  {
2964  DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2965  goto Done;
2966  }
2967 
2968  /* Check the desired access */
2969  dwError = ScmCheckAccess(hHandle,
2970  dwDesiredAccess);
2971  if (dwError != ERROR_SUCCESS)
2972  {
2973  DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2974  HeapFree(GetProcessHeap(), 0, hHandle);
2975  goto Done;
2976  }
2977 
2978  lpService->dwRefCount++;
2979  DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2980 
2981  *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2982  DPRINT("*hService = %p\n", *lpServiceHandle);
2983 
2984 Done:
2985  /* Unlock the service database */
2987 
2988  DPRINT("ROpenServiceW() done\n");
2989 
2990  return dwError;
2991 }
2992 
2993 
2994 /* Function 17 */
2995 DWORD
2996 WINAPI
2998  SC_RPC_HANDLE hService,
2999  LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
3000  DWORD cbBufSize,
3002 {
3003  LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
3004  DWORD dwError = ERROR_SUCCESS;
3005  PSERVICE_HANDLE hSvc;
3006  PSERVICE lpService = NULL;
3007  HKEY hServiceKey = NULL;
3008  LPWSTR lpImagePath = NULL;
3009  LPWSTR lpServiceStartName = NULL;
3010  LPWSTR lpDependencies = NULL;
3011  DWORD dwDependenciesLength = 0;
3012  DWORD dwRequiredSize;
3013  LPWSTR lpStr;
3014 
3015  DPRINT("RQueryServiceConfigW() called\n");
3016 
3017  if (ScmShutdown)
3019 
3020  hSvc = ScmGetServiceFromHandle(hService);
3021  if (hSvc == NULL)
3022  {
3023  DPRINT1("Invalid service handle!\n");
3024  return ERROR_INVALID_HANDLE;
3025  }
3026 
3029  {
3030  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3031  return ERROR_ACCESS_DENIED;
3032  }
3033 
3034  lpService = hSvc->ServiceEntry;
3035  if (lpService == NULL)
3036  {
3037  DPRINT("lpService == NULL!\n");
3038  return ERROR_INVALID_HANDLE;
3039  }
3040 
3041  /* Lock the service database shared */
3043 
3044  dwError = ScmOpenServiceKey(lpService->lpServiceName,
3045  KEY_READ,
3046  &hServiceKey);
3047  if (dwError != ERROR_SUCCESS)
3048  goto Done;
3049 
3050  /* Read the image path */
3051  dwError = ScmReadString(hServiceKey,
3052  L"ImagePath",
3053  &lpImagePath);
3054  if (dwError != ERROR_SUCCESS)
3055  goto Done;
3056 
3057  /* Read the service start name */
3058  ScmReadString(hServiceKey,
3059  L"ObjectName",
3060  &lpServiceStartName);
3061 
3062  /* Read the dependencies */
3063  ScmReadDependencies(hServiceKey,
3064  &lpDependencies,
3065  &dwDependenciesLength);
3066 
3067  dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3068 
3069  if (lpImagePath != NULL)
3070  dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
3071  else
3072  dwRequiredSize += 2 * sizeof(WCHAR);
3073 
3074  if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3075  dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
3076  else
3077  dwRequiredSize += 2 * sizeof(WCHAR);
3078 
3079  if (lpDependencies != NULL)
3080  dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
3081  else
3082  dwRequiredSize += 2 * sizeof(WCHAR);
3083 
3084  if (lpServiceStartName != NULL)
3085  dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
3086  else
3087  dwRequiredSize += 2 * sizeof(WCHAR);
3088 
3089  if (lpService->lpDisplayName != NULL)
3090  dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
3091  else
3092  dwRequiredSize += 2 * sizeof(WCHAR);
3093 
3094  if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3095  {
3096  dwError = ERROR_INSUFFICIENT_BUFFER;
3097  }
3098  else
3099  {
3100  lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
3101  lpServiceConfig->dwStartType = lpService->dwStartType;
3102  lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
3103  lpServiceConfig->dwTagId = lpService->dwTag;
3104 
3105  lpStr = (LPWSTR)(lpServiceConfig + 1);
3106 
3107  /* Append the image path */
3108  if (lpImagePath != NULL)
3109  {
3110  wcscpy(lpStr, lpImagePath);
3111  }
3112  else
3113  {
3114  *lpStr = 0;
3115  }
3116 
3117  lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3118  lpStr += (wcslen(lpStr) + 1);
3119 
3120  /* Append the group name */
3121  if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3122  {
3123  wcscpy(lpStr, lpService->lpGroup->lpGroupName);
3124  }
3125  else
3126  {
3127  *lpStr = 0;
3128  }
3129 
3130  lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3131  lpStr += (wcslen(lpStr) + 1);
3132 
3133  /* Append Dependencies */
3134  if (lpDependencies != NULL)
3135  {
3136  memcpy(lpStr,
3137  lpDependencies,
3138  dwDependenciesLength * sizeof(WCHAR));
3139  }
3140  else
3141  {
3142  *lpStr = 0;
3143  }
3144 
3145  lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3146  if (lpDependencies != NULL)
3147  lpStr += dwDependenciesLength;
3148  else
3149  lpStr += (wcslen(lpStr) + 1);
3150 
3151  /* Append the service start name */
3152  if (lpServiceStartName != NULL)
3153  {
3154  wcscpy(lpStr, lpServiceStartName);
3155  }
3156  else
3157  {
3158  *lpStr = 0;
3159  }
3160 
3161  lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3162  lpStr += (wcslen(lpStr) + 1);
3163 
3164  /* Append the display name */
3165  if (lpService->lpDisplayName != NULL)
3166  {
3167  wcscpy(lpStr, lpService->lpDisplayName);
3168  }
3169  else
3170  {
3171  *lpStr = 0;
3172  }
3173 
3174  lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3175  }
3176 
3177  if (pcbBytesNeeded != NULL)
3178  *pcbBytesNeeded = dwRequiredSize;
3179 
3180 Done:
3181  /* Unlock the service database */
3183 
3184  if (lpImagePath != NULL)
3185  HeapFree(GetProcessHeap(), 0, lpImagePath);
3186 
3187  if (lpServiceStartName != NULL)
3188  HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3189 
3190  if (lpDependencies != NULL)
3191  HeapFree(GetProcessHeap(), 0, lpDependencies);
3192 
3193  if (hServiceKey != NULL)
3194  RegCloseKey(hServiceKey);
3195 
3196  DPRINT("RQueryServiceConfigW() done\n");
3197 
3198  return dwError;
3199 }
3200 
3201 
3202 /* Function 18 */
3203 DWORD
3204 WINAPI
3207  LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3208  DWORD cbBufSize,
3210 {
3212  PMANAGER_HANDLE hMgr;
3213  DWORD dwRequiredSize;
3214 
3215  if (!lpLockStatus || !pcbBytesNeeded)
3216  return ERROR_INVALID_PARAMETER;
3217 
3219  if (hMgr == NULL)
3220  {
3221  DPRINT1("Invalid service manager handle!\n");
3222  return ERROR_INVALID_HANDLE;
3223  }
3224 
3227  {
3228  DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
3229  return ERROR_ACCESS_DENIED;
3230  }
3231 
3232  /* FIXME: we need to compute instead the real length of the owner name */
3233  dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
3234  *pcbBytesNeeded = dwRequiredSize;
3235 
3236  if (cbBufSize < dwRequiredSize)
3238 
3239  ScmQueryServiceLockStatusW(lpLockStatus);
3240 
3241  return ERROR_SUCCESS;
3242 }
3243 
3244 
3245 /* Function 19 */
3246 DWORD
3247 WINAPI
3249  SC_RPC_HANDLE hService,
3250  DWORD argc,
3252 {
3253  DWORD dwError = ERROR_SUCCESS;
3254  PSERVICE_HANDLE hSvc;
3255  PSERVICE lpService = NULL;
3256 
3257 #ifndef NDEBUG
3258  DWORD i;
3259 
3260  DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3261  DPRINT(" argc: %lu\n", argc);
3262  if (argv != NULL)
3263  {
3264  for (i = 0; i < argc; i++)
3265  {
3266  DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
3267  }
3268  }
3269 #endif
3270 
3271  if (ScmShutdown)
3273 
3274  hSvc = ScmGetServiceFromHandle(hService);
3275  if (hSvc == NULL)
3276  {
3277  DPRINT1("Invalid service handle!\n");
3278  return ERROR_INVALID_HANDLE;
3279  }
3280 
3282  SERVICE_START))
3283  {
3284  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3285  return ERROR_ACCESS_DENIED;
3286  }
3287 
3288  lpService = hSvc->ServiceEntry;
3289  if (lpService == NULL)
3290  {
3291  DPRINT("lpService == NULL!\n");
3292  return ERROR_INVALID_HANDLE;
3293  }
3294 
3295  if (lpService->dwStartType == SERVICE_DISABLED)
3296  return ERROR_SERVICE_DISABLED;
3297 
3298  if (lpService->bDeleted)
3300 
3301  /* Start the service */
3302  dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3303 
3304  return dwError;
3305 }
3306 
3307 
3308 /* Function 20 */
3309 DWORD
3310 WINAPI
3313  LPCWSTR lpServiceName,
3315  DWORD *lpcchBuffer)
3316 {
3317  // PMANAGER_HANDLE hManager;
3318  PSERVICE lpService;
3319  LPCWSTR lpSvcDisplayName;
3320  DWORD dwLength;
3321  DWORD dwError;
3322 
3323  DPRINT("RGetServiceDisplayNameW() called\n");
3324  DPRINT("hSCManager = %p\n", hSCManager);
3325  DPRINT("lpServiceName: %S\n", lpServiceName);
3326  DPRINT("lpDisplayName: %p\n", lpDisplayName);
3327  DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3328 
3329 #if 0
3330  hManager = (PMANAGER_HANDLE)hSCManager;
3331  if (hManager->Handle.Tag != MANAGER_TAG)
3332  {
3333  DPRINT("Invalid manager handle!\n");
3334  return ERROR_INVALID_HANDLE;
3335  }
3336 #endif
3337 
3338  /* Get service database entry */
3339  lpService = ScmGetServiceEntryByName(lpServiceName);
3340  if (lpService == NULL)
3341  {
3342  DPRINT("Could not find the service!\n");
3344  }
3345 
3346  if (lpService->lpDisplayName)
3347  lpSvcDisplayName = lpService->lpDisplayName;
3348  else
3349  lpSvcDisplayName = lpService->lpServiceName;
3350 
3351  dwLength = (DWORD)wcslen(lpSvcDisplayName);
3352 
3353  if (*lpcchBuffer > dwLength)
3354  {
3355  if (lpDisplayName != NULL)
3356  wcscpy(lpDisplayName, lpSvcDisplayName);
3357 
3358  dwError = ERROR_SUCCESS;
3359  }
3360  else
3361  {
3362  dwError = ERROR_INSUFFICIENT_BUFFER;
3363  }
3364 
3365  *lpcchBuffer = dwLength;
3366 
3367  return dwError;
3368 }
3369 
3370 
3371 /* Function 21 */
3372 DWORD
3373 WINAPI
3377  LPWSTR lpServiceName,
3378  DWORD *lpcchBuffer)
3379 {
3380  // PMANAGER_HANDLE hManager;
3381  PSERVICE lpService;
3382  DWORD dwLength;
3383  DWORD dwError;
3384 
3385  DPRINT("RGetServiceKeyNameW() called\n");
3386  DPRINT("hSCManager = %p\n", hSCManager);
3387  DPRINT("lpDisplayName: %S\n", lpDisplayName);
3388  DPRINT("lpServiceName: %p\n", lpServiceName);
3389  DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3390 
3391 #if 0
3392  hManager = (PMANAGER_HANDLE)hSCManager;
3393  if (hManager->Handle.Tag != MANAGER_TAG)
3394  {
3395  DPRINT("Invalid manager handle!\n");
3396  return ERROR_INVALID_HANDLE;
3397  }
3398 #endif
3399 
3400  /* Get service database entry */
3402  if (lpService == NULL)
3403  {
3404  DPRINT("Could not find the service!\n");
3406  }
3407 
3408  dwLength = (DWORD)wcslen(lpService->lpServiceName);
3409 
3410  if (*lpcchBuffer > dwLength)
3411  {
3412  if (lpServiceName != NULL)
3413  wcscpy(lpServiceName, lpService->lpServiceName);
3414 
3415  dwError = ERROR_SUCCESS;
3416  }
3417  else
3418  {
3419  dwError = ERROR_INSUFFICIENT_BUFFER;
3420  }
3421 
3422  *lpcchBuffer = dwLength;
3423 
3424  return dwError;
3425 }
3426 
3427 
3428 /* Function 22 */
3429 DWORD
3430 WINAPI
3434  int bSetBitsOn,
3435  int bUpdateImmediately,
3436  char *lpString)
3437 {
3438  if (ScmShutdown)
3440 
3441  if (lpString != NULL)
3442  return ERROR_INVALID_PARAMETER;
3443 
3445  dwServiceBits,
3446  bSetBitsOn,
3447  bUpdateImmediately,
3448  NULL);
3449 }
3450 
3451 
3452 /* Function 23 */
3453 DWORD
3454 WINAPI
3456  SC_RPC_HANDLE hService,
3457  DWORD dwServiceType,
3458  DWORD dwStartType,
3459  DWORD dwErrorControl,
3460  LPSTR lpBinaryPathName,
3461  LPSTR lpLoadOrderGroup,
3462  LPDWORD lpdwTagId,
3463  LPBYTE lpDependencies,
3464  DWORD dwDependSize,
3465  LPSTR lpServiceStartName,
3466  LPBYTE lpPassword,
3467  DWORD dwPwSize,
3469 {
3470  DWORD dwError = ERROR_SUCCESS;
3471  LPWSTR lpBinaryPathNameW = NULL;
3472  LPWSTR lpLoadOrderGroupW = NULL;
3473  LPWSTR lpDependenciesW = NULL;
3474  LPWSTR lpServiceStartNameW = NULL;
3475  LPWSTR lpDisplayNameW = NULL;
3476  DWORD dwDependenciesLength = 0;
3477  SIZE_T cchLength;
3478  int len;
3479  LPCSTR lpStr;
3480 
3481  if (lpBinaryPathName)
3482  {
3483  len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3484  lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3485  if (!lpBinaryPathNameW)
3486  {
3488  goto cleanup;
3489  }
3490  MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3491  }
3492 
3493  if (lpLoadOrderGroup)
3494  {
3495  len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3496  lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3497  if (!lpLoadOrderGroupW)
3498  {
3500  goto cleanup;
3501  }
3502  MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3503  }
3504 
3505  if (lpDependencies)
3506  {
3507  lpStr = (LPCSTR)lpDependencies;
3508  while (*lpStr)
3509  {
3510  cchLength = strlen(lpStr) + 1;
3511  dwDependenciesLength += (DWORD)cchLength;
3512  lpStr = lpStr + cchLength;
3513  }
3514  dwDependenciesLength++;
3515 
3516  lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3517  if (!lpDependenciesW)
3518  {
3520  goto cleanup;
3521  }
3522  MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3523  }
3524 
3525  if (lpServiceStartName)
3526  {
3527  len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3528  lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3529  if (!lpServiceStartNameW)
3530  {
3532  goto cleanup;
3533  }
3534  MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3535  }
3536 
3537  if (lpDisplayName)
3538  {
3540  lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3541  if (!lpDisplayNameW)
3542  {
3544  goto cleanup;
3545  }
3546  MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3547  }
3548 
3549  dwError = RChangeServiceConfigW(hService,
3550  dwServiceType,
3551  dwStartType,
3552  dwErrorControl,
3553  lpBinaryPathNameW,
3554  lpLoadOrderGroupW,
3555  lpdwTagId,
3556  (LPBYTE)lpDependenciesW,
3557  dwDependenciesLength,
3558  lpServiceStartNameW,
3559  lpPassword,
3560  dwPwSize,
3561  lpDisplayNameW);
3562 
3563 cleanup:
3564  if (lpBinaryPathNameW != NULL)
3565  HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3566 
3567  if (lpLoadOrderGroupW != NULL)
3568  HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3569 
3570  if (lpDependenciesW != NULL)
3571  HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3572 
3573  if (lpServiceStartNameW != NULL)
3574  HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3575 
3576  if (lpDisplayNameW != NULL)
3577  HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3578 
3579  return dwError;
3580 }
3581 
3582 
3583 /* Function 24 */
3584 DWORD
3585 WINAPI
3588  LPSTR lpServiceName,
3590  DWORD dwDesiredAccess,
3591  DWORD dwServiceType,
3592  DWORD dwStartType,
3593  DWORD dwErrorControl,
3594  LPSTR lpBinaryPathName,
3595  LPSTR lpLoadOrderGroup,
3596  LPDWORD lpdwTagId,
3597  LPBYTE lpDependencies,
3598  DWORD dwDependSize,
3599  LPSTR lpServiceStartName,
3600  LPBYTE lpPassword,
3601  DWORD dwPwSize,
3602  LPSC_RPC_HANDLE lpServiceHandle)
3603 {
3604  DWORD dwError = ERROR_SUCCESS;
3605  LPWSTR lpServiceNameW = NULL;
3606  LPWSTR lpDisplayNameW = NULL;
3607  LPWSTR lpBinaryPathNameW = NULL;
3608  LPWSTR lpLoadOrderGroupW = NULL;
3609  LPWSTR lpDependenciesW = NULL;
3610  LPWSTR lpServiceStartNameW = NULL;
3611  DWORD dwDependenciesLength = 0;
3612  SIZE_T cchLength;
3613  int len;
3614  LPCSTR lpStr;
3615 
3616  if (lpServiceName)
3617  {
3618  len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3619  lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3620  if (!lpServiceNameW)
3621  {
3623  goto cleanup;
3624  }
3625  MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3626  }
3627 
3628  if (lpDisplayName)
3629  {
3631  lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3632  if (!lpDisplayNameW)
3633  {
3635  goto cleanup;
3636  }
3637  MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3638  }
3639 
3640  if (lpBinaryPathName)
3641  {
3642  len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3643  lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3644  if (!lpBinaryPathNameW)
3645  {
3647  goto cleanup;
3648  }
3649  MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3650  }
3651 
3652  if (lpLoadOrderGroup)
3653  {
3654  len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3655  lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3656  if (!lpLoadOrderGroupW)
3657  {
3659  goto cleanup;
3660  }
3661  MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3662  }
3663 
3664  if (lpDependencies)
3665  {
3666  lpStr = (LPCSTR)lpDependencies;
3667  while (*lpStr)
3668  {
3669  cchLength = strlen(lpStr) + 1;
3670  dwDependenciesLength += (DWORD)cchLength;
3671  lpStr = lpStr + cchLength;
3672  }
3673  dwDependenciesLength++;
3674 
3675  lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3676  if (!lpDependenciesW)
3677  {
3679  goto cleanup;
3680  }
3681  MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3682  }
3683 
3684  if (lpServiceStartName)
3685  {
3686  len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3687  lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3688  if (!lpServiceStartNameW)
3689  {
3691  goto cleanup;
3692  }
3693  MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3694  }
3695 
3696  dwError = RCreateServiceW(hSCManager,
3697  lpServiceNameW,
3698  lpDisplayNameW,
3699  dwDesiredAccess,
3700  dwServiceType,
3701  dwStartType,
3702  dwErrorControl,
3703  lpBinaryPathNameW,
3704  lpLoadOrderGroupW,
3705  lpdwTagId,
3706  (LPBYTE)lpDependenciesW,
3707  dwDependenciesLength,
3708  lpServiceStartNameW,
3709  lpPassword,
3710  dwPwSize,
3711  lpServiceHandle);
3712 
3713 cleanup:
3714  if (lpServiceNameW !=NULL)
3715  HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3716 
3717  if (lpDisplayNameW != NULL)
3718  HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3719 
3720  if (lpBinaryPathNameW != NULL)
3721  HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3722 
3723  if (lpLoadOrderGroupW != NULL)
3724  HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3725 
3726  if (lpDependenciesW != NULL)
3727  HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3728 
3729  if (lpServiceStartNameW != NULL)
3730  HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3731 
3732  return dwError;
3733 }
3734 
3735 
3736 /* Function 25 */
3737 DWORD
3738 WINAPI
3740  SC_RPC_HANDLE hService,
3741  DWORD dwServiceState,
3742  LPBYTE lpServices,
3743  DWORD cbBufSize,
3745  LPBOUNDED_DWORD_256K lpServicesReturned)
3746 {
3747  DWORD dwError = ERROR_SUCCESS;
3748  DWORD dwServicesReturned = 0;
3749  DWORD dwServiceCount;
3751  PSERVICE_HANDLE hSvc;
3752  PSERVICE lpService = NULL;
3753  PSERVICE *lpServicesArray = NULL;
3754  LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3755  LPSTR lpStr;
3756 
3757  *pcbBytesNeeded = 0;
3758  *lpServicesReturned = 0;
3759 
3760  DPRINT("REnumDependentServicesA() called\n");
3761 
3762  hSvc = ScmGetServiceFromHandle(hService);
3763  if (hSvc == NULL)
3764  {
3765  DPRINT1("Invalid service handle!\n");
3766  return ERROR_INVALID_HANDLE;
3767  }
3768 
3769  lpService = hSvc->ServiceEntry;
3770 
3771  /* Check access rights */
3774  {
3775  DPRINT("Insufficient access rights! 0x%lx\n",
3776  hSvc->Handle.DesiredAccess);
3777  return ERROR_ACCESS_DENIED;
3778  }
3779 
3780  /* Open the Services Reg key */
3782  L"System\\CurrentControlSet\\Services",
3783  0,
3784  KEY_READ,
3785  &hServicesKey);
3786 
3787  if (dwError != ERROR_SUCCESS)
3788  return dwError;
3789 
3790  /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3791  both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3792  are the same for both. Verified in WINXP. */
3793 
3794  /* First determine the bytes needed and get the number of dependent services*/
3796  lpService,
3797  dwServiceState,
3798  NULL,
3800  &dwServicesReturned);
3801  if (dwError != ERROR_SUCCESS)
3802  goto Done;
3803 
3804  /* If buffer size is less than the bytes needed or pointer is null*/
3805  if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3806  {
3807  dwError = ERROR_MORE_DATA;
3808  goto Done;
3809  }
3810 
3811  /* Allocate memory for array of service pointers */
3812  lpServicesArray = HeapAlloc(GetProcessHeap(),
3814  (dwServicesReturned + 1) * sizeof(PSERVICE));
3815  if (!lpServicesArray)
3816  {
3817  DPRINT("Could not allocate a buffer!!\n");
3818  dwError = ERROR_NOT_ENOUGH_MEMORY;
3819  goto Done;
3820  }
3821 
3822  dwServicesReturned = 0;
3823  *pcbBytesNeeded = 0;
3824 
3826  lpService,
3827  dwServiceState,
3828  lpServicesArray,
3830  &dwServicesReturned);
3831  if (dwError != ERROR_SUCCESS)
3832  {
3833  goto Done;
3834  }
3835 
3836  lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3837  lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3838 
3839  /* Copy EnumDepenedentService to Buffer */
3840  for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3841  {
3842  lpService = lpServicesArray[dwServiceCount];
3843 
3844  /* Copy the status info */
3845  memcpy(&lpServicesPtr->ServiceStatus,
3846  &lpService->Status,
3847  sizeof(SERVICE_STATUS));
3848 
3849  /* Copy display name */
3851  0,
3852  lpService->lpDisplayName,
3853  -1,
3854  lpStr,
3855  (int)wcslen(lpService->lpDisplayName),
3856  0,
3857  0);
3858  lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3859  lpStr += strlen(lpStr) + 1;
3860 
3861  /* Copy service name */
3863  0,
3864  lpService->lpServiceName,
3865  -1,
3866  lpStr,
3867  (int)wcslen(lpService->lpServiceName),
3868  0,
3869  0);
3870  lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3871  lpStr += strlen(lpStr) + 1;
3872 
3873  lpServicesPtr++;
3874  }
3875 
3876  *lpServicesReturned = dwServicesReturned;
3877 
3878 Done:
3879  if (lpServicesArray)
3880  HeapFree(GetProcessHeap(), 0, lpServicesArray);
3881 
3883 
3884  DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3885 
3886  return dwError;
3887 }
3888 
3889 
3890 /* Function 26 */
3891 DWORD
3892 WINAPI
3895  DWORD dwServiceType,
3896  DWORD dwServiceState,
3897  LPBYTE lpBuffer,
3898  DWORD dwBufSize,
3900  LPBOUNDED_DWORD_256K lpServicesReturned,
3901  LPBOUNDED_DWORD_256K lpResumeHandle)
3902 {
3903  LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3904  LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
3905  LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3906  LPWSTR lpStringPtrW;
3907  LPSTR lpStringPtrA;
3908  DWORD dwError;
3909  DWORD dwServiceCount;
3910 
3911  DPRINT("REnumServicesStatusA() called\n");
3912 
3913  if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
3914  {
3915  return ERROR_INVALID_ADDRESS;
3916  }
3917 
3918  if ((dwBufSize > 0) && (lpBuffer))
3919  {
3920  lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3921  if (!lpStatusPtrW)
3922  {
3923  DPRINT("Failed to allocate buffer!\n");
3924  return ERROR_NOT_ENOUGH_MEMORY;
3925  }
3926  }
3927 
3928  dwError = REnumServicesStatusW(hSCManager,
3929  dwServiceType,
3930  dwServiceState,
3931  (LPBYTE)lpStatusPtrW,
3932  dwBufSize,
3934  lpServicesReturned,
3935  lpResumeHandle);
3936 
3937  /* if no services were returned then we are Done */
3938  if (*lpServicesReturned == 0)
3939  goto Done;
3940 
3941  lpStatusPtrIncrW = lpStatusPtrW;
3942  lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3943  lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3944  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3945  lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3946  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3947 
3948  for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3949  {
3950  /* Copy the service name */
3952  0,
3953  lpStringPtrW,
3954  -1,
3955  lpStringPtrA,
3956  (int)wcslen(lpStringPtrW),
3957  0,
3958  0);
3959 
3960  lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3961  lpStringPtrA += wcslen(lpStringPtrW) + 1;
3962  lpStringPtrW += wcslen(lpStringPtrW) + 1;
3963 
3964  /* Copy the display name */
3966  0,
3967  lpStringPtrW,
3968  -1,
3969  lpStringPtrA,
3970  (int)wcslen(lpStringPtrW),
3971  0,
3972  0);
3973 
3974  lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3975  lpStringPtrA += wcslen(lpStringPtrW) + 1;
3976  lpStringPtrW += wcslen(lpStringPtrW) + 1;
3977 
3978  /* Copy the status information */
3979  memcpy(&lpStatusPtrA->ServiceStatus,
3980  &lpStatusPtrIncrW->ServiceStatus,
3981  sizeof(SERVICE_STATUS));
3982 
3983  lpStatusPtrIncrW++;
3984  lpStatusPtrA++;
3985  }
3986 
3987 Done:
3988  if (lpStatusPtrW)
3989  HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3990 
3991  DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3992 
3993  return dwError;
3994 }
3995 
3996 
3997 /* Function 27 */
3998 DWORD
3999 WINAPI
4001  LPSTR lpMachineName,
4002  LPSTR lpDatabaseName,
4003  DWORD dwDesiredAccess,
4004  LPSC_RPC_HANDLE lpScHandle)
4005 {
4007  UNICODE_STRING DatabaseName;
4008  DWORD dwError;
4009 
4010  DPRINT("ROpenSCManagerA() called\n");
4011 
4012  if (lpMachineName)
4014  lpMachineName);
4015 
4016  if (lpDatabaseName)
4017  RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
4018  lpDatabaseName);
4019 
4020  dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
4021  lpDatabaseName ? DatabaseName.Buffer : NULL,
4022  dwDesiredAccess,
4023  lpScHandle);
4024 
4025  if (lpMachineName)
4027 
4028  if (lpDatabaseName)
4029  RtlFreeUnicodeString(&DatabaseName);
4030 
4031  return dwError;
4032 }
4033 
4034 
4035 /* Function 28 */
4036 DWORD
4037 WINAPI
4040  LPSTR lpServiceName,
4041  DWORD dwDesiredAccess,
4042  LPSC_RPC_HANDLE lpServiceHandle)
4043 {
4045  DWORD dwError;
4046 
4047  DPRINT("ROpenServiceA() called\n");
4048 
4049  if (lpServiceName)
4051  lpServiceName);
4052 
4053  dwError = ROpenServiceW(hSCManager,
4054  lpServiceName ? ServiceName.Buffer : NULL,
4055  dwDesiredAccess,
4056  lpServiceHandle);
4057 
4058  if (lpServiceName)
4060 
4061  return dwError;
4062 }
4063 
4064 
4065 /* Function 29 */
4066 DWORD
4067 WINAPI
4069  SC_RPC_HANDLE hService,
4070  LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4071  DWORD cbBufSize,
4073 {
4074  LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
4075  DWORD dwError = ERROR_SUCCESS;
4076  PSERVICE_HANDLE hSvc;
4077  PSERVICE lpService = NULL;
4078  HKEY hServiceKey = NULL;
4079  LPWSTR lpImagePath = NULL;
4080  LPWSTR lpServiceStartName = NULL;
4081  LPWSTR lpDependencies = NULL;
4082  DWORD dwDependenciesLength = 0;
4083  DWORD dwRequiredSize;
4084  LPSTR lpStr;
4085 
4086  DPRINT("RQueryServiceConfigA() called\n");
4087 
4088  if (ScmShutdown)
4090 
4091  hSvc = ScmGetServiceFromHandle(hService);
4092  if (hSvc == NULL)
4093  {
4094  DPRINT1("Invalid service handle!\n");
4095  return ERROR_INVALID_HANDLE;
4096  }
4097 
4100  {
4101  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4102  return ERROR_ACCESS_DENIED;
4103  }
4104 
4105  lpService = hSvc->ServiceEntry;
4106  if (lpService == NULL)
4107  {
4108  DPRINT("lpService == NULL!\n");
4109  return ERROR_INVALID_HANDLE;
4110  }
4111 
4112  /* Lock the service database shared */
4114 
4115  dwError = ScmOpenServiceKey(lpService->lpServiceName,
4116  KEY_READ,
4117  &hServiceKey);
4118  if (dwError != ERROR_SUCCESS)
4119  goto Done;
4120 
4121  /* Read the image path */
4122  dwError = ScmReadString(hServiceKey,
4123  L"ImagePath",
4124  &lpImagePath);
4125  if (dwError != ERROR_SUCCESS)
4126  goto Done;
4127 
4128  /* Read the service start name */
4129  ScmReadString(hServiceKey,
4130  L"ObjectName",
4131  &lpServiceStartName);
4132 
4133  /* Read the dependencies */
4134  ScmReadDependencies(hServiceKey,
4135  &lpDependencies,
4136  &dwDependenciesLength);
4137 
4138  dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA);
4139 
4140  if (lpImagePath != NULL)
4141  dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
4142  else
4143  dwRequiredSize += 2 * sizeof(CHAR);
4144 
4145  if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
4146  dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
4147  else
4148  dwRequiredSize += 2 * sizeof(CHAR);
4149 
4150  /* Add Dependencies length */
4151  if (lpDependencies != NULL)
4152  dwRequiredSize += dwDependenciesLength;
4153  else
4154  dwRequiredSize += 2 * sizeof(CHAR);
4155 
4156  if (lpServiceStartName != NULL)
4157  dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
4158  else
4159  dwRequiredSize += 2 * sizeof(CHAR);
4160 
4161  if (lpService->lpDisplayName != NULL)
4162  dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
4163  else
4164  dwRequiredSize += 2 * sizeof(CHAR);
4165 
4166  if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
4167  {
4168  dwError = ERROR_INSUFFICIENT_BUFFER;
4169  }
4170  else
4171  {
4172  lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
4173  lpServiceConfig->dwStartType = lpService->dwStartType;
4174  lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
4175  lpServiceConfig->dwTagId = lpService->dwTag;
4176 
4177  lpStr = (LPSTR)(lpServiceConfig + 1);
4178 
4179  /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4180  Verified in WINXP */
4181 
4182  if (lpImagePath)
4183  {
4185  0,
4186  lpImagePath,
4187  -1,
4188  lpStr,
4189  (int)(wcslen(lpImagePath) + 1),
4190  0,
4191  0);
4192  }
4193  else
4194  {
4195  *lpStr = 0;
4196  }
4197 
4198  lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4199  lpStr += (strlen((LPSTR)lpStr) + 1);
4200 
4201  if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4202  {
4204  0,
4205  lpService->lpGroup->lpGroupName,
4206  -1,
4207  lpStr,
4208  (int)(wcslen(lpService->lpGroup->lpGroupName) + 1),
4209  0,
4210  0);
4211  }
4212  else
4213  {
4214  *lpStr = 0;
4215  }
4216 
4217  lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4218  lpStr += (strlen(lpStr) + 1);
4219 
4220  /* Append Dependencies */
4221  if (lpDependencies)
4222  {
4224  0,
4225  lpDependencies,
4226  dwDependenciesLength,
4227  lpStr,
4228  dwDependenciesLength,
4229  0,
4230  0);
4231  }
4232  else
4233  {
4234  *lpStr = 0;
4235  }
4236 
4237  lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4238  if (lpDependencies)
4239  lpStr += dwDependenciesLength;
4240  else
4241  lpStr += (strlen(lpStr) + 1);
4242 
4243  if (lpServiceStartName)
4244  {
4246  0,
4247  lpServiceStartName,
4248  -1,
4249  lpStr,
4250  (int)(wcslen(lpServiceStartName) + 1),
4251  0,
4252  0);
4253  }
4254  else
4255  {
4256  *lpStr = 0;
4257  }
4258 
4259  lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4260  lpStr += (strlen(lpStr) + 1);
4261 
4262  if (lpService->lpDisplayName)
4263  {
4265  0,
4266  lpService->lpDisplayName,
4267  -1,
4268  lpStr,
4269  (int)(wcslen(lpService->lpDisplayName) + 1),
4270  0,
4271  0);
4272  }
4273  else
4274  {
4275  *lpStr = 0;
4276  }
4277 
4278  lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4279  }
4280 
4281  if (pcbBytesNeeded != NULL)
4282  *pcbBytesNeeded = dwRequiredSize;
4283 
4284 Done:
4285  /* Unlock the service database */
4287 
4288  if (lpImagePath != NULL)
4289  HeapFree(GetProcessHeap(), 0, lpImagePath);
4290 
4291  if (lpServiceStartName != NULL)
4292  HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4293 
4294  if (lpDependencies != NULL)
4295  HeapFree(GetProcessHeap(), 0, lpDependencies);
4296 
4297  if (hServiceKey != NULL)
4298  RegCloseKey(hServiceKey);
4299 
4300  DPRINT("RQueryServiceConfigA() done\n");
4301 
4302  return dwError;
4303 }
4304 
4305 
4306 /* Function 30 */
4307 DWORD
4308 WINAPI
4311  LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4312  DWORD cbBufSize,
4314 {
4316  PMANAGER_HANDLE hMgr;
4317  DWORD dwRequiredSize;
4318 
4319  if (!lpLockStatus || !pcbBytesNeeded)
4320  return ERROR_INVALID_PARAMETER;
4321 
4323  if (hMgr == NULL)
4324  {
4325  DPRINT1("Invalid service manager handle!\n");
4326  return ERROR_INVALID_HANDLE;
4327  }
4328 
4331  {
4332  DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
4333  return ERROR_ACCESS_DENIED;
4334  }
4335 
4336  /* FIXME: we need to compute instead the real length of the owner name */
4337  dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR);
4338  *pcbBytesNeeded = dwRequiredSize;
4339 
4340  if (cbBufSize < dwRequiredSize)
4342 
4343  ScmQueryServiceLockStatusA(lpLockStatus);
4344 
4345  return ERROR_SUCCESS;
4346 }
4347 
4348 
4349 /* Function 31 */
4350 DWORD
4351 WINAPI
4353  SC_RPC_HANDLE hService,
4354  DWORD argc,
4356 {
4357  DWORD dwError = ERROR_SUCCESS;
4358  PSERVICE_HANDLE hSvc;
4359  PSERVICE lpService = NULL;
4360  LPWSTR *lpVector = NULL;
4361  DWORD i;
4362  DWORD dwLength;
4363 
4364  DPRINT("RStartServiceA() called\n");
4365 
4366  if (ScmShutdown)
4368 
4369  hSvc = ScmGetServiceFromHandle(hService);
4370  if (hSvc == NULL)
4371  {
4372  DPRINT1("Invalid service handle!\n");
4373  return ERROR_INVALID_HANDLE;
4374  }
4375 
4377  SERVICE_START))
4378  {
4379  DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4380  return ERROR_ACCESS_DENIED;
4381  }
4382 
4383  lpService = hSvc->ServiceEntry;
4384  if (lpService == NULL)
4385  {
4386  DPRINT("lpService == NULL!\n");
4387  return ERROR_INVALID_HANDLE;
4388  }
4389 
4390  if (lpService->dwStartType == SERVICE_DISABLED)
4391  return ERROR_SERVICE_DISABLED;
4392 
4393  if (lpService->bDeleted)
4395 
4396  /* Build a Unicode argument vector */
4397  if (argc > 0)
4398  {
4399  lpVector = HeapAlloc(GetProcessHeap(),
4401  argc * sizeof(LPWSTR));
4402  if (lpVector == NULL)
4403  return ERROR_NOT_ENOUGH_MEMORY;
4404 
4405  for (i = 0; i < argc; i++)
4406  {
4408  0,
4409  ((LPSTR*)argv)[i],
4410  -1,
4411  NULL,
4412  0);
4413 
4414  lpVector[i] = HeapAlloc(GetProcessHeap(),
4416  dwLength * sizeof(WCHAR));
4417  if (lpVector[i] == NULL)
4418  {
4419  dwError = ERROR_NOT_ENOUGH_MEMORY;
4420  goto done;
4421  }
4422 
4424  0,
4425  ((LPSTR*)argv)[i],
4426  -1,
4427  lpVector[i],
4428  dwLength);
4429  }
4430  }
4431 
4432  /* Start the service */
4433  dwError = ScmStartService(lpService, argc, lpVector);
4434 
4435 done:
4436  /* Free the Unicode argument vector */
4437  if (lpVector != NULL)
4438  {
4439  for (i = 0; i < argc; i++)
4440  {
4441  if (lpVector[i] != NULL)
4442  HeapFree(GetProcessHeap(), 0, lpVector[i]);
4443  }
4444  HeapFree(GetProcessHeap(), 0, lpVector);
4445  }
4446 
4447  return dwError;
4448 }
4449 
4450 
4451 /* Function 32 */
4452 DWORD
4453 WINAPI
4456  LPCSTR lpServiceName,
4458  LPBOUNDED_DWORD_4K lpcchBuffer)
4459 {
4460  // PMANAGER_HANDLE hManager;
4461  PSERVICE lpService = NULL;
4462  LPCWSTR lpSvcDisplayName;
4463  LPWSTR lpServiceNameW;
4464  DWORD dwLength;
4465 
4466  DPRINT("RGetServiceDisplayNameA() called\n");
4467  DPRINT("hSCManager = %p\n", hSCManager);
4468  DPRINT("lpServiceName: %s\n", lpServiceName);
4469  DPRINT("lpDisplayName: %p\n", lpDisplayName);
4470  DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4471 
4472 #if 0
4473  hManager = (PMANAGER_HANDLE)hSCManager;
4474  if (hManager->Handle.Tag != MANAGER_TAG)
4475  {
4476  DPRINT("Invalid manager handle!\n");
4477  return ERROR_INVALID_HANDLE;
4478  }
4479 #endif
4480 
4481  /* Get service database entry */
4482  if (lpServiceName != NULL)
4483  {
4484  dwLength = (DWORD)(strlen(lpServiceName) + 1);
4485  lpServiceNameW = HeapAlloc(GetProcessHeap(),
4487  dwLength * sizeof(WCHAR));
4488  if (!lpServiceNameW)
4489  return ERROR_NOT_ENOUGH_MEMORY;
4490 
4492  0,
4493  lpServiceName,
4494  -1,
4495  lpServiceNameW,
4496  dwLength);
4497 
4498  lpService = ScmGetServiceEntryByName(lpServiceNameW);
4499 
4500  HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4501  }
4502 
4503  if (lpService == NULL)
4504  {
4505  DPRINT("Could not find the service!\n");
4507  }
4508 
4509  if (lpService->lpDisplayName)
4510  lpSvcDisplayName = lpService->lpDisplayName;
4511  else
4512  lpSvcDisplayName = lpService->lpServiceName;
4513 
4514  /*
4515  * NOTE: On Windows the comparison on *lpcchBuffer is made against
4516  * the number of (wide) characters of the UNICODE display name, and
4517  * not against the number of bytes needed to store the ANSI string.
4518  */
4519  dwLength = (DWORD)wcslen(lpSvcDisplayName);
4520 
4521  if (*lpcchBuffer > dwLength)
4522  {
4523  if (lpDisplayName != NULL &&
4525  0,
4526  lpSvcDisplayName,
4527  -1,
4528  lpDisplayName,
4529  (int)*lpcchBuffer,
4530  NULL,
4531  NULL) == 0)
4532  {
4533  /*
4534  * But then, if *lpcchBuffer was greater than the number of
4535  * (wide) characters of the UNICODE display name, yet smaller
4536  * than the number of bytes needed due to the possible presence
4537  * of DBCS characters, the *exact* number of bytes is returned
4538  * (without the NULL terminator).
4539  */
4541  0,
4542  lpSvcDisplayName,
4543  (int)dwLength,
4544  NULL,
4545  0,
4546  NULL,
4547  NULL);
4548  *lpDisplayName = 0;
4549  *lpcchBuffer = dwLength;
4551  }
4552 
4553  /*
4554  * NOTE: On Windows, RGetServiceDisplayNameA() does not update
4555  * *lpcchBuffer on success, contrary to RGetServiceDisplayNameW().
4556  */
4557  return ERROR_SUCCESS;
4558  }
4559  else
4560  {
4561  /*
4562  * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4563  * (wide) characters of the UNICODE display name, only an upper
4564  * estimation is returned by doubling the string length, to account
4565  * for the presence of any possible DBCS characters.
4566  */
4567  *lpcchBuffer = dwLength * sizeof(WCHAR);
4569  }
4570 }
4571 
4572 
4573 /* Function 33 */
4574 DWORD
4575 WINAPI
4579  LPSTR lpServiceName,
4580  LPBOUNDED_DWORD_4K lpcchBuffer)
4581 {
4582  // PMANAGER_HANDLE hManager;
4583  PSERVICE lpService;
4584  LPWSTR lpDisplayNameW;
4585  DWORD dwLength;
4586 
4587  DPRINT("RGetServiceKeyNameA() called\n");
4588  DPRINT("hSCManager = %p\n", hSCManager);
4589  DPRINT("lpDisplayName: %s\n", lpDisplayName);
4590  DPRINT("lpServiceName: %p\n", lpServiceName);
4591  DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4592 
4593 #if 0
4594  hManager = (PMANAGER_HANDLE)hSCManager;
4595  if (hManager->Handle.Tag != MANAGER_TAG)
4596  {
4597  DPRINT("Invalid manager handle!\n");
4598  return ERROR_INVALID_HANDLE;
4599  }
4600 #endif
4601 
4602  /* Get service database entry */
4603 
4604  dwLength = (DWORD)(strlen(lpDisplayName) + 1);
4605  lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4607  dwLength * sizeof(WCHAR));
4608  if (!lpDisplayNameW)
4609  return ERROR_NOT_ENOUGH_MEMORY;
4610 
4612  0,
4613  lpDisplayName,
4614  -1,
4615  lpDisplayNameW,
4616  dwLength);
4617 
4618  lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4619 
4620  HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4621 
4622  if (lpService == NULL)
4623  {
4624  DPRINT("Could not find the service!\n");
4626  }
4627 
4628  /*
4629  * NOTE: On Windows the comparison on *lpcchBuffer is made against
4630  * the number of (wide) characters of the UNICODE service name, and
4631  * not against the number of bytes needed to store the ANSI string.
4632  */
4633  dwLength = (DWORD)wcslen(lpService->lpServiceName);
4634 
4635  if (*lpcchBuffer > dwLength)
4636  {
4637  if (lpServiceName != NULL &&
4639  0,
4640  lpService->lpServiceName,
4641  -1,
4642  lpServiceName,
4643  (int)*lpcchBuffer,
4644  NULL,
4645  NULL) == 0)
4646  {
4647  /*
4648  * But then, if *lpcchBuffer was greater than the number of
4649  * (wide) characters of the UNICODE service name, yet smaller
4650  * than the number of bytes needed due to the possible presence
4651  * of DBCS characters, the *exact* number of bytes is returned
4652  * (without the NULL terminator).
4653  */
4655  0,
4656  lpService->lpServiceName,
4657  (int)dwLength,
4658  NULL,
4659  0,
4660  NULL,
4661  NULL);
4662  *lpServiceName = 0;
4663  *lpcchBuffer = dwLength;
4665  }
4666 
4667  /*
4668  * NOTE: On Windows, RGetServiceKeyNameA() does not update
4669  * *lpcchBuffer on success, contrary to RGetServiceKeyNameW().
4670  */
4671  return ERROR_SUCCESS;
4672  }
4673  else
4674  {
4675  /*
4676  * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4677  * (wide) characters of the UNICODE service name, only an upper
4678  * estimation is returned by doubling the string length, to account
4679  * for the presence of any possible DBCS characters.
4680  */
4681  *lpcchBuffer = dwLength * sizeof(WCHAR);
4683  }
4684 }
4685 
4686 
4687 /* Function 34 */
4688 DWORD
4689 WINAPI
4692  LPWSTR lpLoadOrderGroup,
4693  LPDWORD lpState)
4694 {
4695  PMANAGER_HANDLE hManager;
4696  PSERVICE_GROUP pServiceGroup;
4697  DWORD dwError = ERROR_SUCCESS;
4698 
4699  DPRINT("RI_ScGetCurrentGroupStateW() called\n");
4700 
4701  if (ScmShutdown)
4703 
4705  if (hManager == NULL)
4706  {
4707  DPRINT1("Invalid service manager handle!\n");
4708  return ERROR_INVALID_HANDLE;
4709  }
4710 
4711  /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */
4714  {
4715  DPRINT("Insufficient access rights! 0x%lx\n",
4716  hManager->Handle.DesiredAccess);
4717  return ERROR_ACCESS_DENIED;
4718  }
4719 
4720  /* Lock the service database shared */
4722 
4723  /* Get the group list entry */
4724  pServiceGroup = ScmGetServiceGroupByName(lpLoadOrderGroup);
4725  if (pServiceGroup == NULL)
4726  {
4727  dwError = ERROR_SERVICE_DOES_NOT_EXIST;
4728  goto done;
4729  }
4730 
4731  /* FIXME: Return the group state */
4732  *lpState = 0;
4733 
4734 done:
4735  /* Unlock the service database */
4737 
4738  DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError);
4739 
4740  return dwError;
4741 }
4742 
4743 
4744 /* Function 35 */
4745 DWORD
4746 WINAPI
4749  DWORD dwServiceType,
4750  DWORD dwServiceState,
4751  LPBYTE lpBuffer,
4752  DWORD cbBufSize,
4754  LPBOUNDED_DWORD_256K lpServicesReturned,
4755  LPBOUNDED_DWORD_256K lpResumeIndex,
4756  LPCWSTR pszGroupName)
4757 {
4758  PMANAGER_HANDLE hManager;
4759  PSERVICE lpService;
4760  DWORD dwError = ERROR_SUCCESS;
4761  PLIST_ENTRY ServiceEntry;
4762  PSERVICE CurrentService;
4763  DWORD dwState;
4764  DWORD dwRequiredSize;
4765  DWORD dwServiceCount;
4766  DWORD dwSize;
4767  DWORD dwLastResumeCount = 0;
4768  LPENUM_SERVICE_STATUSW lpStatusPtr;
4769  LPWSTR lpStringPtr;
4770 
4771  DPRINT("REnumServiceGroupW() called\n");
4772 
4773  if (ScmShutdown)
4775 
4777  if (hManager == NULL)
4778  {
4779  DPRINT1("Invalid service manager handle!\n");
4780  return ERROR_INVALID_HANDLE;
4781  }
4782 
4783  if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
4784  {
4785  return ERROR_INVALID_ADDRESS;
4786  }
4787 
4788  *pcbBytesNeeded = 0;
4789  *lpServicesReturned = 0;
4790 
4791  if ((dwServiceType == 0) ||
4792  ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
4793  {
4794  DPRINT("Not a valid Service Type!\n");
4795  return ERROR_INVALID_PARAMETER;
4796  }
4797 
4798  if ((dwServiceState == 0) ||
4799  ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
4800  {
4801  DPRINT("Not a valid Service State!\n");
4802  return ERROR_INVALID_PARAMETER;
4803  }
4804 
4805  /* Check access rights */
4808  {
4809  DPRINT("Insufficient access rights! 0x%lx\n",
4810  hManager->Handle.DesiredAccess);
4811  return ERROR_ACCESS_DENIED;
4812  }
4813 
4814  if (lpResumeIndex)
4815  dwLastResumeCount = *lpResumeIndex;
4816 
4817  /* Lock the service database shared */
4819 
4820  lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4821  if (lpService == NULL)
4822  {
4823  dwError = ERROR_SUCCESS;
4824  goto Done;
4825  }
4826 
4827  dwRequiredSize = 0;
4828  dwServiceCount = 0;
4829 
4830  for (ServiceEntry = &lpService->ServiceListEntry;
4831  ServiceEntry != &ServiceListHead;
4832  ServiceEntry = ServiceEntry->Flink)
4833  {
4834  CurrentService = CONTAINING_RECORD(ServiceEntry,
4835  SERVICE,
4836  ServiceListEntry);
4837 
4838  if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4839  continue;
4840 
4841  dwState = SERVICE_ACTIVE;
4842  if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4843  dwState = SERVICE_INACTIVE;
4844 
4845  if ((dwState & dwServiceState) == 0)
4846  continue;
4847 
4848  if (pszGroupName)
4849  {
4850  if (*pszGroupName == 0)
4851  {
4852  if (CurrentService->lpGroup != NULL)
4853  continue;
4854  }
4855  else
4856  {
4857  if ((CurrentService->lpGroup == NULL) ||
4858  _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4859  continue;
4860  }
4861  }
4862 
4863  dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4864  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4865  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4866 
4867  if (dwRequiredSize + dwSize > cbBufSize)
4868  {
4869  DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4870  break;
4871  }
4872 
4873  DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4874  dwRequiredSize += dwSize;
4875  dwServiceCount++;
4876  dwLastResumeCount = CurrentService->dwResumeCount;
4877  }
4878 
4879  DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4880  DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4881 
4882  for (;
4883  ServiceEntry != &ServiceListHead;
4884  ServiceEntry = ServiceEntry->Flink)
4885  {
4886  CurrentService = CONTAINING_RECORD(ServiceEntry,
4887  SERVICE,
4888  ServiceListEntry);
4889 
4890  if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4891  continue;
4892 
4893  dwState = SERVICE_ACTIVE;
4894  if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4895  dwState = SERVICE_INACTIVE;
4896 
4897  if ((dwState & dwServiceState) == 0)
4898  continue;
4899 
4900  if (pszGroupName)
4901  {
4902  if (*pszGroupName == 0)
4903  {
4904  if (CurrentService->lpGroup != NULL)
4905  continue;
4906  }
4907  else
4908  {
4909  if ((CurrentService->lpGroup == NULL) ||
4910  _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4911  continue;
4912  }
4913  }
4914 
4915  dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
4916  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4917  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4918 
4919  dwError = ERROR_MORE_DATA;
4920  }
4921 
4922  DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4923 
4924  if (lpResumeIndex)
4925  *lpResumeIndex = dwLastResumeCount;
4926 
4927  *lpServicesReturned = dwServiceCount;
4928  *pcbBytesNeeded = dwRequiredSize;
4929 
4930  lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
4931  lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
4932  dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
4933 
4934  dwRequiredSize = 0;
4935  for (ServiceEntry = &lpService->ServiceListEntry;
4936  ServiceEntry != &ServiceListHead;
4937  ServiceEntry = ServiceEntry->Flink)
4938  {
4939  CurrentService = CONTAINING_RECORD(ServiceEntry,
4940  SERVICE,
4941  ServiceListEntry);
4942 
4943  if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4944  continue;
4945 
4946  dwState = SERVICE_ACTIVE;
4947  if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4948  dwState = SERVICE_INACTIVE;
4949 
4950  if ((dwState & dwServiceState) == 0)
4951  continue;
4952 
4953  if (pszGroupName)
4954  {
4955  if (*pszGroupName == 0)
4956  {
4957  if (CurrentService->lpGroup != NULL)
4958  continue;
4959  }
4960  else
4961  {
4962  if ((CurrentService->lpGroup == NULL) ||
4963  _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4964  continue;
4965  }
4966  }
4967 
4968  dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4969  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4970  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4971 
4972  if (dwRequiredSize + dwSize > cbBufSize)
4973  break;
4974 
4975  /* Copy the service name */
4976  wcscpy(lpStringPtr, CurrentService->lpServiceName);
4977  lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4978  lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
4979 
4980  /* Copy the display name */
4981  wcscpy(lpStringPtr, CurrentService->lpDisplayName);
4982  lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4983  lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
4984 
4985  /* Copy the status information */
4986  memcpy(&lpStatusPtr->ServiceStatus,
4987  &CurrentService->Status,
4988  sizeof(SERVICE_STATUS));
4989 
4990  lpStatusPtr++;
4991  dwRequiredSize += dwSize;
4992  }
4993 
4994  if (dwError == ERROR_SUCCESS)
4995  {
4996  *pcbBytesNeeded = 0;
4997  if (lpResumeIndex) *lpResumeIndex = 0;
4998  }
4999 
5000 Done:
5001  /* Unlock the service database */
5003 
5004  DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError);
5005 
5006  return dwError;
5007 }
5008 
5009 
5010 /* Function 36 */
5011 DWORD
5012 WINAPI
5014  SC_RPC_HANDLE hService,
5016 {
5017  SC_RPC_CONFIG_INFOW InfoW = { 0 };
5018  DWORD dwRet, dwLength;
5019  PVOID ptr = NULL;
5020 
5021  DPRINT("RChangeServiceConfig2A() called\n");
5022  DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
5023 
5024  if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
5025  (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
5026  {
5027  return ERROR_INVALID_LEVEL;
5028  }
5029 
5030  InfoW.dwInfoLevel = Info.dwInfoLevel;
5031 
5033  {
5034  LPSERVICE_DESCRIPTIONW lpServiceDescriptionW;
5035  LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
5036 
5037  lpServiceDescriptionA = Info.psd;
5038 
5039  if (lpServiceDescriptionA &&
5040  lpServiceDescriptionA->lpDescription)
5041  {
5042  dwLength = (DWORD)((strlen(lpServiceDescriptionA->lpDescription) + 1) * sizeof(WCHAR));
5043 
5044  lpServiceDescriptionW = HeapAlloc(GetProcessHeap(),
5046  dwLength + sizeof(SERVICE_DESCRIPTIONW));
5047  if (!lpServiceDescriptionW)
5048  {
5049  return ERROR_NOT_ENOUGH_MEMORY;
5050  }
5051 
5052  lpServiceDescriptionW->lpDescription = (LPWSTR)(lpServiceDescriptionW + 1);
5053 
5055  0,
5056  lpServiceDescriptionA->lpDescription,
5057  -1,
5058  lpServiceDescriptionW->lpDescription,
5059  dwLength);
5060 
5061  ptr = lpServiceDescriptionW;
5062  InfoW.psd = lpServiceDescriptionW;
5063  }
5064  }
5065  else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5066  {
5067  LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
5068  LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
5069  DWORD dwRebootLen = 0;
5070  DWORD dwCommandLen = 0;
5071  DWORD dwActionArrayLen = 0;
5072  LPWSTR lpStr = NULL;
5073 
5074  lpServiceFailureActionsA = Info.psfa;
5075 
5076  if (lpServiceFailureActionsA)
5077  {
5078  /*
5079  * The following code is inspired by the
5080  * SERVICE_CONFIG_FAILURE_ACTIONS case of
5081  * the RQueryServiceConfig2W function.
5082  */
5083 
5084  /* Retrieve the needed length for the two data strings */
5085  if (lpServiceFailureActionsA->lpRebootMsg)
5086  {
5087  dwRebootLen = (DWORD)((strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR));
5088  }
5089  if (lpServiceFailureActionsA->lpCommand)
5090  {
5091  dwCommandLen = (DWORD)((strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR));
5092  }
5093 
5094  /*
5095  * Retrieve the size of the lpsaActions array if needed.
5096  * We will copy the lpsaActions array only if there is at
5097  * least one action AND that the original array is valid.
5098  */
5099  if (lpServiceFailureActionsA->cActions > 0 && lpServiceFailureActionsA->lpsaActions)
5100  {
5101  dwActionArrayLen = lpServiceFailureActionsA->cActions * sizeof(SC_ACTION);
5102  }
5103 
5104  /* Compute the total length for the UNICODE structure, including data */
5106  dwActionArrayLen + dwRebootLen + dwCommandLen;
5107 
5108  /* Allocate the structure */
5109  lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
5111  dwLength);
5112  if (!lpServiceFailureActionsW)
5113  {
5114  return ERROR_NOT_ENOUGH_MEMORY;
5115  }
5116 
5117  /* Copy the members */
5118  lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
5119  lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
5120 
5121  /* Copy the lpsaActions array if needed */
5122  if (dwActionArrayLen > 0)
5123  {
5124  /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
5125  lpServiceFailureActionsW->lpsaActions = (LPSC_ACTION)((ULONG_PTR)(lpServiceFailureActionsW + 1));
5126 
5127  /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
5128  RtlCopyMemory(lpServiceFailureActionsW->lpsaActions,
5129  lpServiceFailureActionsA->lpsaActions,
5130  dwActionArrayLen);
5131  }
5132  else
5133  {
5134  /* No lpsaActions array */
5135  lpServiceFailureActionsW->lpsaActions = NULL;
5136  }
5137  /* The data strings are stored just after the lpsaActions array */
5138  lpStr = (LPWSTR)((ULONG_PTR)(lpServiceFailureActionsW + 1) + dwActionArrayLen);
5139 
5140  /*
5141  * Convert the data strings to UNICODE
5142  */
5143 
5144  lpServiceFailureActionsW->lpRebootMsg = NULL;
5145  lpServiceFailureActionsW->lpCommand = NULL;
5146 
5147  if (dwRebootLen)
5148  {
5149  /* lpRebootMsg points just after the lpsaActions array */
5150  lpServiceFailureActionsW->lpRebootMsg = lpStr;
5151 
5153  0,
5154  lpServiceFailureActionsA->lpRebootMsg,
5155  -1,
5156  lpServiceFailureActionsW->lpRebootMsg,
5157  dwRebootLen);
5158 
5159  lpStr += dwRebootLen / sizeof(WCHAR);
5160  }
5161 
5162  if (dwCommandLen)
5163  {
5164  /* lpRebootMsg points just after the lpRebootMsg data string */
5165  lpServiceFailureActionsW->lpCommand = lpStr;
5166 
5168  0,
5169  lpServiceFailureActionsA->lpCommand,
5170  -1,
5171  lpServiceFailureActionsW->lpCommand,
5172  dwCommandLen);
5173  }
5174 
5175  /* Set the pointers */
5176  ptr = lpServiceFailureActionsW;
5177  InfoW.psfa = lpServiceFailureActionsW;
5178  }
5179  }
5180 
5181  dwRet = RChangeServiceConfig2W(hService, InfoW);
5182 
5183  HeapFree(GetProcessHeap(), 0, ptr);
5184 
5185  return dwRet;
5186 }
5187 
5188 
5189 static DWORD
5191  LPSERVICE_FAILURE_ACTIONSW lpFailureActions)
5192 {
5193  LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL;
5194  LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL;
5195  DWORD dwRequiredSize = 0;
5196  DWORD dwType = 0;
5197  DWORD dwError;
5198 
5199  /* There is nothing to be done if we have no failure actions */
5200  if (lpFailureActions == NULL)
5201  return ERROR_SUCCESS;
5202 
5203  /*
5204  * 1- Retrieve the original value of FailureActions.
5205  */
5206 
5207  /* Query value length */
5208  dwError = RegQueryValueExW(hServiceKey,
5209  L"FailureActions",
5210  NULL,
5211  &dwType,
5212  NULL,
5213  &dwRequiredSize);
5214  if (dwError != ERROR_SUCCESS &&
5215  dwError != ERROR_MORE_DATA &&
5216  dwError != ERROR_FILE_NOT_FOUND)
5217  {
5218  return dwError;
5219  }
5220 
5221  dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
5222  : sizeof(SERVICE_FAILURE_ACTIONSW);
5223 
5224  /* Initialize the read buffer */
5225  lpReadBuffer = HeapAlloc(GetProcessHeap(),
5227  dwRequiredSize);
5228  if (lpReadBuffer == NULL)
5229  return ERROR_NOT_ENOUGH_MEMORY;
5230 
5231  /* Now we can fill the read buffer */
5232  if (dwError != ERROR_FILE_NOT_FOUND &&
5233  dwType == REG_BINARY)
5234  {
5235  dwError = RegQueryValueExW(hServiceKey,
5236  L"FailureActions",
5237  NULL,
5238  NULL,
5239  (LPBYTE)lpReadBuffer,
5240  &dwRequiredSize);
5241  if (dwError != ERROR_SUCCESS &&
5242  dwError != ERROR_FILE_NOT_FOUND)
5243  goto done;
5244 
5245  if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
5246  dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5247  }
5248  else
5249  {
5250  /*
5251  * The value of the error doesn't really matter, the only
5252  * important thing is that it must be != ERROR_SUCCESS.
5253  */
5254  dwError = ERROR_INVALID_DATA;
5255  }
5256 
5257  if (dwError == ERROR_SUCCESS)
5258  {
5259  lpReadBuffer->cActions = min(lpReadBuffer->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
5260  lpReadBuffer->lpsaActions = (lpReadBuffer->cActions > 0 ? (LPSC_ACTION)(lpReadBuffer + 1) : NULL);
5261  }
5262  else
5263  {
5264  lpReadBuffer->dwResetPeriod = 0;
5265  lpReadBuffer->cActions = 0;
5266  lpReadBuffer->lpsaActions = NULL;
5267  }
5268 
5269  lpReadBuffer->lpRebootMsg = NULL;
5270  lpReadBuffer->lpCommand = NULL;
5271 
5272  /*
5273  * 2- Initialize the new value to set.
5274  */
5275 
5276  dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5277 
5278  if (lpFailureActions->lpsaActions == NULL)
5279  {
5280  /*
5281  * lpFailureActions->cActions is ignored.
5282  * Therefore we use the original values
5283  * of cActions and lpsaActions.
5284  */
5285  dwRequiredSize += lpReadBuffer->cActions * sizeof(SC_ACTION);
5286  }
5287  else
5288  {
5289  /*
5290  * The reset period and array of failure actions
5291  * are deleted if lpFailureActions->cActions == 0 .
5292  */
5293  dwRequiredSize += lpFailureActions->cActions * sizeof(SC_ACTION);
5294  }
5295 
5296  lpWriteBuffer = HeapAlloc(GetProcessHeap(),
5298  dwRequiredSize);
5299  if (lpWriteBuffer == NULL)
5300  {
5301  dwError = ERROR_NOT_ENOUGH_MEMORY;
5302  goto done;
5303  }
5304 
5305  /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5306  lpWriteBuffer->lpRebootMsg = NULL;
5307  lpWriteBuffer->lpCommand = NULL;
5308  lpWriteBuffer->lpsaActions = NULL;
5309 
5310  /* Set the members */
5311  if (lpFailureActions->lpsaActions == NULL)
5312  {
5313  /*
5314  * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5315  * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5316  */
5317  lpWriteBuffer->dwResetPeriod = lpReadBuffer->dwResetPeriod;
5318  lpWriteBuffer->cActions = lpReadBuffer->cActions;
5319 
5320  if (lpReadBuffer->lpsaActions != NULL)