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