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