xref: /reactos/base/system/services/rpcserver.c (revision 05c39d8d)
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 {
31     DWORD Tag;
32     DWORD DesiredAccess;
33 } SCMGR_HANDLE;
34 
35 
36 typedef struct _MANAGER_HANDLE
37 {
38     SCMGR_HANDLE Handle;
39     WCHAR DatabaseName[1];
40 } MANAGER_HANDLE, *PMANAGER_HANDLE;
41 
42 
43 typedef struct _SERVICE_HANDLE
44 {
45     SCMGR_HANDLE Handle;
46     PSERVICE ServiceEntry;
47 } SERVICE_HANDLE, *PSERVICE_HANDLE;
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
91 ScmManagerMapping = {SC_MANAGER_READ,
92                      SC_MANAGER_WRITE,
93                      SC_MANAGER_EXECUTE,
94                      SC_MANAGER_ALL_ACCESS};
95 
96 static GENERIC_MAPPING
97 ScmServiceMapping = {SERVICE_READ,
98                      SERVICE_WRITE,
99                      SERVICE_EXECUTE,
100                      SERVICE_ALL_ACCESS};
101 
102 DWORD g_dwServiceBits = 0;
103 
104 /* FUNCTIONS ***************************************************************/
105 
106 VOID
107 ScmStartRpcServer(VOID)
108 {
109     RPC_STATUS Status;
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
144 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
145                        SC_HANDLE *Handle)
146 {
147     PMANAGER_HANDLE Ptr;
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);
155         return ERROR_DATABASE_DOES_NOT_EXIST;
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 
163     Ptr = HeapAlloc(GetProcessHeap(),
164                     HEAP_ZERO_MEMORY,
165                     FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1]));
166     if (Ptr == NULL)
167         return ERROR_NOT_ENOUGH_MEMORY;
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
180 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
181                        SC_HANDLE *Handle)
182 {
183     PSERVICE_HANDLE Ptr;
184 
185     Ptr = HeapAlloc(GetProcessHeap(),
186                     HEAP_ZERO_MEMORY,
187                     sizeof(SERVICE_HANDLE));
188     if (Ptr == NULL)
189         return ERROR_NOT_ENOUGH_MEMORY;
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
202 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE 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     }
211     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
212     {
213         DPRINT1("Exception: Invalid Service Manager handle!\n");
214     }
215     _SEH2_END;
216 
217     return pManager;
218 }
219 
220 
221 static PSERVICE_HANDLE
222 ScmGetServiceFromHandle(SC_RPC_HANDLE 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     }
231     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
232     {
233         DPRINT1("Exception: Invalid Service handle!\n");
234     }
235     _SEH2_END;
236 
237     return pService;
238 }
239 
240 
241 static DWORD
242 ScmCheckAccess(SC_HANDLE Handle,
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,
251                           &ScmManagerMapping);
252 
253         hMgr->Handle.DesiredAccess = dwDesiredAccess;
254 
255         return ERROR_SUCCESS;
256     }
257     else if (hMgr->Handle.Tag == SERVICE_TAG)
258     {
259         RtlMapGenericMask(&dwDesiredAccess,
260                           &ScmServiceMapping);
261 
262         hMgr->Handle.DesiredAccess = dwDesiredAccess;
263 
264         return ERROR_SUCCESS;
265     }
266 
267     return ERROR_INVALID_HANDLE;
268 }
269 
270 
271 DWORD
272 ScmAssignNewTag(PSERVICE lpService)
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 
290     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
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;
406     DWORD BufferSize;
407     WCHAR Dest;
408     WCHAR *Expanded;
409     UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
410     OBJECT_ATTRIBUTES ObjectAttributes;
411     NTSTATUS Status;
412     HANDLE SymbolicLinkHandle;
413 
414     DPRINT("ScmConvertToBootPathName %S\n", CanonName);
415 
416     if (!RelativeName)
417         return ERROR_INVALID_PARAMETER;
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(),
428                                   HEAP_ZERO_MEMORY,
429                                   (ServiceNameLen + 1) * sizeof(WCHAR));
430         if (*RelativeName == NULL)
431         {
432             DPRINT("Error allocating memory for boot driver name!\n");
433             return ERROR_NOT_ENOUGH_MEMORY;
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(),
449                                   HEAP_ZERO_MEMORY,
450                                   ServiceNameLen * sizeof(WCHAR));
451 
452         if (*RelativeName == NULL)
453         {
454             DPRINT("Error allocating memory for boot driver name!\n");
455             return ERROR_NOT_ENOUGH_MEMORY;
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");
471         return ERROR_INVALID_ENVIRONMENT;
472     }
473 
474     /* Allocate memory, since the size is known now */
475     Expanded = HeapAlloc(GetProcessHeap(),
476                          HEAP_ZERO_MEMORY,
477                          (BufferSize + 1) * sizeof(WCHAR));
478     if (!Expanded)
479     {
480         DPRINT("Error allocating memory for boot driver name!\n");
481         return ERROR_NOT_ENOUGH_MEMORY;
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);
490         return ERROR_NOT_ENOUGH_MEMORY;
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");
497         return ERROR_INVALID_ENVIRONMENT;
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(),
507                          HEAP_ZERO_MEMORY,
508                          NtPathName.Length + sizeof(UNICODE_NULL));
509     if (!Expanded)
510     {
511         DPRINT("Error allocating memory for boot driver name!\n");
512         RtlFreeUnicodeString(&NtPathName);
513         return ERROR_NOT_ENOUGH_MEMORY;
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(),
528                                   HEAP_ZERO_MEMORY,
529                                   (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
530         if (*RelativeName == NULL)
531         {
532             DPRINT("Error allocating memory for boot driver name!\n");
533             return ERROR_NOT_ENOUGH_MEMORY;
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");
547     InitializeObjectAttributes(&ObjectAttributes,
548                                &SystemRoot,
549                                OBJ_CASE_INSENSITIVE,
550                                NULL,
551                                NULL);
552 
553     /* Open this symlink */
554     Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
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);
561         if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
562         {
563             /* Check if required buffer size is sane */
564             if (BufferSize > UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL))
565             {
566                 DPRINT("Too large buffer required\n");
567 
568                 NtClose(SymbolicLinkHandle);
569                 return ERROR_NOT_ENOUGH_MEMORY;
570             }
571 
572             /* Alloc the string */
573             LinkTarget.Length = (USHORT)BufferSize;
574             LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL);
575             LinkTarget.Buffer = HeapAlloc(GetProcessHeap(),
576                                           HEAP_ZERO_MEMORY,
577                                           LinkTarget.MaximumLength);
578             if (!LinkTarget.Buffer)
579             {
580                 DPRINT("Unable to alloc buffer\n");
581                 NtClose(SymbolicLinkHandle);
582                 return ERROR_NOT_ENOUGH_MEMORY;
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(),
597                                               HEAP_ZERO_MEMORY,
598                                               (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
599 
600                     if (*RelativeName == NULL)
601                     {
602                         DPRINT("Unable to alloc buffer\n");
603                         return ERROR_NOT_ENOUGH_MEMORY;
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                 {
616                     return ERROR_INVALID_PARAMETER;
617                 }
618             }
619             else
620             {
621                 DPRINT("Error, Status = %08X\n", Status);
622                 return ERROR_INVALID_PARAMETER;
623             }
624         }
625         else
626         {
627             DPRINT("Error, Status = %08X\n", Status);
628             NtClose(SymbolicLinkHandle);
629             return ERROR_INVALID_PARAMETER;
630         }
631     }
632     else
633     {
634         /* Failure */
635         DPRINT("Error, Status = %08X\n", Status);
636         return ERROR_INVALID_PARAMETER;
637     }
638 }
639 
640 
641 DWORD
642 ScmCanonDriverImagePath(DWORD dwStartType,
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(),
661                                  HEAP_ZERO_MEMORY,
662                                  (ServiceNameLen + 1) * sizeof(WCHAR));
663 
664         if (*lpCanonName == NULL)
665         {
666             DPRINT("Error allocating memory for canonized service name!\n");
667             return ERROR_NOT_ENOUGH_MEMORY;
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(),
687                                  HEAP_ZERO_MEMORY,
688                                  (ServiceNameLen + 1) * sizeof(WCHAR));
689 
690         if (*lpCanonName == NULL)
691         {
692             DPRINT("Error allocating memory for canonized service name!\n");
693             return ERROR_NOT_ENOUGH_MEMORY;
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(),
710                                  HEAP_ZERO_MEMORY,
711                                  (ServiceNameLen + 1) * sizeof(WCHAR));
712 
713         if (*lpCanonName == NULL)
714         {
715             DPRINT("Error allocating memory for canonized service name!\n");
716             return ERROR_NOT_ENOUGH_MEMORY;
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");
729         return ERROR_INVALID_PARAMETER;
730     }
731 
732     *lpCanonName = HeapAlloc(GetProcessHeap(),
733                              HEAP_ZERO_MEMORY,
734                              NtServiceName.Length + sizeof(WCHAR));
735 
736     if (*lpCanonName == NULL)
737     {
738         DPRINT("Error allocating memory for canonized service name!\n");
739         RtlFreeUnicodeString(&NtServiceName);
740         return ERROR_NOT_ENOUGH_MEMORY;
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
783 Int_EnumDependentServicesW(HKEY hServicesKey,
784                            PSERVICE lpService,
785                            DWORD dwServiceState,
786                            PSERVICE *lpServices,
787                            LPDWORD pcbBytesNeeded,
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 */
903                         Int_EnumDependentServicesW(hServicesKey,
904                                                    lpCurrentService,
905                                                    dwServiceState,
906                                                    lpServices,
907                                                    pcbBytesNeeded,
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
936 RCloseServiceHandle(
937     LPSC_RPC_HANDLE hSCObject)
938 {
939     PMANAGER_HANDLE hManager;
940     PSERVICE_HANDLE hService;
941     PSERVICE lpService;
942     HKEY hServicesKey;
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 */
977         ScmLockDatabaseExclusive();
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 */
1002                 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1003                                         L"System\\CurrentControlSet\\Services",
1004                                         0,
1005                                         KEY_SET_VALUE | KEY_READ,
1006                                         &hServicesKey);
1007                 if (dwError != ERROR_SUCCESS)
1008                 {
1009                     DPRINT("Failed to open services key\n");
1010                     ScmUnlockDatabase();
1011                     return dwError;
1012                 }
1013 
1014                 /* Call the internal function with NULL, just to get bytes we need */
1015                 Int_EnumDependentServicesW(hServicesKey,
1016                                            lpService,
1017                                            SERVICE_ACTIVE,
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");
1026                     RegCloseKey(hServicesKey);
1027                     ScmUnlockDatabase();
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 
1038                 RegCloseKey(hServicesKey);
1039 
1040                 if (dwError != ERROR_SUCCESS)
1041                 {
1042                     DPRINT("Failed to Delete the Service Registry key\n");
1043                     ScmUnlockDatabase();
1044                     return dwError;
1045                 }
1046 
1047                 /* Delete the Service */
1048                 ScmDeleteServiceRecord(lpService);
1049             }
1050         }
1051 
1052         ScmUnlockDatabase();
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
1069 RControlService(
1070     SC_RPC_HANDLE hService,
1071     DWORD dwControl,
1072     LPSERVICE_STATUS lpServiceStatus)
1073 {
1074     PSERVICE_HANDLE hSvc;
1075     PSERVICE lpService;
1076     ACCESS_MASK DesiredAccess;
1077     DWORD dwError = ERROR_SUCCESS;
1078     DWORD pcbBytesNeeded = 0;
1079     DWORD dwServicesReturned = 0;
1080     DWORD dwControlsAccepted;
1081     DWORD dwCurrentState;
1082     HKEY hServicesKey = NULL;
1083     LPCWSTR lpLogStrings[2];
1084     WCHAR szLogBuffer[80];
1085     UINT uID;
1086 
1087     DPRINT("RControlService() called\n");
1088 
1089     if (ScmShutdown)
1090         return ERROR_SHUTDOWN_IN_PROGRESS;
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:
1112             DesiredAccess = SERVICE_STOP;
1113             break;
1114 
1115         case SERVICE_CONTROL_PAUSE:
1116         case SERVICE_CONTROL_CONTINUE:
1117         case SERVICE_CONTROL_PARAMCHANGE:
1118         case SERVICE_CONTROL_NETBINDADD:
1119         case SERVICE_CONTROL_NETBINDREMOVE:
1120         case SERVICE_CONTROL_NETBINDENABLE:
1121         case SERVICE_CONTROL_NETBINDDISABLE:
1122             DesiredAccess = SERVICE_PAUSE_CONTINUE;
1123             break;
1124 
1125         case SERVICE_CONTROL_INTERROGATE:
1126             DesiredAccess = SERVICE_INTERROGATE;
1127             break;
1128 
1129         default:
1130             if (dwControl >= 128 && dwControl <= 255)
1131                 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
1132             else
1133                 return ERROR_INVALID_PARAMETER;
1134             break;
1135     }
1136 
1137     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
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 */
1152         dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
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 */
1164         Int_EnumDependentServicesW(hServicesKey,
1165                                    lpService,
1166                                    SERVICE_ACTIVE,
1167                                    NULL,
1168                                    &pcbBytesNeeded,
1169                                    &dwServicesReturned);
1170 
1171         RegCloseKey(hServicesKey);
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");
1178             return ERROR_DEPENDENT_SERVICES_RUNNING;
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:
1203                 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1204 
1205             case SERVICE_START_PENDING:
1206                 switch (dwControl)
1207                 {
1208                     case SERVICE_CONTROL_STOP:
1209                         break;
1210 
1211                     case SERVICE_CONTROL_INTERROGATE:
1212                         RtlCopyMemory(lpServiceStatus,
1213                                       &lpService->Status,
1214                                       sizeof(SERVICE_STATUS));
1215                         return ERROR_SUCCESS;
1216 
1217                     default:
1218                         return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
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)
1228                     return ERROR_INVALID_SERVICE_CONTROL;
1229                 break;
1230 
1231             case SERVICE_CONTROL_PAUSE:
1232             case SERVICE_CONTROL_CONTINUE:
1233                 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1234                     return ERROR_INVALID_SERVICE_CONTROL;
1235                 break;
1236 
1237             case SERVICE_CONTROL_PARAMCHANGE:
1238                 if ((dwControlsAccepted & SERVICE_ACCEPT_PARAMCHANGE) == 0)
1239                     return ERROR_INVALID_SERVICE_CONTROL;
1240                 break;
1241 
1242             case SERVICE_CONTROL_NETBINDADD:
1243             case SERVICE_CONTROL_NETBINDREMOVE:
1244             case SERVICE_CONTROL_NETBINDENABLE:
1245             case SERVICE_CONTROL_NETBINDDISABLE:
1246                 if ((dwControlsAccepted & SERVICE_ACCEPT_NETBINDCHANGE) == 0)
1247                     return ERROR_INVALID_SERVICE_CONTROL;
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 
1281                 case SERVICE_CONTROL_CONTINUE:
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 
1290             ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
1291                         EVENTLOG_INFORMATION_TYPE,
1292                         2,
1293                         lpLogStrings);
1294         }
1295     }
1296 
1297     return dwError;
1298 }
1299 
1300 
1301 /* Function 2 */
1302 DWORD
1303 WINAPI
1304 RDeleteService(
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)
1314         return ERROR_SHUTDOWN_IN_PROGRESS;
1315 
1316     hSvc = ScmGetServiceFromHandle(hService);
1317     if (hSvc == NULL)
1318     {
1319         DPRINT1("Invalid service handle!\n");
1320         return ERROR_INVALID_HANDLE;
1321     }
1322 
1323     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
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 */
1335     ScmLockDatabaseExclusive();
1336 
1337     if (lpService->bDeleted)
1338     {
1339         DPRINT("The service has already been marked for delete!\n");
1340         dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
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 */
1351     ScmUnlockDatabase();
1352 
1353     DPRINT("RDeleteService() done\n");
1354 
1355     return dwError;
1356 }
1357 
1358 
1359 /* Function 3 */
1360 DWORD
1361 WINAPI
1362 RLockServiceDatabase(
1363     SC_RPC_HANDLE hSCManager,
1364     LPSC_RPC_LOCK lpLock)
1365 {
1366     PMANAGER_HANDLE hMgr;
1367 
1368     DPRINT("RLockServiceDatabase() called\n");
1369 
1370     *lpLock = NULL;
1371 
1372     hMgr = ScmGetServiceManagerFromHandle(hSCManager);
1373     if (hMgr == NULL)
1374     {
1375         DPRINT1("Invalid service manager handle!\n");
1376         return ERROR_INVALID_HANDLE;
1377     }
1378 
1379     if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
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
1390 RQueryServiceObjectSecurity(
1391     SC_RPC_HANDLE hService,
1392     SECURITY_INFORMATION dwSecurityInformation,
1393     LPBYTE lpSecurityDescriptor,
1394     DWORD cbBufSize,
1395     LPBOUNDED_DWORD_256K pcbBytesNeeded)
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 |
1414                                  GROUP_SECURITY_INFORMATION |
1415                                  OWNER_SECURITY_INFORMATION))
1416         DesiredAccess |= READ_CONTROL;
1417 
1418     if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1419         DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1420 
1421     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
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 */
1436     ScmLockDatabaseShared();
1437 
1438     /* Retrieve the security descriptor */
1439     Status = RtlQuerySecurityObject(lpService->pSecurityDescriptor,
1440                                     dwSecurityInformation,
1441                                     (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1442                                     cbBufSize,
1443                                     &dwBytesNeeded);
1444 
1445     /* Unlock the service database */
1446     ScmUnlockDatabase();
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     }
1458     else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
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
1474 RSetServiceObjectSecurity(
1475     SC_RPC_HANDLE hService,
1476     DWORD dwSecurityInformation,
1477     LPBYTE lpSecurityDescriptor,
1478     DWORD dwSecurityDescriptorSize)
1479 {
1480     PSERVICE_HANDLE hSvc;
1481     PSERVICE lpService;
1482     ACCESS_MASK DesiredAccess = 0;
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
1500         | DACL_SECURITY_INFORMATION | SACL_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)
1509         DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1510 
1511     if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1512         DesiredAccess |= WRITE_DAC;
1513 
1514     if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1515         DesiredAccess |= WRITE_OWNER;
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 
1529     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
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)
1544         return ERROR_SERVICE_MARKED_FOR_DELETE;
1545 
1546 #if 0
1547     RpcImpersonateClient(NULL);
1548 
1549     Status = NtOpenThreadToken(NtCurrentThread(),
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,
1563                                   &ScmServiceMapping,
1564                                   hToken);
1565     if (!NT_SUCCESS(Status))
1566     {
1567         dwError = RtlNtStatusToDosError(Status);
1568         goto Done;
1569     }
1570 
1571     /* Lock the service database exclusive */
1572     ScmLockDatabaseExclusive();
1573     bDatabaseLocked = TRUE;
1574 
1575     /* Open the service key */
1576     dwError = ScmOpenServiceKey(lpService->lpServiceName,
1577                                 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
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)
1594         ScmUnlockDatabase();
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
1608 RQueryServiceStatus(
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)
1618         return ERROR_SHUTDOWN_IN_PROGRESS;
1619 
1620     hSvc = ScmGetServiceFromHandle(hService);
1621     if (hSvc == NULL)
1622     {
1623         DPRINT1("Invalid service handle!\n");
1624         return ERROR_INVALID_HANDLE;
1625     }
1626 
1627     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1628                                   SERVICE_QUERY_STATUS))
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 */
1642     ScmLockDatabaseShared();
1643 
1644     /* Return service status information */
1645     RtlCopyMemory(lpServiceStatus,
1646                   &lpService->Status,
1647                   sizeof(SERVICE_STATUS));
1648 
1649     /* Unlock the service database */
1650     ScmUnlockDatabase();
1651 
1652     return ERROR_SUCCESS;
1653 }
1654 
1655 
1656 static BOOL
1657 ScmIsValidServiceState(DWORD dwCurrentState)
1658 {
1659     switch (dwCurrentState)
1660     {
1661         case SERVICE_STOPPED:
1662         case SERVICE_START_PENDING:
1663         case SERVICE_STOP_PENDING:
1664         case SERVICE_RUNNING:
1665         case SERVICE_CONTINUE_PENDING:
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
1679 RSetServiceStatus(
1680     RPC_SERVICE_STATUS_HANDLE hServiceStatus,
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 */
1741     ScmLockDatabaseExclusive();
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 */
1768             ScmControlService(lpService->lpImage->hControlPipe,
1769                               L"",
1770                               (SERVICE_STATUS_HANDLE)lpService,
1771                               SERVICE_CONTROL_STOP);
1772 
1773             /* Remove the service image */
1774             ScmRemoveServiceImage(lpService->lpImage);
1775             lpService->lpImage = NULL;
1776         }
1777     }
1778 
1779     /* Unlock the service database */
1780     ScmUnlockDatabase();
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 
1792         ScmLogEvent(EVENT_SERVICE_EXIT_FAILED,
1793                     EVENTLOG_ERROR_TYPE,
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 
1822         ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS,
1823                     EVENTLOG_INFORMATION_TYPE,
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
1838 RUnlockServiceDatabase(
1839     LPSC_RPC_LOCK Lock)
1840 {
1841     DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1842     return ScmReleaseServiceStartLock(Lock);
1843 }
1844 
1845 
1846 /* Function 9 */
1847 DWORD
1848 WINAPI
1849 RNotifyBootConfigStatus(
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
1866 RI_ScSetServiceBitsW(
1867     RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1868     DWORD dwServiceBits,
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)
1880         return ERROR_SHUTDOWN_IN_PROGRESS;
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;
1899         g_dwServiceBits |= dwServiceBits;
1900         DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1901         DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1902     }
1903     else
1904     {
1905         DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1906         DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1907         pService->dwServiceBits &= ~dwServiceBits;
1908         g_dwServiceBits &= ~dwServiceBits;
1909         DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1910         DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1911     }
1912 
1913     return ERROR_SUCCESS;
1914 }
1915 
1916 
1917 /* Function 11 */
1918 DWORD
1919 WINAPI
1920 RChangeServiceConfigW(
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,
1933     LPWSTR lpDisplayName)
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)
1955         return ERROR_SHUTDOWN_IN_PROGRESS;
1956 
1957     hSvc = ScmGetServiceFromHandle(hService);
1958     if (hSvc == NULL)
1959     {
1960         DPRINT1("Invalid service handle!\n");
1961         return ERROR_INVALID_HANDLE;
1962     }
1963 
1964     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1965                                   SERVICE_CHANGE_CONFIG))
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) &&
1976         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_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 */
2024     ScmLockDatabaseExclusive();
2025 
2026     if (lpService->bDeleted)
2027     {
2028         DPRINT("The service has already been marked for delete!\n");
2029         dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
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,
2049                        (LPBYTE)lpDisplayName,
2050                        (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2051 
2052         /* Update the display name */
2053         lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2054                                    HEAP_ZERO_MEMORY,
2055                                    (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2056         if (lpDisplayNameW == NULL)
2057         {
2058             dwError = ERROR_NOT_ENOUGH_MEMORY;
2059             goto done;
2060         }
2061 
2062         wcscpy(lpDisplayNameW, lpDisplayName);
2063         if (lpService->lpDisplayName != lpService->lpServiceName)
2064             HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2065 
2066         lpService->lpDisplayName = lpDisplayNameW;
2067     }
2068 
2069     if (dwServiceType != SERVICE_NO_CHANGE)
2070     {
2071         /* Set the service type */
2072         dwError = RegSetValueExW(hServiceKey,
2073                                  L"Type",
2074                                  0,
2075                                  REG_DWORD,
2076                                  (LPBYTE)&dwServiceType,
2077                                  sizeof(DWORD));
2078         if (dwError != ERROR_SUCCESS)
2079             goto done;
2080 
2081         lpService->Status.dwServiceType = dwServiceType;
2082     }
2083 
2084     if (dwStartType != SERVICE_NO_CHANGE)
2085     {
2086         /* Set the start value */
2087         dwError = RegSetValueExW(hServiceKey,
2088                                  L"Start",
2089                                  0,
2090                                  REG_DWORD,
2091                                  (LPBYTE)&dwStartType,
2092                                  sizeof(DWORD));
2093         if (dwError != ERROR_SUCCESS)
2094             goto done;
2095 
2096         lpService->dwStartType = dwStartType;
2097     }
2098 
2099     if (dwErrorControl != SERVICE_NO_CHANGE)
2100     {
2101         /* Set the error control value */
2102         dwError = RegSetValueExW(hServiceKey,
2103                                  L"ErrorControl",
2104                                  0,
2105                                  REG_DWORD,
2106                                  (LPBYTE)&dwErrorControl,
2107                                  sizeof(DWORD));
2108         if (dwError != ERROR_SUCCESS)
2109             goto done;
2110 
2111         lpService->dwErrorControl = dwErrorControl;
2112     }
2113 
2114     if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2115     {
2116         /* Set the image path */
2117         lpImagePathW = lpBinaryPathName;
2118 
2119         if (lpService->Status.dwServiceType & SERVICE_DRIVER)
2120         {
2121             dwError = ScmCanonDriverImagePath(lpService->dwStartType,
2122                                               lpBinaryPathName,
2123                                               &lpImagePathW);
2124 
2125             if (dwError != ERROR_SUCCESS)
2126                 goto done;
2127         }
2128 
2129         dwError = RegSetValueExW(hServiceKey,
2130                                  L"ImagePath",
2131                                  0,
2132                                  REG_EXPAND_SZ,
2133                                  (LPBYTE)lpImagePathW,
2134                                  (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
2135 
2136         if (lpImagePathW != lpBinaryPathName)
2137             HeapFree(GetProcessHeap(), 0, lpImagePathW);
2138 
2139         if (dwError != ERROR_SUCCESS)
2140             goto done;
2141     }
2142 
2143     /* Set the group name */
2144     if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2145     {
2146         dwError = RegSetValueExW(hServiceKey,
2147                                  L"Group",
2148                                  0,
2149                                  REG_SZ,
2150                                  (LPBYTE)lpLoadOrderGroup,
2151                                  (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2152         if (dwError != ERROR_SUCCESS)
2153             goto done;
2154 
2155         dwError = ScmSetServiceGroup(lpService,
2156                                      lpLoadOrderGroup);
2157         if (dwError != ERROR_SUCCESS)
2158             goto done;
2159     }
2160 
2161     /* Set the tag */
2162     if (lpdwTagId != NULL)
2163     {
2164         dwError = ScmAssignNewTag(lpService);
2165         if (dwError != ERROR_SUCCESS)
2166             goto done;
2167 
2168         dwError = RegSetValueExW(hServiceKey,
2169                                  L"Tag",
2170                                  0,
2171                                  REG_DWORD,
2172                                  (LPBYTE)&lpService->dwTag,
2173                                  sizeof(DWORD));
2174         if (dwError != ERROR_SUCCESS)
2175             goto done;
2176 
2177         *lpdwTagId = lpService->dwTag;
2178     }
2179 
2180     /* Write dependencies */
2181     if (lpDependencies != NULL && *lpDependencies != 0)
2182     {
2183         dwError = ScmWriteDependencies(hServiceKey,
2184                                        (LPWSTR)lpDependencies,
2185                                        dwDependSize);
2186         if (dwError != ERROR_SUCCESS)
2187             goto done;
2188     }
2189 
2190     /* Start name and password are only used by Win32 services */
2191     if (lpService->Status.dwServiceType & SERVICE_WIN32)
2192     {
2193         /* Write service start name */
2194         if (lpServiceStartName != NULL && *lpServiceStartName != 0)
2195         {
2196             dwError = RegSetValueExW(hServiceKey,
2197                                      L"ObjectName",
2198                                      0,
2199                                      REG_SZ,
2200                                      (LPBYTE)lpServiceStartName,
2201                                      (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)));
2202             if (dwError != ERROR_SUCCESS)
2203                 goto done;
2204         }
2205 
2206         if (lpPassword != NULL)
2207         {
2208             if (*(LPWSTR)lpPassword != 0)
2209             {
2210                 /* Decrypt the password */
2211                 dwError = ScmDecryptPassword(hService,
2212                                              lpPassword,
2213                                              dwPwSize,
2214                                              &lpClearTextPassword);
2215                 if (dwError != ERROR_SUCCESS)
2216                 {
2217                     DPRINT1("ScmDecryptPassword failed (Error %lu)\n", dwError);
2218                     goto done;
2219                 }
2220                 DPRINT1("Clear text password: %S\n", lpClearTextPassword);
2221 
2222                 /* Write the password */
2223                 dwError = ScmSetServicePassword(lpService->szServiceName,
2224                                                 lpClearTextPassword);
2225                 if (dwError != ERROR_SUCCESS)
2226                 {
2227                     DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2228                     goto done;
2229                 }
2230             }
2231             else
2232             {
2233                 /* Delete the password */
2234                 dwError = ScmSetServicePassword(lpService->szServiceName,
2235                                                 NULL);
2236                 if (dwError == ERROR_FILE_NOT_FOUND)
2237                     dwError = ERROR_SUCCESS;
2238 
2239                 if (dwError != ERROR_SUCCESS)
2240                 {
2241                     DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
2242                     goto done;
2243                 }
2244             }
2245         }
2246     }
2247 
2248 done:
2249     if (lpClearTextPassword != NULL)
2250     {
2251         /* Wipe and release the password buffer */
2252         SecureZeroMemory(lpClearTextPassword,
2253                          (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2254         HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2255     }
2256 
2257     if (hServiceKey != NULL)
2258         RegCloseKey(hServiceKey);
2259 
2260     /* Unlock the service database */
2261     ScmUnlockDatabase();
2262 
2263     DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2264 
2265     return dwError;
2266 }
2267 
2268 
2269 /* Function 12 */
2270 DWORD
2271 WINAPI
2272 RCreateServiceW(
2273     SC_RPC_HANDLE hSCManager,
2274     LPCWSTR lpServiceName,
2275     LPCWSTR lpDisplayName,
2276     DWORD dwDesiredAccess,
2277     DWORD dwServiceType,
2278     DWORD dwStartType,
2279     DWORD dwErrorControl,
2280     LPCWSTR lpBinaryPathName,
2281     LPCWSTR lpLoadOrderGroup,
2282     LPDWORD lpdwTagId,
2283     LPBYTE lpDependencies,
2284     DWORD dwDependSize,
2285     LPCWSTR lpServiceStartName,
2286     LPBYTE lpPassword,
2287     DWORD dwPwSize,
2288     LPSC_RPC_HANDLE lpServiceHandle)
2289 {
2290     PMANAGER_HANDLE hManager;
2291     DWORD dwError = ERROR_SUCCESS;
2292     PSERVICE lpService = NULL;
2293     SC_HANDLE hServiceHandle = NULL;
2294     LPWSTR lpImagePath = NULL;
2295     LPWSTR lpClearTextPassword = NULL;
2296     HKEY hServiceKey = NULL;
2297     LPWSTR lpObjectName;
2298 
2299     DPRINT("RCreateServiceW() called\n");
2300     DPRINT("lpServiceName = %S\n", lpServiceName);
2301     DPRINT("lpDisplayName = %S\n", lpDisplayName);
2302     DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2303     DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2304     DPRINT("dwStartType = %lu\n", dwStartType);
2305     DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2306     DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2307     DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2308     DPRINT("lpdwTagId = %p\n", lpdwTagId);
2309 
2310     if (ScmShutdown)
2311         return ERROR_SHUTDOWN_IN_PROGRESS;
2312 
2313     hManager = ScmGetServiceManagerFromHandle(hSCManager);
2314     if (hManager == NULL)
2315     {
2316         DPRINT1("Invalid service manager handle!\n");
2317         return ERROR_INVALID_HANDLE;
2318     }
2319 
2320     /* Check access rights */
2321     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2322                                   SC_MANAGER_CREATE_SERVICE))
2323     {
2324         DPRINT("Insufficient access rights! 0x%lx\n",
2325                hManager->Handle.DesiredAccess);
2326         return ERROR_ACCESS_DENIED;
2327     }
2328 
2329     if (*lpServiceName == 0)
2330         return ERROR_INVALID_NAME;
2331 
2332     if (*lpBinaryPathName == 0)
2333         return ERROR_INVALID_PARAMETER;
2334 
2335     /* Check for invalid service type value */
2336     if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2337         (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2338         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2339         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2340     {
2341         return ERROR_INVALID_PARAMETER;
2342     }
2343 
2344     /* Check for invalid start type value */
2345     if ((dwStartType != SERVICE_BOOT_START) &&
2346         (dwStartType != SERVICE_SYSTEM_START) &&
2347         (dwStartType != SERVICE_AUTO_START) &&
2348         (dwStartType != SERVICE_DEMAND_START) &&
2349         (dwStartType != SERVICE_DISABLED))
2350     {
2351         return ERROR_INVALID_PARAMETER;
2352     }
2353 
2354     /* Only drivers can be boot start or system start services */
2355     if ((dwStartType == SERVICE_BOOT_START) ||
2356         (dwStartType == SERVICE_SYSTEM_START))
2357     {
2358         if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2359             (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2360         {
2361             return ERROR_INVALID_PARAMETER;
2362         }
2363     }
2364 
2365     /* Check for invalid error control value */
2366     if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2367         (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2368         (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2369         (dwErrorControl != SERVICE_ERROR_CRITICAL))
2370     {
2371         return ERROR_INVALID_PARAMETER;
2372     }
2373 
2374     if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2375         (lpServiceStartName))
2376     {
2377         /* We allow LocalSystem to run interactive. */
2378         if (wcsicmp(lpServiceStartName, L"LocalSystem"))
2379         {
2380             return ERROR_INVALID_PARAMETER;
2381         }
2382     }
2383 
2384     if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2385     {
2386         return ERROR_INVALID_PARAMETER;
2387     }
2388 
2389     /* Lock the service database exclusively */
2390     ScmLockDatabaseExclusive();
2391 
2392     lpService = ScmGetServiceEntryByName(lpServiceName);
2393     if (lpService)
2394     {
2395         /* Unlock the service database */
2396         ScmUnlockDatabase();
2397 
2398         /* Check if it is marked for deletion */
2399         if (lpService->bDeleted)
2400             return ERROR_SERVICE_MARKED_FOR_DELETE;
2401 
2402         /* Return service-exists error */
2403         return ERROR_SERVICE_EXISTS;
2404     }
2405 
2406     if (lpDisplayName != NULL &&
2407         ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2408     {
2409         /* Unlock the service database */
2410         ScmUnlockDatabase();
2411 
2412         return ERROR_DUPLICATE_SERVICE_NAME;
2413     }
2414 
2415     if (dwServiceType & SERVICE_DRIVER)
2416     {
2417         dwError = ScmCanonDriverImagePath(dwStartType,
2418                                           lpBinaryPathName,
2419                                           &lpImagePath);
2420         if (dwError != ERROR_SUCCESS)
2421             goto done;
2422     }
2423     else
2424     {
2425         if (dwStartType == SERVICE_BOOT_START ||
2426             dwStartType == SERVICE_SYSTEM_START)
2427         {
2428             /* Unlock the service database */
2429             ScmUnlockDatabase();
2430 
2431             return ERROR_INVALID_PARAMETER;
2432         }
2433     }
2434 
2435     /* Allocate a new service entry */
2436     dwError = ScmCreateNewServiceRecord(lpServiceName,
2437                                         &lpService,
2438                                         dwServiceType,
2439                                         dwStartType);
2440     if (dwError != ERROR_SUCCESS)
2441         goto done;
2442 
2443     /* Fill the new service entry */
2444     lpService->dwErrorControl = dwErrorControl;
2445 
2446     /* Fill the display name */
2447     if (lpDisplayName != NULL &&
2448         *lpDisplayName != 0 &&
2449         _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2450     {
2451         lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2452                                              HEAP_ZERO_MEMORY,
2453                                              (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2454         if (lpService->lpDisplayName == NULL)
2455         {
2456             dwError = ERROR_NOT_ENOUGH_MEMORY;
2457             goto done;
2458         }
2459         wcscpy(lpService->lpDisplayName, lpDisplayName);
2460     }
2461 
2462     /* Assign the service to a group */
2463     if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2464     {
2465         dwError = ScmSetServiceGroup(lpService,
2466                                      lpLoadOrderGroup);
2467         if (dwError != ERROR_SUCCESS)
2468             goto done;
2469     }
2470 
2471     /* Assign a new tag */
2472     if (lpdwTagId != NULL)
2473     {
2474         dwError = ScmAssignNewTag(lpService);
2475         if (dwError != ERROR_SUCCESS)
2476             goto done;
2477     }
2478 
2479     /* Assign the default security descriptor */
2480     if (dwServiceType & SERVICE_WIN32)
2481     {
2482         dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
2483         if (dwError != ERROR_SUCCESS)
2484             goto done;
2485     }
2486 
2487     /* Write service data to the registry */
2488     /* Create the service key */
2489     dwError = ScmCreateServiceKey(lpServiceName,
2490                                   KEY_WRITE,
2491                                   &hServiceKey);
2492     if (dwError != ERROR_SUCCESS)
2493         goto done;
2494 
2495     /* Set the display name */
2496     if (lpDisplayName != NULL && *lpDisplayName != 0)
2497     {
2498         RegSetValueExW(hServiceKey,
2499                        L"DisplayName",
2500                        0,
2501                        REG_SZ,
2502                        (LPBYTE)lpDisplayName,
2503                        (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2504     }
2505 
2506     /* Set the service type */
2507     dwError = RegSetValueExW(hServiceKey,
2508                              L"Type",
2509                              0,
2510                              REG_DWORD,
2511                              (LPBYTE)&dwServiceType,
2512                              sizeof(DWORD));
2513     if (dwError != ERROR_SUCCESS)
2514         goto done;
2515 
2516     /* Set the start value */
2517     dwError = RegSetValueExW(hServiceKey,
2518                              L"Start",
2519                              0,
2520                              REG_DWORD,
2521                              (LPBYTE)&dwStartType,
2522                              sizeof(DWORD));
2523     if (dwError != ERROR_SUCCESS)
2524         goto done;
2525 
2526     /* Set the error control value */
2527     dwError = RegSetValueExW(hServiceKey,
2528                              L"ErrorControl",
2529                              0,
2530                              REG_DWORD,
2531                              (LPBYTE)&dwErrorControl,
2532                              sizeof(DWORD));
2533     if (dwError != ERROR_SUCCESS)
2534         goto done;
2535 
2536     /* Set the image path */
2537     if (dwServiceType & SERVICE_WIN32)
2538     {
2539         dwError = RegSetValueExW(hServiceKey,
2540                                  L"ImagePath",
2541                                  0,
2542                                  REG_EXPAND_SZ,
2543                                  (LPBYTE)lpBinaryPathName,
2544                                  (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2545         if (dwError != ERROR_SUCCESS)
2546             goto done;
2547     }
2548     else if (dwServiceType & SERVICE_DRIVER)
2549     {
2550         dwError = RegSetValueExW(hServiceKey,
2551                                  L"ImagePath",
2552                                  0,
2553                                  REG_EXPAND_SZ,
2554                                  (LPBYTE)lpImagePath,
2555                                  (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2556         if (dwError != ERROR_SUCCESS)
2557             goto done;
2558     }
2559 
2560     /* Set the group name */
2561     if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2562     {
2563         dwError = RegSetValueExW(hServiceKey,
2564                                  L"Group",
2565                                  0,
2566                                  REG_SZ,
2567                                  (LPBYTE)lpLoadOrderGroup,
2568                                  (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2569         if (dwError != ERROR_SUCCESS)
2570             goto done;
2571     }
2572 
2573     /* Set the service tag */
2574     if (lpdwTagId != NULL)
2575     {
2576         dwError = RegSetValueExW(hServiceKey,
2577                                  L"Tag",
2578                                  0,
2579                                  REG_DWORD,
2580                                  (LPBYTE)&lpService->dwTag,
2581                                  sizeof(DWORD));
2582         if (dwError != ERROR_SUCCESS)
2583             goto done;
2584     }
2585 
2586     /* Write dependencies */
2587     if (lpDependencies != NULL && *lpDependencies != 0)
2588     {
2589         dwError = ScmWriteDependencies(hServiceKey,
2590                                        (LPCWSTR)lpDependencies,
2591                                        dwDependSize);
2592         if (dwError != ERROR_SUCCESS)
2593             goto done;
2594     }
2595 
2596     /* Start name and password are only used by Win32 services */
2597     if (dwServiceType & SERVICE_WIN32)
2598     {
2599         /* Write service start name */
2600         lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2601         dwError = RegSetValueExW(hServiceKey,
2602                                  L"ObjectName",
2603                                  0,
2604                                  REG_SZ,
2605                                  (LPBYTE)lpObjectName,
2606                                  (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2607         if (dwError != ERROR_SUCCESS)
2608             goto done;
2609 
2610         if (lpPassword != NULL && *(LPWSTR)lpPassword != 0)
2611         {
2612             /* Decrypt the password */
2613             dwError = ScmDecryptPassword(hSCManager,
2614                                          lpPassword,
2615                                          dwPwSize,
2616                                          &lpClearTextPassword);
2617             if (dwError != ERROR_SUCCESS)
2618                 goto done;
2619 
2620             /* Write the password */
2621             dwError = ScmSetServicePassword(lpServiceName,
2622                                             lpClearTextPassword);
2623             if (dwError != ERROR_SUCCESS)
2624                 goto done;
2625         }
2626 
2627         /* Write the security descriptor */
2628         dwError = ScmWriteSecurityDescriptor(hServiceKey,
2629                                              lpService->pSecurityDescriptor);
2630         if (dwError != ERROR_SUCCESS)
2631             goto done;
2632     }
2633 
2634     dwError = ScmCreateServiceHandle(lpService,
2635                                      &hServiceHandle);
2636     if (dwError != ERROR_SUCCESS)
2637         goto done;
2638 
2639     dwError = ScmCheckAccess(hServiceHandle,
2640                              dwDesiredAccess);
2641     if (dwError != ERROR_SUCCESS)
2642         goto done;
2643 
2644     lpService->dwRefCount = 1;
2645 
2646     /* Get the service tag (if Win32) */
2647     ScmGenerateServiceTag(lpService);
2648 
2649     DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2650 
2651 done:
2652     /* Unlock the service database */
2653     ScmUnlockDatabase();
2654 
2655     if (hServiceKey != NULL)
2656         RegCloseKey(hServiceKey);
2657 
2658     if (lpClearTextPassword != NULL)
2659     {
2660         /* Wipe and release the password buffer */
2661         SecureZeroMemory(lpClearTextPassword,
2662                          (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
2663         HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
2664     }
2665 
2666     if (dwError == ERROR_SUCCESS)
2667     {
2668         DPRINT("hService %p\n", hServiceHandle);
2669         *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2670 
2671         if (lpdwTagId != NULL)
2672             *lpdwTagId = lpService->dwTag;
2673     }
2674     else
2675     {
2676         if (lpService != NULL &&
2677             lpService->lpServiceName != NULL)
2678         {
2679             /* Release the display name buffer */
2680             HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2681         }
2682 
2683         if (hServiceHandle)
2684         {
2685             /* Remove the service handle */
2686             HeapFree(GetProcessHeap(), 0, hServiceHandle);
2687         }
2688 
2689         if (lpService != NULL)
2690         {
2691             /* FIXME: remove the service entry */
2692         }
2693     }
2694 
2695     if (lpImagePath != NULL)
2696         HeapFree(GetProcessHeap(), 0, lpImagePath);
2697 
2698     DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2699 
2700     return dwError;
2701 }
2702 
2703 
2704 /* Function 13 */
2705 DWORD
2706 WINAPI
2707 REnumDependentServicesW(
2708     SC_RPC_HANDLE hService,
2709     DWORD dwServiceState,
2710     LPBYTE lpServices,
2711     DWORD cbBufSize,
2712     LPBOUNDED_DWORD_256K pcbBytesNeeded,
2713     LPBOUNDED_DWORD_256K lpServicesReturned)
2714 {
2715     DWORD dwError = ERROR_SUCCESS;
2716     DWORD dwServicesReturned = 0;
2717     DWORD dwServiceCount;
2718     HKEY hServicesKey = NULL;
2719     PSERVICE_HANDLE hSvc;
2720     PSERVICE lpService = NULL;
2721     PSERVICE *lpServicesArray = NULL;
2722     LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2723     LPWSTR lpStr;
2724 
2725     *pcbBytesNeeded = 0;
2726     *lpServicesReturned = 0;
2727 
2728     DPRINT("REnumDependentServicesW() called\n");
2729 
2730     hSvc = ScmGetServiceFromHandle(hService);
2731     if (hSvc == NULL)
2732     {
2733         DPRINT1("Invalid service handle!\n");
2734         return ERROR_INVALID_HANDLE;
2735     }
2736 
2737     lpService = hSvc->ServiceEntry;
2738 
2739     /* Check access rights */
2740     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2741                                   SC_MANAGER_ENUMERATE_SERVICE))
2742     {
2743         DPRINT("Insufficient access rights! 0x%lx\n",
2744                hSvc->Handle.DesiredAccess);
2745         return ERROR_ACCESS_DENIED;
2746     }
2747 
2748     /* Open the Services Reg key */
2749     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2750                             L"System\\CurrentControlSet\\Services",
2751                             0,
2752                             KEY_READ,
2753                             &hServicesKey);
2754     if (dwError != ERROR_SUCCESS)
2755         return dwError;
2756 
2757     /* First determine the bytes needed and get the number of dependent services */
2758     dwError = Int_EnumDependentServicesW(hServicesKey,
2759                                          lpService,
2760                                          dwServiceState,
2761                                          NULL,
2762                                          pcbBytesNeeded,
2763                                          &dwServicesReturned);
2764     if (dwError != ERROR_SUCCESS)
2765         goto Done;
2766 
2767     /* If buffer size is less than the bytes needed or pointer is null */
2768     if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2769     {
2770         dwError = ERROR_MORE_DATA;
2771         goto Done;
2772     }
2773 
2774     /* Allocate memory for array of service pointers */
2775     lpServicesArray = HeapAlloc(GetProcessHeap(),
2776                                 HEAP_ZERO_MEMORY,
2777                                 (dwServicesReturned + 1) * sizeof(PSERVICE));
2778     if (!lpServicesArray)
2779     {
2780         DPRINT1("Could not allocate a buffer!!\n");
2781         dwError = ERROR_NOT_ENOUGH_MEMORY;
2782         goto Done;
2783     }
2784 
2785     dwServicesReturned = 0;
2786     *pcbBytesNeeded = 0;
2787 
2788     dwError = Int_EnumDependentServicesW(hServicesKey,
2789                                          lpService,
2790                                          dwServiceState,
2791                                          lpServicesArray,
2792                                          pcbBytesNeeded,
2793                                          &dwServicesReturned);
2794     if (dwError != ERROR_SUCCESS)
2795     {
2796         goto Done;
2797     }
2798 
2799     lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2800     lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2801 
2802     /* Copy EnumDepenedentService to Buffer */
2803     for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2804     {
2805         lpService = lpServicesArray[dwServiceCount];
2806 
2807         /* Copy status info */
2808         memcpy(&lpServicesPtr->ServiceStatus,
2809                &lpService->Status,
2810                sizeof(SERVICE_STATUS));
2811 
2812         /* Copy display name */
2813         wcscpy(lpStr, lpService->lpDisplayName);
2814         lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2815         lpStr += (wcslen(lpService->lpDisplayName) + 1);
2816 
2817         /* Copy service name */
2818         wcscpy(lpStr, lpService->lpServiceName);
2819         lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2820         lpStr += (wcslen(lpService->lpServiceName) + 1);
2821 
2822         lpServicesPtr++;
2823     }
2824 
2825     *lpServicesReturned = dwServicesReturned;
2826 
2827 Done:
2828     if (lpServicesArray != NULL)
2829         HeapFree(GetProcessHeap(), 0, lpServicesArray);
2830 
2831     RegCloseKey(hServicesKey);
2832 
2833     DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2834 
2835     return dwError;
2836 }
2837 
2838 
2839 /* Function 14 */
2840 DWORD
2841 WINAPI
2842 REnumServicesStatusW(
2843     SC_RPC_HANDLE hSCManager,
2844     DWORD dwServiceType,
2845     DWORD dwServiceState,
2846     LPBYTE lpBuffer,
2847     DWORD dwBufSize,
2848     LPBOUNDED_DWORD_256K pcbBytesNeeded,
2849     LPBOUNDED_DWORD_256K lpServicesReturned,
2850     LPBOUNDED_DWORD_256K lpResumeHandle)
2851 {
2852     /* Enumerate all the services, not regarding of their group */
2853     return REnumServiceGroupW(hSCManager,
2854                               dwServiceType,
2855                               dwServiceState,
2856                               lpBuffer,
2857                               dwBufSize,
2858                               pcbBytesNeeded,
2859                               lpServicesReturned,
2860                               lpResumeHandle,
2861                               NULL);
2862 }
2863 
2864 
2865 /* Function 15 */
2866 DWORD
2867 WINAPI
2868 ROpenSCManagerW(
2869     LPWSTR lpMachineName,
2870     LPWSTR lpDatabaseName,
2871     DWORD dwDesiredAccess,
2872     LPSC_RPC_HANDLE lpScHandle)
2873 {
2874     DWORD dwError;
2875     SC_HANDLE hHandle;
2876 
2877     DPRINT("ROpenSCManagerW() called\n");
2878     DPRINT("lpMachineName = %p\n", lpMachineName);
2879     DPRINT("lpMachineName: %S\n", lpMachineName);
2880     DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2881     DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2882     DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2883 
2884     if (ScmShutdown)
2885         return ERROR_SHUTDOWN_IN_PROGRESS;
2886 
2887     if (!lpScHandle)
2888         return ERROR_INVALID_PARAMETER;
2889 
2890     dwError = ScmCreateManagerHandle(lpDatabaseName,
2891                                      &hHandle);
2892     if (dwError != ERROR_SUCCESS)
2893     {
2894         DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2895         return dwError;
2896     }
2897 
2898     /* Check the desired access */
2899     dwError = ScmCheckAccess(hHandle,
2900                              dwDesiredAccess | SC_MANAGER_CONNECT);
2901     if (dwError != ERROR_SUCCESS)
2902     {
2903         DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2904         HeapFree(GetProcessHeap(), 0, hHandle);
2905         return dwError;
2906     }
2907 
2908     *lpScHandle = (SC_RPC_HANDLE)hHandle;
2909     DPRINT("*hScm = %p\n", *lpScHandle);
2910 
2911     DPRINT("ROpenSCManagerW() done\n");
2912 
2913     return ERROR_SUCCESS;
2914 }
2915 
2916 
2917 /* Function 16 */
2918 DWORD
2919 WINAPI
2920 ROpenServiceW(
2921     SC_RPC_HANDLE hSCManager,
2922     LPWSTR lpServiceName,
2923     DWORD dwDesiredAccess,
2924     LPSC_RPC_HANDLE lpServiceHandle)
2925 {
2926     PSERVICE lpService;
2927     PMANAGER_HANDLE hManager;
2928     SC_HANDLE hHandle;
2929     DWORD dwError = ERROR_SUCCESS;
2930 
2931     DPRINT("ROpenServiceW() called\n");
2932     DPRINT("hSCManager = %p\n", hSCManager);
2933     DPRINT("lpServiceName = %p\n", lpServiceName);
2934     DPRINT("lpServiceName: %S\n", lpServiceName);
2935     DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2936 
2937     if (ScmShutdown)
2938         return ERROR_SHUTDOWN_IN_PROGRESS;
2939 
2940     hManager = ScmGetServiceManagerFromHandle(hSCManager);
2941     if (hManager == NULL)
2942     {
2943         DPRINT1("Invalid service manager handle!\n");
2944         return ERROR_INVALID_HANDLE;
2945     }
2946 
2947     if (!lpServiceHandle)
2948         return ERROR_INVALID_PARAMETER;
2949 
2950     if (!lpServiceName)
2951         return ERROR_INVALID_ADDRESS;
2952 
2953     /* Lock the service database exclusive */
2954     ScmLockDatabaseExclusive();
2955 
2956     /* Get service database entry */
2957     lpService = ScmGetServiceEntryByName(lpServiceName);
2958     if (lpService == NULL)
2959     {
2960         DPRINT("Could not find the service!\n");
2961         dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2962         goto Done;
2963     }
2964 
2965     /* Create a service handle */
2966     dwError = ScmCreateServiceHandle(lpService,
2967                                      &hHandle);
2968     if (dwError != ERROR_SUCCESS)
2969     {
2970         DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2971         goto Done;
2972     }
2973 
2974     /* Check the desired access */
2975     dwError = ScmCheckAccess(hHandle,
2976                              dwDesiredAccess);
2977     if (dwError != ERROR_SUCCESS)
2978     {
2979         DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2980         HeapFree(GetProcessHeap(), 0, hHandle);
2981         goto Done;
2982     }
2983 
2984     lpService->dwRefCount++;
2985     DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2986 
2987     *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2988     DPRINT("*hService = %p\n", *lpServiceHandle);
2989 
2990 Done:
2991     /* Unlock the service database */
2992     ScmUnlockDatabase();
2993 
2994     DPRINT("ROpenServiceW() done\n");
2995 
2996     return dwError;
2997 }
2998 
2999 
3000 /* Function 17 */
3001 DWORD
3002 WINAPI
3003 RQueryServiceConfigW(
3004     SC_RPC_HANDLE hService,
3005     LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
3006     DWORD cbBufSize,
3007     LPBOUNDED_DWORD_8K pcbBytesNeeded)
3008 {
3009     LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
3010     DWORD dwError = ERROR_SUCCESS;
3011     PSERVICE_HANDLE hSvc;
3012     PSERVICE lpService = NULL;
3013     HKEY hServiceKey = NULL;
3014     LPWSTR lpImagePath = NULL;
3015     LPWSTR lpServiceStartName = NULL;
3016     LPWSTR lpDependencies = NULL;
3017     DWORD dwDependenciesLength = 0;
3018     DWORD dwRequiredSize;
3019     LPWSTR lpStr;
3020 
3021     DPRINT("RQueryServiceConfigW() called\n");
3022 
3023     if (ScmShutdown)
3024         return ERROR_SHUTDOWN_IN_PROGRESS;
3025 
3026     hSvc = ScmGetServiceFromHandle(hService);
3027     if (hSvc == NULL)
3028     {
3029         DPRINT1("Invalid service handle!\n");
3030         return ERROR_INVALID_HANDLE;
3031     }
3032 
3033     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3034                                   SERVICE_QUERY_CONFIG))
3035     {
3036         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3037         return ERROR_ACCESS_DENIED;
3038     }
3039 
3040     lpService = hSvc->ServiceEntry;
3041     if (lpService == NULL)
3042     {
3043         DPRINT("lpService == NULL!\n");
3044         return ERROR_INVALID_HANDLE;
3045     }
3046 
3047     /* Lock the service database shared */
3048     ScmLockDatabaseShared();
3049 
3050     dwError = ScmOpenServiceKey(lpService->lpServiceName,
3051                                 KEY_READ,
3052                                 &hServiceKey);
3053     if (dwError != ERROR_SUCCESS)
3054         goto Done;
3055 
3056     /* Read the image path */
3057     dwError = ScmReadString(hServiceKey,
3058                             L"ImagePath",
3059                             &lpImagePath);
3060     if (dwError != ERROR_SUCCESS)
3061         goto Done;
3062 
3063     /* Read the service start name */
3064     ScmReadString(hServiceKey,
3065                   L"ObjectName",
3066                   &lpServiceStartName);
3067 
3068     /* Read the dependencies */
3069     ScmReadDependencies(hServiceKey,
3070                         &lpDependencies,
3071                         &dwDependenciesLength);
3072 
3073     dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3074 
3075     if (lpImagePath != NULL)
3076         dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
3077     else
3078         dwRequiredSize += 2 * sizeof(WCHAR);
3079 
3080     if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3081         dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
3082     else
3083         dwRequiredSize += 2 * sizeof(WCHAR);
3084 
3085     if (lpDependencies != NULL)
3086         dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
3087     else
3088         dwRequiredSize += 2 * sizeof(WCHAR);
3089 
3090     if (lpServiceStartName != NULL)
3091         dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
3092     else
3093         dwRequiredSize += 2 * sizeof(WCHAR);
3094 
3095     if (lpService->lpDisplayName != NULL)
3096         dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
3097     else
3098         dwRequiredSize += 2 * sizeof(WCHAR);
3099 
3100     if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3101     {
3102         dwError = ERROR_INSUFFICIENT_BUFFER;
3103     }
3104     else
3105     {
3106         lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
3107         lpServiceConfig->dwStartType = lpService->dwStartType;
3108         lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
3109         lpServiceConfig->dwTagId = lpService->dwTag;
3110 
3111         lpStr = (LPWSTR)(lpServiceConfig + 1);
3112 
3113         /* Append the image path */
3114         if (lpImagePath != NULL)
3115         {
3116             wcscpy(lpStr, lpImagePath);
3117         }
3118         else
3119         {
3120             *lpStr = 0;
3121         }
3122 
3123         lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3124         lpStr += (wcslen(lpStr) + 1);
3125 
3126         /* Append the group name */
3127         if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3128         {
3129             wcscpy(lpStr, lpService->lpGroup->lpGroupName);
3130         }
3131         else
3132         {
3133             *lpStr = 0;
3134         }
3135 
3136         lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3137         lpStr += (wcslen(lpStr) + 1);
3138 
3139         /* Append Dependencies */
3140         if (lpDependencies != NULL)
3141         {
3142             memcpy(lpStr,
3143                    lpDependencies,
3144                    dwDependenciesLength * sizeof(WCHAR));
3145         }
3146         else
3147         {
3148             *lpStr = 0;
3149         }
3150 
3151         lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3152         if (lpDependencies != NULL)
3153             lpStr += dwDependenciesLength;
3154         else
3155             lpStr += (wcslen(lpStr) + 1);
3156 
3157         /* Append the service start name */
3158         if (lpServiceStartName != NULL)
3159         {
3160             wcscpy(lpStr, lpServiceStartName);
3161         }
3162         else
3163         {
3164             *lpStr = 0;
3165         }
3166 
3167         lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3168         lpStr += (wcslen(lpStr) + 1);
3169 
3170         /* Append the display name */
3171         if (lpService->lpDisplayName != NULL)
3172         {
3173             wcscpy(lpStr, lpService->lpDisplayName);
3174         }
3175         else
3176         {
3177             *lpStr = 0;
3178         }
3179 
3180         lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3181     }
3182 
3183     if (pcbBytesNeeded != NULL)
3184         *pcbBytesNeeded = dwRequiredSize;
3185 
3186 Done:
3187     /* Unlock the service database */
3188     ScmUnlockDatabase();
3189 
3190     if (lpImagePath != NULL)
3191         HeapFree(GetProcessHeap(), 0, lpImagePath);
3192 
3193     if (lpServiceStartName != NULL)
3194         HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3195 
3196     if (lpDependencies != NULL)
3197         HeapFree(GetProcessHeap(), 0, lpDependencies);
3198 
3199     if (hServiceKey != NULL)
3200         RegCloseKey(hServiceKey);
3201 
3202     DPRINT("RQueryServiceConfigW() done\n");
3203 
3204     return dwError;
3205 }
3206 
3207 
3208 /* Function 18 */
3209 DWORD
3210 WINAPI
3211 RQueryServiceLockStatusW(
3212     SC_RPC_HANDLE hSCManager,
3213     LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3214     DWORD cbBufSize,
3215     LPBOUNDED_DWORD_4K pcbBytesNeeded)
3216 {
3217     LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf;
3218     PMANAGER_HANDLE hMgr;
3219     DWORD dwRequiredSize;
3220 
3221     if (!lpLockStatus || !pcbBytesNeeded)
3222         return ERROR_INVALID_PARAMETER;
3223 
3224     hMgr = ScmGetServiceManagerFromHandle(hSCManager);
3225     if (hMgr == NULL)
3226     {
3227         DPRINT1("Invalid service manager handle!\n");
3228         return ERROR_INVALID_HANDLE;
3229     }
3230 
3231     if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
3232                                   SC_MANAGER_QUERY_LOCK_STATUS))
3233     {
3234         DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
3235         return ERROR_ACCESS_DENIED;
3236     }
3237 
3238     /* FIXME: we need to compute instead the real length of the owner name */
3239     dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
3240     *pcbBytesNeeded = dwRequiredSize;
3241 
3242     if (cbBufSize < dwRequiredSize)
3243         return ERROR_INSUFFICIENT_BUFFER;
3244 
3245     ScmQueryServiceLockStatusW(lpLockStatus);
3246 
3247     return ERROR_SUCCESS;
3248 }
3249 
3250 
3251 /* Function 19 */
3252 DWORD
3253 WINAPI
3254 RStartServiceW(
3255     SC_RPC_HANDLE hService,
3256     DWORD argc,
3257     LPSTRING_PTRSW argv)
3258 {
3259     DWORD dwError = ERROR_SUCCESS;
3260     PSERVICE_HANDLE hSvc;
3261     PSERVICE lpService = NULL;
3262 
3263 #ifndef NDEBUG
3264     DWORD i;
3265 
3266     DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3267     DPRINT("  argc: %lu\n", argc);
3268     if (argv != NULL)
3269     {
3270         for (i = 0; i < argc; i++)
3271         {
3272             DPRINT("  argv[%lu]: %S\n", i, argv[i].StringPtr);
3273         }
3274     }
3275 #endif
3276 
3277     if (ScmShutdown)
3278         return ERROR_SHUTDOWN_IN_PROGRESS;
3279 
3280     hSvc = ScmGetServiceFromHandle(hService);
3281     if (hSvc == NULL)
3282     {
3283         DPRINT1("Invalid service handle!\n");
3284         return ERROR_INVALID_HANDLE;
3285     }
3286 
3287     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3288                                   SERVICE_START))
3289     {
3290         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3291         return ERROR_ACCESS_DENIED;
3292     }
3293 
3294     lpService = hSvc->ServiceEntry;
3295     if (lpService == NULL)
3296     {
3297         DPRINT("lpService == NULL!\n");
3298         return ERROR_INVALID_HANDLE;
3299     }
3300 
3301     if (lpService->dwStartType == SERVICE_DISABLED)
3302         return ERROR_SERVICE_DISABLED;
3303 
3304     if (lpService->bDeleted)
3305         return ERROR_SERVICE_MARKED_FOR_DELETE;
3306 
3307     /* Start the service */
3308     dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3309 
3310     return dwError;
3311 }
3312 
3313 
3314 /* Function 20 */
3315 DWORD
3316 WINAPI
3317 RGetServiceDisplayNameW(
3318     SC_RPC_HANDLE hSCManager,
3319     LPCWSTR lpServiceName,
3320     LPWSTR lpDisplayName,
3321     DWORD *lpcchBuffer)
3322 {
3323     // PMANAGER_HANDLE hManager;
3324     PSERVICE lpService;
3325     LPCWSTR lpSvcDisplayName;
3326     DWORD dwLength;
3327     DWORD dwError;
3328 
3329     DPRINT("RGetServiceDisplayNameW() called\n");
3330     DPRINT("hSCManager = %p\n", hSCManager);
3331     DPRINT("lpServiceName: %S\n", lpServiceName);
3332     DPRINT("lpDisplayName: %p\n", lpDisplayName);
3333     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3334 
3335 #if 0
3336     hManager = (PMANAGER_HANDLE)hSCManager;
3337     if (hManager->Handle.Tag != MANAGER_TAG)
3338     {
3339         DPRINT("Invalid manager handle!\n");
3340         return ERROR_INVALID_HANDLE;
3341     }
3342 #endif
3343 
3344     /* Get service database entry */
3345     lpService = ScmGetServiceEntryByName(lpServiceName);
3346     if (lpService == NULL)
3347     {
3348         DPRINT("Could not find the service!\n");
3349         return ERROR_SERVICE_DOES_NOT_EXIST;
3350     }
3351 
3352     if (lpService->lpDisplayName)
3353         lpSvcDisplayName = lpService->lpDisplayName;
3354     else
3355         lpSvcDisplayName = lpService->lpServiceName;
3356 
3357     dwLength = (DWORD)wcslen(lpSvcDisplayName);
3358 
3359     if (*lpcchBuffer > dwLength)
3360     {
3361         if (lpDisplayName != NULL)
3362             wcscpy(lpDisplayName, lpSvcDisplayName);
3363 
3364         dwError = ERROR_SUCCESS;
3365     }
3366     else
3367     {
3368         dwError = ERROR_INSUFFICIENT_BUFFER;
3369     }
3370 
3371     *lpcchBuffer = dwLength;
3372 
3373     return dwError;
3374 }
3375 
3376 
3377 /* Function 21 */
3378 DWORD
3379 WINAPI
3380 RGetServiceKeyNameW(
3381     SC_RPC_HANDLE hSCManager,
3382     LPCWSTR lpDisplayName,
3383     LPWSTR lpServiceName,
3384     DWORD *lpcchBuffer)
3385 {
3386     // PMANAGER_HANDLE hManager;
3387     PSERVICE lpService;
3388     DWORD dwLength;
3389     DWORD dwError;
3390 
3391     DPRINT("RGetServiceKeyNameW() called\n");
3392     DPRINT("hSCManager = %p\n", hSCManager);
3393     DPRINT("lpDisplayName: %S\n", lpDisplayName);
3394     DPRINT("lpServiceName: %p\n", lpServiceName);
3395     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3396 
3397 #if 0
3398     hManager = (PMANAGER_HANDLE)hSCManager;
3399     if (hManager->Handle.Tag != MANAGER_TAG)
3400     {
3401         DPRINT("Invalid manager handle!\n");
3402         return ERROR_INVALID_HANDLE;
3403     }
3404 #endif
3405 
3406     /* Get service database entry */
3407     lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3408     if (lpService == NULL)
3409     {
3410         DPRINT("Could not find the service!\n");
3411         return ERROR_SERVICE_DOES_NOT_EXIST;
3412     }
3413 
3414     dwLength = (DWORD)wcslen(lpService->lpServiceName);
3415 
3416     if (*lpcchBuffer > dwLength)
3417     {
3418         if (lpServiceName != NULL)
3419             wcscpy(lpServiceName, lpService->lpServiceName);
3420 
3421         dwError = ERROR_SUCCESS;
3422     }
3423     else
3424     {
3425         dwError = ERROR_INSUFFICIENT_BUFFER;
3426     }
3427 
3428     *lpcchBuffer = dwLength;
3429 
3430     return dwError;
3431 }
3432 
3433 
3434 /* Function 22 */
3435 DWORD
3436 WINAPI
3437 RI_ScSetServiceBitsA(
3438     RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3439     DWORD dwServiceBits,
3440     int bSetBitsOn,
3441     int bUpdateImmediately,
3442     char *lpString)
3443 {
3444     if (ScmShutdown)
3445         return ERROR_SHUTDOWN_IN_PROGRESS;
3446 
3447     if (lpString != NULL)
3448         return ERROR_INVALID_PARAMETER;
3449 
3450     return RI_ScSetServiceBitsW(hServiceStatus,
3451                                 dwServiceBits,
3452                                 bSetBitsOn,
3453                                 bUpdateImmediately,
3454                                 NULL);
3455 }
3456 
3457 
3458 /* Function 23 */
3459 DWORD
3460 WINAPI
3461 RChangeServiceConfigA(
3462     SC_RPC_HANDLE hService,
3463     DWORD dwServiceType,
3464     DWORD dwStartType,
3465     DWORD dwErrorControl,
3466     LPSTR lpBinaryPathName,
3467     LPSTR lpLoadOrderGroup,
3468     LPDWORD lpdwTagId,
3469     LPBYTE lpDependencies,
3470     DWORD dwDependSize,
3471     LPSTR lpServiceStartName,
3472     LPBYTE lpPassword,
3473     DWORD dwPwSize,
3474     LPSTR lpDisplayName)
3475 {
3476     DWORD dwError = ERROR_SUCCESS;
3477     LPWSTR lpBinaryPathNameW = NULL;
3478     LPWSTR lpLoadOrderGroupW = NULL;
3479     LPWSTR lpDependenciesW = NULL;
3480     LPWSTR lpServiceStartNameW = NULL;
3481     LPWSTR lpDisplayNameW = NULL;
3482     DWORD dwDependenciesLength = 0;
3483     SIZE_T cchLength;
3484     int len;
3485     LPCSTR lpStr;
3486 
3487     if (lpBinaryPathName)
3488     {
3489         len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3490         lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3491         if (!lpBinaryPathNameW)
3492         {
3493             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3494             goto cleanup;
3495         }
3496         MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3497     }
3498 
3499     if (lpLoadOrderGroup)
3500     {
3501         len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3502         lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3503         if (!lpLoadOrderGroupW)
3504         {
3505             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3506             goto cleanup;
3507         }
3508         MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3509     }
3510 
3511     if (lpDependencies)
3512     {
3513         lpStr = (LPCSTR)lpDependencies;
3514         while (*lpStr)
3515         {
3516             cchLength = strlen(lpStr) + 1;
3517             dwDependenciesLength += (DWORD)cchLength;
3518             lpStr = lpStr + cchLength;
3519         }
3520         dwDependenciesLength++;
3521 
3522         lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3523         if (!lpDependenciesW)
3524         {
3525             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3526             goto cleanup;
3527         }
3528         MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3529     }
3530 
3531     if (lpServiceStartName)
3532     {
3533         len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3534         lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3535         if (!lpServiceStartNameW)
3536         {
3537             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3538             goto cleanup;
3539         }
3540         MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3541     }
3542 
3543     if (lpDisplayName)
3544     {
3545         len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3546         lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3547         if (!lpDisplayNameW)
3548         {
3549             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3550             goto cleanup;
3551         }
3552         MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3553     }
3554 
3555     dwError = RChangeServiceConfigW(hService,
3556                                     dwServiceType,
3557                                     dwStartType,
3558                                     dwErrorControl,
3559                                     lpBinaryPathNameW,
3560                                     lpLoadOrderGroupW,
3561                                     lpdwTagId,
3562                                     (LPBYTE)lpDependenciesW,
3563                                     dwDependenciesLength,
3564                                     lpServiceStartNameW,
3565                                     lpPassword,
3566                                     dwPwSize,
3567                                     lpDisplayNameW);
3568 
3569 cleanup:
3570     if (lpBinaryPathNameW != NULL)
3571         HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3572 
3573     if (lpLoadOrderGroupW != NULL)
3574         HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3575 
3576     if (lpDependenciesW != NULL)
3577         HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3578 
3579     if (lpServiceStartNameW != NULL)
3580         HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3581 
3582     if (lpDisplayNameW != NULL)
3583         HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3584 
3585     return dwError;
3586 }
3587 
3588 
3589 /* Function 24 */
3590 DWORD
3591 WINAPI
3592 RCreateServiceA(
3593     SC_RPC_HANDLE hSCManager,
3594     LPSTR lpServiceName,
3595     LPSTR lpDisplayName,
3596     DWORD dwDesiredAccess,
3597     DWORD dwServiceType,
3598     DWORD dwStartType,
3599     DWORD dwErrorControl,
3600     LPSTR lpBinaryPathName,
3601     LPSTR lpLoadOrderGroup,
3602     LPDWORD lpdwTagId,
3603     LPBYTE lpDependencies,
3604     DWORD dwDependSize,
3605     LPSTR lpServiceStartName,
3606     LPBYTE lpPassword,
3607     DWORD dwPwSize,
3608     LPSC_RPC_HANDLE lpServiceHandle)
3609 {
3610     DWORD dwError = ERROR_SUCCESS;
3611     LPWSTR lpServiceNameW = NULL;
3612     LPWSTR lpDisplayNameW = NULL;
3613     LPWSTR lpBinaryPathNameW = NULL;
3614     LPWSTR lpLoadOrderGroupW = NULL;
3615     LPWSTR lpDependenciesW = NULL;
3616     LPWSTR lpServiceStartNameW = NULL;
3617     DWORD dwDependenciesLength = 0;
3618     SIZE_T cchLength;
3619     int len;
3620     LPCSTR lpStr;
3621 
3622     if (lpServiceName)
3623     {
3624         len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3625         lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3626         if (!lpServiceNameW)
3627         {
3628             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3629             goto cleanup;
3630         }
3631         MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3632     }
3633 
3634     if (lpDisplayName)
3635     {
3636         len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3637         lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3638         if (!lpDisplayNameW)
3639         {
3640             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3641             goto cleanup;
3642         }
3643         MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3644     }
3645 
3646     if (lpBinaryPathName)
3647     {
3648         len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3649         lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3650         if (!lpBinaryPathNameW)
3651         {
3652             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3653             goto cleanup;
3654         }
3655         MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3656     }
3657 
3658     if (lpLoadOrderGroup)
3659     {
3660         len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3661         lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3662         if (!lpLoadOrderGroupW)
3663         {
3664             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3665             goto cleanup;
3666         }
3667         MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3668     }
3669 
3670     if (lpDependencies)
3671     {
3672         lpStr = (LPCSTR)lpDependencies;
3673         while (*lpStr)
3674         {
3675             cchLength = strlen(lpStr) + 1;
3676             dwDependenciesLength += (DWORD)cchLength;
3677             lpStr = lpStr + cchLength;
3678         }
3679         dwDependenciesLength++;
3680 
3681         lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3682         if (!lpDependenciesW)
3683         {
3684             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3685             goto cleanup;
3686         }
3687         MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3688     }
3689 
3690     if (lpServiceStartName)
3691     {
3692         len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3693         lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3694         if (!lpServiceStartNameW)
3695         {
3696             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3697             goto cleanup;
3698         }
3699         MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3700     }
3701 
3702     dwError = RCreateServiceW(hSCManager,
3703                               lpServiceNameW,
3704                               lpDisplayNameW,
3705                               dwDesiredAccess,
3706                               dwServiceType,
3707                               dwStartType,
3708                               dwErrorControl,
3709                               lpBinaryPathNameW,
3710                               lpLoadOrderGroupW,
3711                               lpdwTagId,
3712                               (LPBYTE)lpDependenciesW,
3713                               dwDependenciesLength,
3714                               lpServiceStartNameW,
3715                               lpPassword,
3716                               dwPwSize,
3717                               lpServiceHandle);
3718 
3719 cleanup:
3720     if (lpServiceNameW !=NULL)
3721         HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3722 
3723     if (lpDisplayNameW != NULL)
3724         HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3725 
3726     if (lpBinaryPathNameW != NULL)
3727         HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3728 
3729     if (lpLoadOrderGroupW != NULL)
3730         HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3731 
3732     if (lpDependenciesW != NULL)
3733         HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3734 
3735     if (lpServiceStartNameW != NULL)
3736         HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3737 
3738     return dwError;
3739 }
3740 
3741 
3742 /* Function 25 */
3743 DWORD
3744 WINAPI
3745 REnumDependentServicesA(
3746     SC_RPC_HANDLE hService,
3747     DWORD dwServiceState,
3748     LPBYTE lpServices,
3749     DWORD cbBufSize,
3750     LPBOUNDED_DWORD_256K pcbBytesNeeded,
3751     LPBOUNDED_DWORD_256K lpServicesReturned)
3752 {
3753     DWORD dwError = ERROR_SUCCESS;
3754     DWORD dwServicesReturned = 0;
3755     DWORD dwServiceCount;
3756     HKEY hServicesKey = NULL;
3757     PSERVICE_HANDLE hSvc;
3758     PSERVICE lpService = NULL;
3759     PSERVICE *lpServicesArray = NULL;
3760     LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3761     LPSTR lpStr;
3762 
3763     *pcbBytesNeeded = 0;
3764     *lpServicesReturned = 0;
3765 
3766     DPRINT("REnumDependentServicesA() called\n");
3767 
3768     hSvc = ScmGetServiceFromHandle(hService);
3769     if (hSvc == NULL)
3770     {
3771         DPRINT1("Invalid service handle!\n");
3772         return ERROR_INVALID_HANDLE;
3773     }
3774 
3775     lpService = hSvc->ServiceEntry;
3776 
3777     /* Check access rights */
3778     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3779                                   SC_MANAGER_ENUMERATE_SERVICE))
3780     {
3781         DPRINT("Insufficient access rights! 0x%lx\n",
3782                hSvc->Handle.DesiredAccess);
3783         return ERROR_ACCESS_DENIED;
3784     }
3785 
3786     /* Open the Services Reg key */
3787     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3788                             L"System\\CurrentControlSet\\Services",
3789                             0,
3790                             KEY_READ,
3791                             &hServicesKey);
3792 
3793     if (dwError != ERROR_SUCCESS)
3794         return dwError;
3795 
3796     /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3797              both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3798              are the same for both. Verified in WINXP. */
3799 
3800     /* First determine the bytes needed and get the number of dependent services*/
3801     dwError = Int_EnumDependentServicesW(hServicesKey,
3802                                          lpService,
3803                                          dwServiceState,
3804                                          NULL,
3805                                          pcbBytesNeeded,
3806                                          &dwServicesReturned);
3807     if (dwError != ERROR_SUCCESS)
3808         goto Done;
3809 
3810     /* If buffer size is less than the bytes needed or pointer is null*/
3811     if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3812     {
3813         dwError = ERROR_MORE_DATA;
3814         goto Done;
3815     }
3816 
3817     /* Allocate memory for array of service pointers */
3818     lpServicesArray = HeapAlloc(GetProcessHeap(),
3819                                 HEAP_ZERO_MEMORY,
3820                                 (dwServicesReturned + 1) * sizeof(PSERVICE));
3821     if (!lpServicesArray)
3822     {
3823         DPRINT("Could not allocate a buffer!!\n");
3824         dwError = ERROR_NOT_ENOUGH_MEMORY;
3825         goto Done;
3826     }
3827 
3828     dwServicesReturned = 0;
3829     *pcbBytesNeeded = 0;
3830 
3831     dwError = Int_EnumDependentServicesW(hServicesKey,
3832                                          lpService,
3833                                          dwServiceState,
3834                                          lpServicesArray,
3835                                          pcbBytesNeeded,
3836                                          &dwServicesReturned);
3837     if (dwError != ERROR_SUCCESS)
3838     {
3839         goto Done;
3840     }
3841 
3842     lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3843     lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3844 
3845     /* Copy EnumDepenedentService to Buffer */
3846     for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3847     {
3848         lpService = lpServicesArray[dwServiceCount];
3849 
3850         /* Copy the status info */
3851         memcpy(&lpServicesPtr->ServiceStatus,
3852                &lpService->Status,
3853                sizeof(SERVICE_STATUS));
3854 
3855         /* Copy display name */
3856         WideCharToMultiByte(CP_ACP,
3857                             0,
3858                             lpService->lpDisplayName,
3859                             -1,
3860                             lpStr,
3861                             (int)wcslen(lpService->lpDisplayName),
3862                             0,
3863                             0);
3864         lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3865         lpStr += strlen(lpStr) + 1;
3866 
3867         /* Copy service name */
3868         WideCharToMultiByte(CP_ACP,
3869                             0,
3870                             lpService->lpServiceName,
3871                             -1,
3872                             lpStr,
3873                             (int)wcslen(lpService->lpServiceName),
3874                             0,
3875                             0);
3876         lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3877         lpStr += strlen(lpStr) + 1;
3878 
3879         lpServicesPtr++;
3880     }
3881 
3882     *lpServicesReturned = dwServicesReturned;
3883 
3884 Done:
3885     if (lpServicesArray)
3886         HeapFree(GetProcessHeap(), 0, lpServicesArray);
3887 
3888     RegCloseKey(hServicesKey);
3889 
3890     DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3891 
3892     return dwError;
3893 }
3894 
3895 
3896 /* Function 26 */
3897 DWORD
3898 WINAPI
3899 REnumServicesStatusA(
3900     SC_RPC_HANDLE hSCManager,
3901     DWORD dwServiceType,
3902     DWORD dwServiceState,
3903     LPBYTE lpBuffer,
3904     DWORD dwBufSize,
3905     LPBOUNDED_DWORD_256K pcbBytesNeeded,
3906     LPBOUNDED_DWORD_256K lpServicesReturned,
3907     LPBOUNDED_DWORD_256K lpResumeHandle)
3908 {
3909     LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3910     LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
3911     LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3912     LPWSTR lpStringPtrW;
3913     LPSTR lpStringPtrA;
3914     DWORD dwError;
3915     DWORD dwServiceCount;
3916 
3917     DPRINT("REnumServicesStatusA() called\n");
3918 
3919     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
3920     {
3921         return ERROR_INVALID_ADDRESS;
3922     }
3923 
3924     if ((dwBufSize > 0) && (lpBuffer))
3925     {
3926         lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3927         if (!lpStatusPtrW)
3928         {
3929             DPRINT("Failed to allocate buffer!\n");
3930             return ERROR_NOT_ENOUGH_MEMORY;
3931         }
3932     }
3933 
3934     dwError = REnumServicesStatusW(hSCManager,
3935                                    dwServiceType,
3936                                    dwServiceState,
3937                                    (LPBYTE)lpStatusPtrW,
3938                                    dwBufSize,
3939                                    pcbBytesNeeded,
3940                                    lpServicesReturned,
3941                                    lpResumeHandle);
3942 
3943     /* if no services were returned then we are Done */
3944     if (*lpServicesReturned == 0)
3945         goto Done;
3946 
3947     lpStatusPtrIncrW = lpStatusPtrW;
3948     lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3949     lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3950                   *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3951     lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3952                   *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3953 
3954     for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3955     {
3956         /* Copy the service name */
3957         WideCharToMultiByte(CP_ACP,
3958                             0,
3959                             lpStringPtrW,
3960                             -1,
3961                             lpStringPtrA,
3962                             (int)wcslen(lpStringPtrW),
3963                             0,
3964                             0);
3965 
3966         lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3967         lpStringPtrA += wcslen(lpStringPtrW) + 1;
3968         lpStringPtrW += wcslen(lpStringPtrW) + 1;
3969 
3970         /* Copy the display name */
3971         WideCharToMultiByte(CP_ACP,
3972                             0,
3973                             lpStringPtrW,
3974                             -1,
3975                             lpStringPtrA,
3976                             (int)wcslen(lpStringPtrW),
3977                             0,
3978                             0);
3979 
3980         lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3981         lpStringPtrA += wcslen(lpStringPtrW) + 1;
3982         lpStringPtrW += wcslen(lpStringPtrW) + 1;
3983 
3984         /* Copy the status information */
3985         memcpy(&lpStatusPtrA->ServiceStatus,
3986                &lpStatusPtrIncrW->ServiceStatus,
3987                sizeof(SERVICE_STATUS));
3988 
3989         lpStatusPtrIncrW++;
3990         lpStatusPtrA++;
3991     }
3992 
3993 Done:
3994     if (lpStatusPtrW)
3995         HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3996 
3997     DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3998 
3999     return dwError;
4000 }
4001 
4002 
4003 /* Function 27 */
4004 DWORD
4005 WINAPI
4006 ROpenSCManagerA(
4007     LPSTR lpMachineName,
4008     LPSTR lpDatabaseName,
4009     DWORD dwDesiredAccess,
4010     LPSC_RPC_HANDLE lpScHandle)
4011 {
4012     UNICODE_STRING MachineName;
4013     UNICODE_STRING DatabaseName;
4014     DWORD dwError;
4015 
4016     DPRINT("ROpenSCManagerA() called\n");
4017 
4018     if (lpMachineName)
4019         RtlCreateUnicodeStringFromAsciiz(&MachineName,
4020                                          lpMachineName);
4021 
4022     if (lpDatabaseName)
4023         RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
4024                                          lpDatabaseName);
4025 
4026     dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
4027                               lpDatabaseName ? DatabaseName.Buffer : NULL,
4028                               dwDesiredAccess,
4029                               lpScHandle);
4030 
4031     if (lpMachineName)
4032         RtlFreeUnicodeString(&MachineName);
4033 
4034     if (lpDatabaseName)
4035         RtlFreeUnicodeString(&DatabaseName);
4036 
4037     return dwError;
4038 }
4039 
4040 
4041 /* Function 28 */
4042 DWORD
4043 WINAPI
4044 ROpenServiceA(
4045     SC_RPC_HANDLE hSCManager,
4046     LPSTR lpServiceName,
4047     DWORD dwDesiredAccess,
4048     LPSC_RPC_HANDLE lpServiceHandle)
4049 {
4050     UNICODE_STRING ServiceName;
4051     DWORD dwError;
4052 
4053     DPRINT("ROpenServiceA() called\n");
4054 
4055     if (lpServiceName)
4056         RtlCreateUnicodeStringFromAsciiz(&ServiceName,
4057                                          lpServiceName);
4058 
4059     dwError = ROpenServiceW(hSCManager,
4060                             lpServiceName ? ServiceName.Buffer : NULL,
4061                             dwDesiredAccess,
4062                             lpServiceHandle);
4063 
4064     if (lpServiceName)
4065         RtlFreeUnicodeString(&ServiceName);
4066 
4067     return dwError;
4068 }
4069 
4070 
4071 /* Function 29 */
4072 DWORD
4073 WINAPI
4074 RQueryServiceConfigA(
4075     SC_RPC_HANDLE hService,
4076     LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4077     DWORD cbBufSize,
4078     LPBOUNDED_DWORD_8K pcbBytesNeeded)
4079 {
4080     LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
4081     DWORD dwError = ERROR_SUCCESS;
4082     PSERVICE_HANDLE hSvc;
4083     PSERVICE lpService = NULL;
4084     HKEY hServiceKey = NULL;
4085     LPWSTR lpImagePath = NULL;
4086     LPWSTR lpServiceStartName = NULL;
4087     LPWSTR lpDependencies = NULL;
4088     DWORD dwDependenciesLength = 0;
4089     DWORD dwRequiredSize;
4090     LPSTR lpStr;
4091 
4092     DPRINT("RQueryServiceConfigA() called\n");
4093 
4094     if (ScmShutdown)
4095         return ERROR_SHUTDOWN_IN_PROGRESS;
4096 
4097     hSvc = ScmGetServiceFromHandle(hService);
4098     if (hSvc == NULL)
4099     {
4100         DPRINT1("Invalid service handle!\n");
4101         return ERROR_INVALID_HANDLE;
4102     }
4103 
4104     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4105                                   SERVICE_QUERY_CONFIG))
4106     {
4107         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4108         return ERROR_ACCESS_DENIED;
4109     }
4110 
4111     lpService = hSvc->ServiceEntry;
4112     if (lpService == NULL)
4113     {
4114         DPRINT("lpService == NULL!\n");
4115         return ERROR_INVALID_HANDLE;
4116     }
4117 
4118     /* Lock the service database shared */
4119     ScmLockDatabaseShared();
4120 
4121     dwError = ScmOpenServiceKey(lpService->lpServiceName,
4122                                 KEY_READ,
4123                                 &hServiceKey);
4124     if (dwError != ERROR_SUCCESS)
4125         goto Done;
4126 
4127     /* Read the image path */
4128     dwError = ScmReadString(hServiceKey,
4129                             L"ImagePath",
4130                             &lpImagePath);
4131     if (dwError != ERROR_SUCCESS)
4132         goto Done;
4133 
4134     /* Read the service start name */
4135     ScmReadString(hServiceKey,
4136                   L"ObjectName",
4137                   &lpServiceStartName);
4138 
4139     /* Read the dependencies */
4140     ScmReadDependencies(hServiceKey,
4141                         &lpDependencies,
4142                         &dwDependenciesLength);
4143 
4144     dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA);
4145 
4146     if (lpImagePath != NULL)
4147         dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
4148     else
4149         dwRequiredSize += 2 * sizeof(CHAR);
4150 
4151     if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
4152         dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
4153     else
4154         dwRequiredSize += 2 * sizeof(CHAR);
4155 
4156     /* Add Dependencies length */
4157     if (lpDependencies != NULL)
4158         dwRequiredSize += dwDependenciesLength;
4159     else
4160         dwRequiredSize += 2 * sizeof(CHAR);
4161 
4162     if (lpServiceStartName != NULL)
4163         dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
4164     else
4165         dwRequiredSize += 2 * sizeof(CHAR);
4166 
4167     if (lpService->lpDisplayName != NULL)
4168         dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
4169     else
4170         dwRequiredSize += 2 * sizeof(CHAR);
4171 
4172     if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
4173     {
4174         dwError = ERROR_INSUFFICIENT_BUFFER;
4175     }
4176     else
4177     {
4178         lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
4179         lpServiceConfig->dwStartType = lpService->dwStartType;
4180         lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
4181         lpServiceConfig->dwTagId = lpService->dwTag;
4182 
4183         lpStr = (LPSTR)(lpServiceConfig + 1);
4184 
4185         /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4186            Verified in WINXP */
4187 
4188         if (lpImagePath)
4189         {
4190             WideCharToMultiByte(CP_ACP,
4191                                 0,
4192                                 lpImagePath,
4193                                 -1,
4194                                 lpStr,
4195                                 (int)(wcslen(lpImagePath) + 1),
4196                                 0,
4197                                 0);
4198         }
4199         else
4200         {
4201             *lpStr = 0;
4202         }
4203 
4204         lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4205         lpStr += (strlen((LPSTR)lpStr) + 1);
4206 
4207         if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4208         {
4209             WideCharToMultiByte(CP_ACP,
4210                                 0,
4211                                 lpService->lpGroup->lpGroupName,
4212                                 -1,
4213                                 lpStr,
4214                                 (int)(wcslen(lpService->lpGroup->lpGroupName) + 1),
4215                                 0,
4216                                 0);
4217         }
4218         else
4219         {
4220             *lpStr = 0;
4221         }
4222 
4223         lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4224         lpStr += (strlen(lpStr) + 1);
4225 
4226         /* Append Dependencies */
4227         if (lpDependencies)
4228         {
4229             WideCharToMultiByte(CP_ACP,
4230                                 0,
4231                                 lpDependencies,
4232                                 dwDependenciesLength,
4233                                 lpStr,
4234                                 dwDependenciesLength,
4235                                 0,
4236                                 0);
4237         }
4238         else
4239         {
4240             *lpStr = 0;
4241         }
4242 
4243         lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4244         if (lpDependencies)
4245             lpStr += dwDependenciesLength;
4246         else
4247             lpStr += (strlen(lpStr) + 1);
4248 
4249         if (lpServiceStartName)
4250         {
4251             WideCharToMultiByte(CP_ACP,
4252                                 0,
4253                                 lpServiceStartName,
4254                                 -1,
4255                                 lpStr,
4256                                 (int)(wcslen(lpServiceStartName) + 1),
4257                                 0,
4258                                 0);
4259         }
4260         else
4261         {
4262             *lpStr = 0;
4263         }
4264 
4265         lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4266         lpStr += (strlen(lpStr) + 1);
4267 
4268         if (lpService->lpDisplayName)
4269         {
4270             WideCharToMultiByte(CP_ACP,
4271                                 0,
4272                                 lpService->lpDisplayName,
4273                                 -1,
4274                                 lpStr,
4275                                 (int)(wcslen(lpService->lpDisplayName) + 1),
4276                                 0,
4277                                 0);
4278         }
4279         else
4280         {
4281             *lpStr = 0;
4282         }
4283 
4284         lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4285     }
4286 
4287     if (pcbBytesNeeded != NULL)
4288         *pcbBytesNeeded = dwRequiredSize;
4289 
4290 Done:
4291     /* Unlock the service database */
4292     ScmUnlockDatabase();
4293 
4294     if (lpImagePath != NULL)
4295         HeapFree(GetProcessHeap(), 0, lpImagePath);
4296 
4297     if (lpServiceStartName != NULL)
4298         HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4299 
4300     if (lpDependencies != NULL)
4301         HeapFree(GetProcessHeap(), 0, lpDependencies);
4302 
4303     if (hServiceKey != NULL)
4304         RegCloseKey(hServiceKey);
4305 
4306     DPRINT("RQueryServiceConfigA() done\n");
4307 
4308     return dwError;
4309 }
4310 
4311 
4312 /* Function 30 */
4313 DWORD
4314 WINAPI
4315 RQueryServiceLockStatusA(
4316     SC_RPC_HANDLE hSCManager,
4317     LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4318     DWORD cbBufSize,
4319     LPBOUNDED_DWORD_4K pcbBytesNeeded)
4320 {
4321     LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSA)lpBuf;
4322     PMANAGER_HANDLE hMgr;
4323     DWORD dwRequiredSize;
4324 
4325     if (!lpLockStatus || !pcbBytesNeeded)
4326         return ERROR_INVALID_PARAMETER;
4327 
4328     hMgr = ScmGetServiceManagerFromHandle(hSCManager);
4329     if (hMgr == NULL)
4330     {
4331         DPRINT1("Invalid service manager handle!\n");
4332         return ERROR_INVALID_HANDLE;
4333     }
4334 
4335     if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
4336                                   SC_MANAGER_QUERY_LOCK_STATUS))
4337     {
4338         DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
4339         return ERROR_ACCESS_DENIED;
4340     }
4341 
4342     /* FIXME: we need to compute instead the real length of the owner name */
4343     dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR);
4344     *pcbBytesNeeded = dwRequiredSize;
4345 
4346     if (cbBufSize < dwRequiredSize)
4347         return ERROR_INSUFFICIENT_BUFFER;
4348 
4349     ScmQueryServiceLockStatusA(lpLockStatus);
4350 
4351     return ERROR_SUCCESS;
4352 }
4353 
4354 
4355 /* Function 31 */
4356 DWORD
4357 WINAPI
4358 RStartServiceA(
4359     SC_RPC_HANDLE hService,
4360     DWORD argc,
4361     LPSTRING_PTRSA argv)
4362 {
4363     DWORD dwError = ERROR_SUCCESS;
4364     PSERVICE_HANDLE hSvc;
4365     PSERVICE lpService = NULL;
4366     LPWSTR *lpVector = NULL;
4367     DWORD i;
4368     DWORD dwLength;
4369 
4370     DPRINT("RStartServiceA() called\n");
4371 
4372     if (ScmShutdown)
4373         return ERROR_SHUTDOWN_IN_PROGRESS;
4374 
4375     hSvc = ScmGetServiceFromHandle(hService);
4376     if (hSvc == NULL)
4377     {
4378         DPRINT1("Invalid service handle!\n");
4379         return ERROR_INVALID_HANDLE;
4380     }
4381 
4382     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4383                                   SERVICE_START))
4384     {
4385         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4386         return ERROR_ACCESS_DENIED;
4387     }
4388 
4389     lpService = hSvc->ServiceEntry;
4390     if (lpService == NULL)
4391     {
4392         DPRINT("lpService == NULL!\n");
4393         return ERROR_INVALID_HANDLE;
4394     }
4395 
4396     if (lpService->dwStartType == SERVICE_DISABLED)
4397         return ERROR_SERVICE_DISABLED;
4398 
4399     if (lpService->bDeleted)
4400         return ERROR_SERVICE_MARKED_FOR_DELETE;
4401 
4402     /* Build a Unicode argument vector */
4403     if (argc > 0)
4404     {
4405         lpVector = HeapAlloc(GetProcessHeap(),
4406                              HEAP_ZERO_MEMORY,
4407                              argc * sizeof(LPWSTR));
4408         if (lpVector == NULL)
4409             return ERROR_NOT_ENOUGH_MEMORY;
4410 
4411         for (i = 0; i < argc; i++)
4412         {
4413             dwLength = MultiByteToWideChar(CP_ACP,
4414                                            0,
4415                                            ((LPSTR*)argv)[i],
4416                                            -1,
4417                                            NULL,
4418                                            0);
4419 
4420             lpVector[i] = HeapAlloc(GetProcessHeap(),
4421                                     HEAP_ZERO_MEMORY,
4422                                     dwLength * sizeof(WCHAR));
4423             if (lpVector[i] == NULL)
4424             {
4425                 dwError = ERROR_NOT_ENOUGH_MEMORY;
4426                 goto done;
4427             }
4428 
4429             MultiByteToWideChar(CP_ACP,
4430                                 0,
4431                                 ((LPSTR*)argv)[i],
4432                                 -1,
4433                                 lpVector[i],
4434                                 dwLength);
4435         }
4436     }
4437 
4438     /* Start the service */
4439     dwError = ScmStartService(lpService, argc, lpVector);
4440 
4441 done:
4442     /* Free the Unicode argument vector */
4443     if (lpVector != NULL)
4444     {
4445         for (i = 0; i < argc; i++)
4446         {
4447             if (lpVector[i] != NULL)
4448                 HeapFree(GetProcessHeap(), 0, lpVector[i]);
4449         }
4450         HeapFree(GetProcessHeap(), 0, lpVector);
4451     }
4452 
4453     return dwError;
4454 }
4455 
4456 
4457 /* Function 32 */
4458 DWORD
4459 WINAPI
4460 RGetServiceDisplayNameA(
4461     SC_RPC_HANDLE hSCManager,
4462     LPCSTR lpServiceName,
4463     LPSTR lpDisplayName,
4464     LPBOUNDED_DWORD_4K lpcchBuffer)
4465 {
4466     // PMANAGER_HANDLE hManager;
4467     PSERVICE lpService = NULL;
4468     LPCWSTR lpSvcDisplayName;
4469     LPWSTR lpServiceNameW;
4470     DWORD dwLength;
4471 
4472     DPRINT("RGetServiceDisplayNameA() called\n");
4473     DPRINT("hSCManager = %p\n", hSCManager);
4474     DPRINT("lpServiceName: %s\n", lpServiceName);
4475     DPRINT("lpDisplayName: %p\n", lpDisplayName);
4476     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4477 
4478 #if 0
4479     hManager = (PMANAGER_HANDLE)hSCManager;
4480     if (hManager->Handle.Tag != MANAGER_TAG)
4481     {
4482         DPRINT("Invalid manager handle!\n");
4483         return ERROR_INVALID_HANDLE;
4484     }
4485 #endif
4486 
4487     /* Get service database entry */
4488     if (lpServiceName != NULL)
4489     {
4490         dwLength = (DWORD)(strlen(lpServiceName) + 1);
4491         lpServiceNameW = HeapAlloc(GetProcessHeap(),
4492                                    HEAP_ZERO_MEMORY,
4493                                    dwLength * sizeof(WCHAR));
4494         if (!lpServiceNameW)
4495             return ERROR_NOT_ENOUGH_MEMORY;
4496 
4497         MultiByteToWideChar(CP_ACP,
4498                             0,
4499                             lpServiceName,
4500                             -1,
4501                             lpServiceNameW,
4502                             dwLength);
4503 
4504         lpService = ScmGetServiceEntryByName(lpServiceNameW);
4505 
4506         HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4507     }
4508 
4509     if (lpService == NULL)
4510     {
4511         DPRINT("Could not find the service!\n");
4512         return ERROR_SERVICE_DOES_NOT_EXIST;
4513     }
4514 
4515     if (lpService->lpDisplayName)
4516         lpSvcDisplayName = lpService->lpDisplayName;
4517     else
4518         lpSvcDisplayName = lpService->lpServiceName;
4519 
4520     /*
4521      * NOTE: On Windows the comparison on *lpcchBuffer is made against
4522      * the number of (wide) characters of the UNICODE display name, and
4523      * not against the number of bytes needed to store the ANSI string.
4524      */
4525     dwLength = (DWORD)wcslen(lpSvcDisplayName);
4526 
4527     if (*lpcchBuffer > dwLength)
4528     {
4529         if (lpDisplayName != NULL &&
4530             WideCharToMultiByte(CP_ACP,
4531                                 0,
4532                                 lpSvcDisplayName,
4533                                 -1,
4534                                 lpDisplayName,
4535                                 (int)*lpcchBuffer,
4536                                 NULL,
4537                                 NULL) == 0)
4538         {
4539             /*
4540              * But then, if *lpcchBuffer was greater than the number of
4541              * (wide) characters of the UNICODE display name, yet smaller
4542              * than the number of bytes needed due to the possible presence
4543              * of DBCS characters, the *exact* number of bytes is returned
4544              * (without the NULL terminator).
4545              */
4546             dwLength = (DWORD)WideCharToMultiByte(CP_ACP,
4547                                                   0,
4548                                                   lpSvcDisplayName,
4549                                                   (int)dwLength,
4550                                                   NULL,
4551                                                   0,
4552                                                   NULL,
4553                                                   NULL);
4554             *lpDisplayName = 0;
4555             *lpcchBuffer = dwLength;
4556             return ERROR_INSUFFICIENT_BUFFER;
4557         }
4558 
4559         /*
4560          * NOTE: On Windows, RGetServiceDisplayNameA() does not update
4561          * *lpcchBuffer on success, contrary to RGetServiceDisplayNameW().
4562          */
4563         return ERROR_SUCCESS;
4564     }
4565     else
4566     {
4567         /*
4568          * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4569          * (wide) characters of the UNICODE display name, only an upper
4570          * estimation is returned by doubling the string length, to account
4571          * for the presence of any possible DBCS characters.
4572          */
4573         *lpcchBuffer = dwLength * sizeof(WCHAR);
4574         return ERROR_INSUFFICIENT_BUFFER;
4575     }
4576 }
4577 
4578 
4579 /* Function 33 */
4580 DWORD
4581 WINAPI
4582 RGetServiceKeyNameA(
4583     SC_RPC_HANDLE hSCManager,
4584     LPCSTR lpDisplayName,
4585     LPSTR lpServiceName,
4586     LPBOUNDED_DWORD_4K lpcchBuffer)
4587 {
4588     // PMANAGER_HANDLE hManager;
4589     PSERVICE lpService;
4590     LPWSTR lpDisplayNameW;
4591     DWORD dwLength;
4592 
4593     DPRINT("RGetServiceKeyNameA() called\n");
4594     DPRINT("hSCManager = %p\n", hSCManager);
4595     DPRINT("lpDisplayName: %s\n", lpDisplayName);
4596     DPRINT("lpServiceName: %p\n", lpServiceName);
4597     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4598 
4599 #if 0
4600     hManager = (PMANAGER_HANDLE)hSCManager;
4601     if (hManager->Handle.Tag != MANAGER_TAG)
4602     {
4603         DPRINT("Invalid manager handle!\n");
4604         return ERROR_INVALID_HANDLE;
4605     }
4606 #endif
4607 
4608     /* Get service database entry */
4609 
4610     dwLength = (DWORD)(strlen(lpDisplayName) + 1);
4611     lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4612                                HEAP_ZERO_MEMORY,
4613                                dwLength * sizeof(WCHAR));
4614     if (!lpDisplayNameW)
4615         return ERROR_NOT_ENOUGH_MEMORY;
4616 
4617     MultiByteToWideChar(CP_ACP,
4618                         0,
4619                         lpDisplayName,
4620                         -1,
4621                         lpDisplayNameW,
4622                         dwLength);
4623 
4624     lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4625 
4626     HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4627 
4628     if (lpService == NULL)
4629     {
4630         DPRINT("Could not find the service!\n");
4631         return ERROR_SERVICE_DOES_NOT_EXIST;
4632     }
4633 
4634     /*
4635      * NOTE: On Windows the comparison on *lpcchBuffer is made against
4636      * the number of (wide) characters of the UNICODE service name, and
4637      * not against the number of bytes needed to store the ANSI string.
4638      */
4639     dwLength = (DWORD)wcslen(lpService->lpServiceName);
4640 
4641     if (*lpcchBuffer > dwLength)
4642     {
4643         if (lpServiceName != NULL &&
4644             WideCharToMultiByte(CP_ACP,
4645                                 0,
4646                                 lpService->lpServiceName,
4647                                 -1,
4648                                 lpServiceName,
4649                                 (int)*lpcchBuffer,
4650                                 NULL,
4651                                 NULL) == 0)
4652         {
4653             /*
4654              * But then, if *lpcchBuffer was greater than the number of
4655              * (wide) characters of the UNICODE service name, yet smaller
4656              * than the number of bytes needed due to the possible presence
4657              * of DBCS characters, the *exact* number of bytes is returned
4658              * (without the NULL terminator).
4659              */
4660             dwLength = (DWORD)WideCharToMultiByte(CP_ACP,
4661                                                   0,
4662                                                   lpService->lpServiceName,
4663                                                   (int)dwLength,
4664                                                   NULL,
4665                                                   0,
4666                                                   NULL,
4667                                                   NULL);
4668             *lpServiceName = 0;
4669             *lpcchBuffer = dwLength;
4670             return ERROR_INSUFFICIENT_BUFFER;
4671         }
4672 
4673         /*
4674          * NOTE: On Windows, RGetServiceKeyNameA() does not update
4675          * *lpcchBuffer on success, contrary to RGetServiceKeyNameW().
4676          */
4677         return ERROR_SUCCESS;
4678     }
4679     else
4680     {
4681         /*
4682          * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
4683          * (wide) characters of the UNICODE service name, only an upper
4684          * estimation is returned by doubling the string length, to account
4685          * for the presence of any possible DBCS characters.
4686          */
4687         *lpcchBuffer = dwLength * sizeof(WCHAR);
4688         return ERROR_INSUFFICIENT_BUFFER;
4689     }
4690 }
4691 
4692 
4693 /* Function 34 */
4694 DWORD
4695 WINAPI
4696 RI_ScGetCurrentGroupStateW(
4697     SC_RPC_HANDLE hSCManager,
4698     LPWSTR lpLoadOrderGroup,
4699     LPDWORD lpState)
4700 {
4701     PMANAGER_HANDLE hManager;
4702     PSERVICE_GROUP pServiceGroup;
4703     DWORD dwError = ERROR_SUCCESS;
4704 
4705     DPRINT("RI_ScGetCurrentGroupStateW() called\n");
4706 
4707     if (ScmShutdown)
4708         return ERROR_SHUTDOWN_IN_PROGRESS;
4709 
4710     hManager = ScmGetServiceManagerFromHandle(hSCManager);
4711     if (hManager == NULL)
4712     {
4713         DPRINT1("Invalid service manager handle!\n");
4714         return ERROR_INVALID_HANDLE;
4715     }
4716 
4717     /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */
4718     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4719                                   SC_MANAGER_ENUMERATE_SERVICE))
4720     {
4721         DPRINT("Insufficient access rights! 0x%lx\n",
4722                 hManager->Handle.DesiredAccess);
4723         return ERROR_ACCESS_DENIED;
4724     }
4725 
4726     /* Lock the service database shared */
4727     ScmLockDatabaseShared();
4728 
4729     /* Get the group list entry */
4730     pServiceGroup = ScmGetServiceGroupByName(lpLoadOrderGroup);
4731     if (pServiceGroup == NULL)
4732     {
4733         dwError = ERROR_SERVICE_DOES_NOT_EXIST;
4734         goto done;
4735     }
4736 
4737     /* FIXME: Return the group state */
4738     *lpState = 0;
4739 
4740 done:
4741     /* Unlock the service database */
4742     ScmUnlockDatabase();
4743 
4744     DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError);
4745 
4746     return dwError;
4747 }
4748 
4749 
4750 /* Function 35 */
4751 DWORD
4752 WINAPI
4753 REnumServiceGroupW(
4754     SC_RPC_HANDLE hSCManager,
4755     DWORD dwServiceType,
4756     DWORD dwServiceState,
4757     LPBYTE lpBuffer,
4758     DWORD cbBufSize,
4759     LPBOUNDED_DWORD_256K pcbBytesNeeded,
4760     LPBOUNDED_DWORD_256K lpServicesReturned,
4761     LPBOUNDED_DWORD_256K lpResumeIndex,
4762     LPCWSTR pszGroupName)
4763 {
4764     PMANAGER_HANDLE hManager;
4765     PSERVICE lpService;
4766     DWORD dwError = ERROR_SUCCESS;
4767     PLIST_ENTRY ServiceEntry;
4768     PSERVICE CurrentService;
4769     DWORD dwState;
4770     DWORD dwRequiredSize;
4771     DWORD dwServiceCount;
4772     DWORD dwSize;
4773     DWORD dwLastResumeCount = 0;
4774     LPENUM_SERVICE_STATUSW lpStatusPtr;
4775     LPWSTR lpStringPtr;
4776 
4777     DPRINT("REnumServiceGroupW() called\n");
4778 
4779     if (ScmShutdown)
4780         return ERROR_SHUTDOWN_IN_PROGRESS;
4781 
4782     hManager = ScmGetServiceManagerFromHandle(hSCManager);
4783     if (hManager == NULL)
4784     {
4785         DPRINT1("Invalid service manager handle!\n");
4786         return ERROR_INVALID_HANDLE;
4787     }
4788 
4789     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
4790     {
4791         return ERROR_INVALID_ADDRESS;
4792     }
4793 
4794     *pcbBytesNeeded = 0;
4795     *lpServicesReturned = 0;
4796 
4797     if ((dwServiceType == 0) ||
4798         ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
4799     {
4800         DPRINT("Not a valid Service Type!\n");
4801         return ERROR_INVALID_PARAMETER;
4802     }
4803 
4804     if ((dwServiceState == 0) ||
4805         ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
4806     {
4807         DPRINT("Not a valid Service State!\n");
4808         return ERROR_INVALID_PARAMETER;
4809     }
4810 
4811     /* Check access rights */
4812     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4813                                   SC_MANAGER_ENUMERATE_SERVICE))
4814     {
4815         DPRINT("Insufficient access rights! 0x%lx\n",
4816                 hManager->Handle.DesiredAccess);
4817         return ERROR_ACCESS_DENIED;
4818     }
4819 
4820     if (lpResumeIndex)
4821         dwLastResumeCount = *lpResumeIndex;
4822 
4823     /* Lock the service database shared */
4824     ScmLockDatabaseShared();
4825 
4826     lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4827     if (lpService == NULL)
4828     {
4829         dwError = ERROR_SUCCESS;
4830         goto Done;
4831     }
4832 
4833     dwRequiredSize = 0;
4834     dwServiceCount = 0;
4835 
4836     for (ServiceEntry = &lpService->ServiceListEntry;
4837          ServiceEntry != &ServiceListHead;
4838          ServiceEntry = ServiceEntry->Flink)
4839     {
4840         CurrentService = CONTAINING_RECORD(ServiceEntry,
4841                                            SERVICE,
4842                                            ServiceListEntry);
4843 
4844         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4845             continue;
4846 
4847         dwState = SERVICE_ACTIVE;
4848         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4849             dwState = SERVICE_INACTIVE;
4850 
4851         if ((dwState & dwServiceState) == 0)
4852             continue;
4853 
4854         if (pszGroupName)
4855         {
4856             if (*pszGroupName == 0)
4857             {
4858                 if (CurrentService->lpGroup != NULL)
4859                     continue;
4860             }
4861             else
4862             {
4863                 if ((CurrentService->lpGroup == NULL) ||
4864                     _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4865                     continue;
4866             }
4867         }
4868 
4869         dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4870                  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4871                  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4872 
4873         if (dwRequiredSize + dwSize > cbBufSize)
4874         {
4875             DPRINT("Service name: %S  no fit\n", CurrentService->lpServiceName);
4876             break;
4877         }
4878 
4879         DPRINT("Service name: %S  fit\n", CurrentService->lpServiceName);
4880         dwRequiredSize += dwSize;
4881         dwServiceCount++;
4882         dwLastResumeCount = CurrentService->dwResumeCount;
4883     }
4884 
4885     DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4886     DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4887 
4888     for (;
4889          ServiceEntry != &ServiceListHead;
4890          ServiceEntry = ServiceEntry->Flink)
4891     {
4892         CurrentService = CONTAINING_RECORD(ServiceEntry,
4893                                            SERVICE,
4894                                            ServiceListEntry);
4895 
4896         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4897             continue;
4898 
4899         dwState = SERVICE_ACTIVE;
4900         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4901             dwState = SERVICE_INACTIVE;
4902 
4903         if ((dwState & dwServiceState) == 0)
4904             continue;
4905 
4906         if (pszGroupName)
4907         {
4908             if (*pszGroupName == 0)
4909             {
4910                 if (CurrentService->lpGroup != NULL)
4911                     continue;
4912             }
4913             else
4914             {
4915                 if ((CurrentService->lpGroup == NULL) ||
4916                     _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4917                     continue;
4918             }
4919         }
4920 
4921         dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
4922                            (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4923                            (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4924 
4925         dwError = ERROR_MORE_DATA;
4926     }
4927 
4928     DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4929 
4930     if (lpResumeIndex)
4931         *lpResumeIndex = dwLastResumeCount;
4932 
4933     *lpServicesReturned = dwServiceCount;
4934     *pcbBytesNeeded = dwRequiredSize;
4935 
4936     lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
4937     lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
4938                            dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
4939 
4940     dwRequiredSize = 0;
4941     for (ServiceEntry = &lpService->ServiceListEntry;
4942          ServiceEntry != &ServiceListHead;
4943          ServiceEntry = ServiceEntry->Flink)
4944     {
4945         CurrentService = CONTAINING_RECORD(ServiceEntry,
4946                                            SERVICE,
4947                                            ServiceListEntry);
4948 
4949         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4950             continue;
4951 
4952         dwState = SERVICE_ACTIVE;
4953         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4954             dwState = SERVICE_INACTIVE;
4955 
4956         if ((dwState & dwServiceState) == 0)
4957             continue;
4958 
4959         if (pszGroupName)
4960         {
4961             if (*pszGroupName == 0)
4962             {
4963                 if (CurrentService->lpGroup != NULL)
4964                     continue;
4965             }
4966             else
4967             {
4968                 if ((CurrentService->lpGroup == NULL) ||
4969                     _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4970                     continue;
4971             }
4972         }
4973 
4974         dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4975                  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4976                  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4977 
4978         if (dwRequiredSize + dwSize > cbBufSize)
4979             break;
4980 
4981         /* Copy the service name */
4982         wcscpy(lpStringPtr, CurrentService->lpServiceName);
4983         lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4984         lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
4985 
4986         /* Copy the display name */
4987         wcscpy(lpStringPtr, CurrentService->lpDisplayName);
4988         lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4989         lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
4990 
4991         /* Copy the status information */
4992         memcpy(&lpStatusPtr->ServiceStatus,
4993                &CurrentService->Status,
4994                sizeof(SERVICE_STATUS));
4995 
4996         lpStatusPtr++;
4997         dwRequiredSize += dwSize;
4998     }
4999 
5000     if (dwError == ERROR_SUCCESS)
5001     {
5002         *pcbBytesNeeded = 0;
5003         if (lpResumeIndex) *lpResumeIndex = 0;
5004     }
5005 
5006 Done:
5007     /* Unlock the service database */
5008     ScmUnlockDatabase();
5009 
5010     DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError);
5011 
5012     return dwError;
5013 }
5014 
5015 
5016 /* Function 36 */
5017 DWORD
5018 WINAPI
5019 RChangeServiceConfig2A(
5020     SC_RPC_HANDLE hService,
5021     SC_RPC_CONFIG_INFOA Info)
5022 {
5023     SC_RPC_CONFIG_INFOW InfoW = { 0 };
5024     DWORD dwRet, dwLength;
5025     PVOID ptr = NULL;
5026 
5027     DPRINT("RChangeServiceConfig2A() called\n");
5028     DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
5029 
5030     if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
5031         (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
5032     {
5033         return ERROR_INVALID_LEVEL;
5034     }
5035 
5036     InfoW.dwInfoLevel = Info.dwInfoLevel;
5037 
5038     if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5039     {
5040         LPSERVICE_DESCRIPTIONW lpServiceDescriptionW;
5041         LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
5042 
5043         lpServiceDescriptionA = Info.psd;
5044 
5045         if (lpServiceDescriptionA &&
5046             lpServiceDescriptionA->lpDescription)
5047         {
5048             dwLength = (DWORD)((strlen(lpServiceDescriptionA->lpDescription) + 1) * sizeof(WCHAR));
5049 
5050             lpServiceDescriptionW = HeapAlloc(GetProcessHeap(),
5051                                               HEAP_ZERO_MEMORY,
5052                                               dwLength + sizeof(SERVICE_DESCRIPTIONW));
5053             if (!lpServiceDescriptionW)
5054             {
5055                 return ERROR_NOT_ENOUGH_MEMORY;
5056             }
5057 
5058             lpServiceDescriptionW->lpDescription = (LPWSTR)(lpServiceDescriptionW + 1);
5059 
5060             MultiByteToWideChar(CP_ACP,
5061                                 0,
5062                                 lpServiceDescriptionA->lpDescription,
5063                                 -1,
5064                                 lpServiceDescriptionW->lpDescription,
5065                                 dwLength);
5066 
5067             ptr = lpServiceDescriptionW;
5068             InfoW.psd = lpServiceDescriptionW;
5069         }
5070     }
5071     else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5072     {
5073         LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
5074         LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
5075         DWORD dwRebootLen  = 0;
5076         DWORD dwCommandLen = 0;
5077         DWORD dwActionArrayLen = 0;
5078         LPWSTR lpStr = NULL;
5079 
5080         lpServiceFailureActionsA = Info.psfa;
5081 
5082         if (lpServiceFailureActionsA)
5083         {
5084             /*
5085              * The following code is inspired by the
5086              * SERVICE_CONFIG_FAILURE_ACTIONS case of
5087              * the RQueryServiceConfig2W function.
5088              */
5089 
5090             /* Retrieve the needed length for the two data strings */
5091             if (lpServiceFailureActionsA->lpRebootMsg)
5092             {
5093                 dwRebootLen = (DWORD)((strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR));
5094             }
5095             if (lpServiceFailureActionsA->lpCommand)
5096             {
5097                 dwCommandLen = (DWORD)((strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR));
5098             }
5099 
5100             /*
5101              * Retrieve the size of the lpsaActions array if needed.
5102              * We will copy the lpsaActions array only if there is at
5103              * least one action AND that the original array is valid.
5104              */
5105             if (lpServiceFailureActionsA->cActions > 0 && lpServiceFailureActionsA->lpsaActions)
5106             {
5107                 dwActionArrayLen = lpServiceFailureActionsA->cActions * sizeof(SC_ACTION);
5108             }
5109 
5110             /* Compute the total length for the UNICODE structure, including data */
5111             dwLength = sizeof(SERVICE_FAILURE_ACTIONSW) +
5112                        dwActionArrayLen + dwRebootLen + dwCommandLen;
5113 
5114             /* Allocate the structure */
5115             lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
5116                                                  HEAP_ZERO_MEMORY,
5117                                                  dwLength);
5118             if (!lpServiceFailureActionsW)
5119             {
5120                 return ERROR_NOT_ENOUGH_MEMORY;
5121             }
5122 
5123             /* Copy the members */
5124             lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
5125             lpServiceFailureActionsW->cActions      = lpServiceFailureActionsA->cActions;
5126 
5127             /* Copy the lpsaActions array if needed */
5128             if (dwActionArrayLen > 0)
5129             {
5130                 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
5131                 lpServiceFailureActionsW->lpsaActions = (LPSC_ACTION)((ULONG_PTR)(lpServiceFailureActionsW + 1));
5132 
5133                 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
5134                 RtlCopyMemory(lpServiceFailureActionsW->lpsaActions,
5135                               lpServiceFailureActionsA->lpsaActions,
5136                               dwActionArrayLen);
5137             }
5138             else
5139             {
5140                 /* No lpsaActions array */
5141                 lpServiceFailureActionsW->lpsaActions = NULL;
5142             }
5143             /* The data strings are stored just after the lpsaActions array */
5144             lpStr = (LPWSTR)((ULONG_PTR)(lpServiceFailureActionsW + 1) + dwActionArrayLen);
5145 
5146             /*
5147              * Convert the data strings to UNICODE
5148              */
5149 
5150             lpServiceFailureActionsW->lpRebootMsg = NULL;
5151             lpServiceFailureActionsW->lpCommand   = NULL;
5152 
5153             if (dwRebootLen)
5154             {
5155                 /* lpRebootMsg points just after the lpsaActions array */
5156                 lpServiceFailureActionsW->lpRebootMsg = lpStr;
5157 
5158                 MultiByteToWideChar(CP_ACP,
5159                                     0,
5160                                     lpServiceFailureActionsA->lpRebootMsg,
5161                                     -1,
5162                                     lpServiceFailureActionsW->lpRebootMsg,
5163                                     dwRebootLen);
5164 
5165                 lpStr += dwRebootLen / sizeof(WCHAR);
5166             }
5167 
5168             if (dwCommandLen)
5169             {
5170                 /* lpRebootMsg points just after the lpRebootMsg data string */
5171                 lpServiceFailureActionsW->lpCommand = lpStr;
5172 
5173                 MultiByteToWideChar(CP_ACP,
5174                                     0,
5175                                     lpServiceFailureActionsA->lpCommand,
5176                                     -1,
5177                                     lpServiceFailureActionsW->lpCommand,
5178                                     dwCommandLen);
5179             }
5180 
5181             /* Set the pointers */
5182             ptr = lpServiceFailureActionsW;
5183             InfoW.psfa = lpServiceFailureActionsW;
5184         }
5185     }
5186 
5187     dwRet = RChangeServiceConfig2W(hService, InfoW);
5188 
5189     HeapFree(GetProcessHeap(), 0, ptr);
5190 
5191     return dwRet;
5192 }
5193 
5194 
5195 static DWORD
5196 ScmSetFailureActions(HKEY hServiceKey,
5197                      LPSERVICE_FAILURE_ACTIONSW lpFailureActions)
5198 {
5199     LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL;
5200     LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL;
5201     DWORD dwRequiredSize = 0;
5202     DWORD dwType = 0;
5203     DWORD dwError;
5204 
5205     /* There is nothing to be done if we have no failure actions */
5206     if (lpFailureActions == NULL)
5207         return ERROR_SUCCESS;
5208 
5209     /*
5210      * 1- Retrieve the original value of FailureActions.
5211      */
5212 
5213     /* Query value length */
5214     dwError = RegQueryValueExW(hServiceKey,
5215                                L"FailureActions",
5216                                NULL,
5217                                &dwType,
5218                                NULL,
5219                                &dwRequiredSize);
5220     if (dwError != ERROR_SUCCESS &&
5221         dwError != ERROR_MORE_DATA &&
5222         dwError != ERROR_FILE_NOT_FOUND)
5223     {
5224         return dwError;
5225     }
5226 
5227     dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
5228                                             : sizeof(SERVICE_FAILURE_ACTIONSW);
5229 
5230     /* Initialize the read buffer */
5231     lpReadBuffer = HeapAlloc(GetProcessHeap(),
5232                              HEAP_ZERO_MEMORY,
5233                              dwRequiredSize);
5234     if (lpReadBuffer == NULL)
5235         return ERROR_NOT_ENOUGH_MEMORY;
5236 
5237     /* Now we can fill the read buffer */
5238     if (dwError != ERROR_FILE_NOT_FOUND &&
5239         dwType == REG_BINARY)
5240     {
5241         dwError = RegQueryValueExW(hServiceKey,
5242                                    L"FailureActions",
5243                                    NULL,
5244                                    NULL,
5245                                    (LPBYTE)lpReadBuffer,
5246                                    &dwRequiredSize);
5247         if (dwError != ERROR_SUCCESS &&
5248             dwError != ERROR_FILE_NOT_FOUND)
5249             goto done;
5250 
5251         if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
5252             dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5253     }
5254     else
5255     {
5256         /*
5257          * The value of the error doesn't really matter, the only
5258          * important thing is that it must be != ERROR_SUCCESS.
5259          */
5260         dwError = ERROR_INVALID_DATA;
5261     }
5262 
5263     if (dwError == ERROR_SUCCESS)
5264     {
5265         lpReadBuffer->cActions = min(lpReadBuffer->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
5266         lpReadBuffer->lpsaActions = (lpReadBuffer->cActions > 0 ? (LPSC_ACTION)(lpReadBuffer + 1) : NULL);
5267     }
5268     else
5269     {
5270         lpReadBuffer->dwResetPeriod = 0;
5271         lpReadBuffer->cActions = 0;
5272         lpReadBuffer->lpsaActions = NULL;
5273     }
5274 
5275     lpReadBuffer->lpRebootMsg = NULL;
5276     lpReadBuffer->lpCommand = NULL;
5277 
5278     /*
5279      * 2- Initialize the new value to set.
5280      */
5281 
5282     dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5283 
5284     if (lpFailureActions->lpsaActions == NULL)
5285     {
5286         /*
5287          * lpFailureActions->cActions is ignored.
5288          * Therefore we use the original values
5289          * of cActions and lpsaActions.
5290          */
5291         dwRequiredSize += lpReadBuffer->cActions * sizeof(SC_ACTION);
5292     }
5293     else
5294     {
5295         /*
5296          * The reset period and array of failure actions
5297          * are deleted if lpFailureActions->cActions == 0 .
5298          */
5299         dwRequiredSize += lpFailureActions->cActions * sizeof(SC_ACTION);
5300     }
5301 
5302     lpWriteBuffer = HeapAlloc(GetProcessHeap(),
5303                               HEAP_ZERO_MEMORY,
5304                               dwRequiredSize);
5305     if (lpWriteBuffer == NULL)
5306     {
5307         dwError = ERROR_NOT_ENOUGH_MEMORY;
5308         goto done;
5309     }
5310 
5311     /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5312     lpWriteBuffer->lpRebootMsg = NULL;
5313     lpWriteBuffer->lpCommand = NULL;
5314     lpWriteBuffer->lpsaActions = NULL;
5315 
5316     /* Set the members */
5317     if (lpFailureActions->lpsaActions == NULL)
5318     {
5319         /*
5320          * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5321          * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5322          */
5323         lpWriteBuffer->dwResetPeriod = lpReadBuffer->dwResetPeriod;
5324         lpWriteBuffer->cActions = lpReadBuffer->cActions;
5325 
5326         if (lpReadBuffer->lpsaActions != NULL)
5327         {
5328             memmove(lpWriteBuffer + 1,
5329                     lpReadBuffer->lpsaActions,
5330                     lpReadBuffer->cActions * sizeof(SC_ACTION));
5331         }
5332     }
5333     else
5334     {
5335         if (lpFailureActions->cActions > 0)
5336         {
5337             lpWriteBuffer->dwResetPeriod = lpFailureActions->dwResetPeriod;
5338             lpWriteBuffer->cActions = lpFailureActions->cActions;
5339 
5340             memmove(lpWriteBuffer + 1,
5341                     lpFailureActions->lpsaActions,
5342                     lpFailureActions->cActions * sizeof(SC_ACTION));
5343         }
5344         else
5345         {
5346             /* The reset period and array of failure actions are deleted */
5347             lpWriteBuffer->dwResetPeriod = 0;
5348             lpWriteBuffer->cActions = 0;
5349         }
5350     }
5351 
5352     /* Save the new failure actions into the registry */
5353     dwError = RegSetValueExW(hServiceKey,
5354                              L"FailureActions",
5355                              0,
5356                              REG_BINARY,
5357                              (LPBYTE)lpWriteBuffer,
5358                              dwRequiredSize);
5359 
5360     /* We modify the strings only in case of success.*/
5361     if (dwError == ERROR_SUCCESS)
5362     {
5363         /* Modify the Reboot Message value, if specified */
5364         if (lpFailureActions->lpRebootMsg != NULL)
5365         {
5366             /* If the Reboot Message is "" then we delete it */
5367             if (*lpFailureActions->lpRebootMsg == 0)
5368             {
5369                 DPRINT("Delete Reboot Message value\n");
5370                 RegDeleteValueW(hServiceKey, L"RebootMessage");
5371             }
5372             else
5373             {
5374                 DPRINT("Setting Reboot Message value %S\n", lpFailureActions->lpRebootMsg);
5375                 RegSetValueExW(hServiceKey,
5376                                L"RebootMessage",
5377                                0,
5378                                REG_SZ,
5379                                (LPBYTE)lpFailureActions->lpRebootMsg,
5380                                (DWORD)((wcslen(lpFailureActions->lpRebootMsg) + 1) * sizeof(WCHAR)));
5381             }
5382         }
5383 
5384         /* Modify the Failure Command value, if specified */
5385         if (lpFailureActions->lpCommand != NULL)
5386         {
5387             /* If the FailureCommand string is an empty string, delete the value */
5388             if (*lpFailureActions->lpCommand == 0)
5389             {
5390                 DPRINT("Delete Failure Command value\n");
5391                 RegDeleteValueW(hServiceKey, L"FailureCommand");
5392             }
5393             else
5394             {
5395                 DPRINT("Setting Failure Command value %S\n", lpFailureActions->lpCommand);
5396                 RegSetValueExW(hServiceKey,
5397                                L"FailureCommand",
5398                                0,
5399                                REG_SZ,
5400                                (LPBYTE)lpFailureActions->lpCommand,
5401                                (DWORD)((wcslen(lpFailureActions->lpCommand) + 1) * sizeof(WCHAR)));
5402             }
5403         }
5404     }
5405 
5406 done:
5407     if (lpWriteBuffer != NULL)
5408         HeapFree(GetProcessHeap(), 0, lpWriteBuffer);
5409 
5410     if (lpReadBuffer != NULL)
5411         HeapFree(GetProcessHeap(), 0, lpReadBuffer);
5412 
5413     return dwError;
5414 }
5415 
5416 
5417 /* Function 37 */
5418 DWORD
5419 WINAPI
5420 RChangeServiceConfig2W(
5421     SC_RPC_HANDLE hService,
5422     SC_RPC_CONFIG_INFOW Info)
5423 {
5424     DWORD dwError = ERROR_SUCCESS;
5425     PSERVICE_HANDLE hSvc;
5426     PSERVICE lpService = NULL;
5427     HKEY hServiceKey = NULL;
5428     ACCESS_MASK RequiredAccess = SERVICE_CHANGE_CONFIG;
5429 
5430     DPRINT("RChangeServiceConfig2W() called\n");
5431     DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
5432 
5433     if (ScmShutdown)
5434         return ERROR_SHUTDOWN_IN_PROGRESS;
5435 
5436     if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
5437         (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
5438     {
5439         return ERROR_INVALID_LEVEL;
5440     }
5441 
5442     hSvc = ScmGetServiceFromHandle(hService);
5443     if (hSvc == NULL)
5444     {
5445         DPRINT("Invalid service handle!\n");
5446         return ERROR_INVALID_HANDLE;
5447     }
5448 
5449     if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5450         RequiredAccess |= SERVICE_START;
5451 
5452     /* Check the access rights */
5453     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5454                                   RequiredAccess))
5455     {
5456         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5457         return ERROR_ACCESS_DENIED;
5458     }
5459 
5460     if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5461     {
5462         /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
5463 
5464     }
5465 
5466     lpService = hSvc->ServiceEntry;
5467     if (lpService == NULL)
5468     {
5469         DPRINT("lpService == NULL!\n");
5470         return ERROR_INVALID_HANDLE;
5471     }
5472 
5473     /* Failure actions can only be set for Win32 services, not for drivers */
5474     if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5475     {
5476         if (lpService->Status.dwServiceType & SERVICE_DRIVER)
5477             return ERROR_CANNOT_DETECT_DRIVER_FAILURE;
5478     }
5479 
5480     /* Lock the service database exclusively */
5481     ScmLockDatabaseExclusive();
5482 
5483     if (lpService->bDeleted)
5484     {
5485         DPRINT("The service has already been marked for delete!\n");
5486         dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
5487         goto done;
5488     }
5489 
5490     /* Open the service key */
5491     dwError = ScmOpenServiceKey(lpService->szServiceName,
5492                                 KEY_READ | KEY_SET_VALUE,
5493                                 &hServiceKey);
5494     if (dwError != ERROR_SUCCESS)
5495         goto done;
5496 
5497     if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5498     {
5499         LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
5500 
5501         /* Modify the service description, if specified */
5502         if (lpServiceDescription != NULL &&
5503             lpServiceDescription->lpDescription != NULL)
5504         {
5505             /* If the description is "" then we delete it */
5506             if (*lpServiceDescription->lpDescription == 0)
5507             {
5508                 DPRINT("Delete service description\n");
5509                 dwError = RegDeleteValueW(hServiceKey, L"Description");
5510 
5511                 if (dwError == ERROR_FILE_NOT_FOUND)
5512                     dwError = ERROR_SUCCESS;
5513             }
5514             else
5515             {
5516                 DPRINT("Setting service description value %S\n", lpServiceDescription->lpDescription);
5517                 dwError = RegSetValueExW(hServiceKey,
5518                                          L"Description",
5519                                          0,
5520                                          REG_SZ,
5521                                          (LPBYTE)lpServiceDescription->lpDescription,
5522                                          (DWORD)((wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR)));
5523             }
5524         }
5525         else
5526         {
5527             dwError = ERROR_SUCCESS;
5528         }
5529     }
5530     else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5531     {
5532         dwError = ScmSetFailureActions(hServiceKey,
5533                                        (LPSERVICE_FAILURE_ACTIONSW)Info.psfa);
5534     }
5535 
5536 done:
5537     if (hServiceKey != NULL)
5538         RegCloseKey(hServiceKey);
5539 
5540     /* Unlock the service database */
5541     ScmUnlockDatabase();
5542 
5543     DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
5544 
5545     return dwError;
5546 }
5547 
5548 
5549 /* Function 38 */
5550 DWORD
5551 WINAPI
5552 RQueryServiceConfig2A(
5553     SC_RPC_HANDLE hService,
5554     DWORD dwInfoLevel,
5555     LPBYTE lpBuffer,
5556     DWORD cbBufSize,
5557     LPBOUNDED_DWORD_8K pcbBytesNeeded)
5558 {
5559     DWORD dwError = ERROR_SUCCESS;
5560     PSERVICE_HANDLE hSvc;
5561     PSERVICE lpService = NULL;
5562     HKEY hServiceKey = NULL;
5563     DWORD dwRequiredSize = 0;
5564     DWORD dwType = 0;
5565     LPWSTR lpDescriptionW = NULL;
5566     LPWSTR lpRebootMessageW = NULL;
5567     LPWSTR lpFailureCommandW = NULL;
5568 
5569     DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5570            hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
5571 
5572     if (!lpBuffer)
5573         return ERROR_INVALID_ADDRESS;
5574 
5575     if (ScmShutdown)
5576         return ERROR_SHUTDOWN_IN_PROGRESS;
5577 
5578     if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
5579         (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
5580     {
5581         return ERROR_INVALID_LEVEL;
5582     }
5583 
5584     hSvc = ScmGetServiceFromHandle(hService);
5585     if (hSvc == NULL)
5586     {
5587         DPRINT1("Invalid service handle!\n");
5588         return ERROR_INVALID_HANDLE;
5589     }
5590 
5591     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5592                                   SERVICE_QUERY_CONFIG))
5593     {
5594         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5595         return ERROR_ACCESS_DENIED;
5596     }
5597 
5598     lpService = hSvc->ServiceEntry;
5599     if (lpService == NULL)
5600     {
5601         DPRINT("lpService == NULL!\n");
5602         return ERROR_INVALID_HANDLE;
5603     }
5604 
5605     /* Lock the service database shared */
5606     ScmLockDatabaseShared();
5607 
5608     dwError = ScmOpenServiceKey(lpService->lpServiceName,
5609                                 KEY_READ,
5610                                 &hServiceKey);
5611     if (dwError != ERROR_SUCCESS)
5612         goto done;
5613 
5614     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5615     {
5616         LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
5617         LPSTR lpStr;
5618 
5619         dwError = ScmReadString(hServiceKey,
5620                                 L"Description",
5621                                 &lpDescriptionW);
5622         if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5623             goto done;
5624 
5625         *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
5626         if (dwError == ERROR_SUCCESS)
5627             *pcbBytesNeeded += (DWORD)((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
5628 
5629         if (cbBufSize < *pcbBytesNeeded)
5630         {
5631             dwError = ERROR_INSUFFICIENT_BUFFER;
5632             goto done;
5633         }
5634 
5635         if (dwError == ERROR_SUCCESS)
5636         {
5637             lpStr = (LPSTR)(lpServiceDescription + 1);
5638 
5639             WideCharToMultiByte(CP_ACP,
5640                                 0,
5641                                 lpDescriptionW,
5642                                 -1,
5643                                 lpStr,
5644                                 (int)wcslen(lpDescriptionW),
5645                                 NULL,
5646                                 NULL);
5647             lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
5648         }
5649         else
5650         {
5651             lpServiceDescription->lpDescription = NULL;
5652             dwError = ERROR_SUCCESS;
5653         }
5654     }
5655     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5656     {
5657         LPSERVICE_FAILURE_ACTIONSA lpFailureActions = (LPSERVICE_FAILURE_ACTIONSA)lpBuffer;
5658         LPSTR lpStr = NULL;
5659 
5660         /* Query value length */
5661         dwError = RegQueryValueExW(hServiceKey,
5662                                    L"FailureActions",
5663                                    NULL,
5664                                    &dwType,
5665                                    NULL,
5666                                    &dwRequiredSize);
5667         if (dwError != ERROR_SUCCESS &&
5668             dwError != ERROR_MORE_DATA &&
5669             dwError != ERROR_FILE_NOT_FOUND)
5670         {
5671             goto done;
5672         }
5673 
5674         dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSA), dwRequiredSize)
5675                                                 : sizeof(SERVICE_FAILURE_ACTIONSA);
5676 
5677         /* Get the strings */
5678         ScmReadString(hServiceKey,
5679                       L"FailureCommand",
5680                       &lpFailureCommandW);
5681 
5682         ScmReadString(hServiceKey,
5683                       L"RebootMessage",
5684                       &lpRebootMessageW);
5685 
5686         if (lpRebootMessageW)
5687             dwRequiredSize += (DWORD)((wcslen(lpRebootMessageW) + 1) * sizeof(WCHAR));
5688 
5689         if (lpFailureCommandW)
5690             dwRequiredSize += (DWORD)((wcslen(lpFailureCommandW) + 1) * sizeof(WCHAR));
5691 
5692         if (cbBufSize < dwRequiredSize)
5693         {
5694             *pcbBytesNeeded = dwRequiredSize;
5695             dwError = ERROR_INSUFFICIENT_BUFFER;
5696             goto done;
5697         }
5698 
5699         /* Now we can fill the buffer */
5700         if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
5701         {
5702             dwError = RegQueryValueExW(hServiceKey,
5703                                        L"FailureActions",
5704                                        NULL,
5705                                        NULL,
5706                                        (LPBYTE)lpFailureActions,
5707                                        &dwRequiredSize);
5708             if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5709                 goto done;
5710 
5711             if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSA))
5712                 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSA);
5713         }
5714         else
5715         {
5716             /*
5717              * The value of the error doesn't really matter, the only
5718              * important thing is that it must be != ERROR_SUCCESS .
5719              */
5720             dwError = ERROR_INVALID_DATA;
5721         }
5722 
5723         if (dwError == ERROR_SUCCESS)
5724         {
5725             lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSA)) / sizeof(SC_ACTION));
5726 
5727             /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5728             lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSA) : NULL);
5729 
5730             lpStr = (LPSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
5731         }
5732         else
5733         {
5734             lpFailureActions->dwResetPeriod = 0;
5735             lpFailureActions->cActions = 0;
5736             lpFailureActions->lpsaActions = NULL;
5737             lpStr = (LPSTR)(lpFailureActions + 1);
5738         }
5739 
5740         lpFailureActions->lpRebootMsg = NULL;
5741         lpFailureActions->lpCommand = NULL;
5742 
5743         if (lpRebootMessageW)
5744         {
5745             WideCharToMultiByte(CP_ACP,
5746                                 0,
5747                                 lpRebootMessageW,
5748                                 -1,
5749                                 lpStr,
5750                                 (int)wcslen(lpRebootMessageW),
5751                                 NULL,
5752                                 NULL);
5753             lpFailureActions->lpRebootMsg = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5754             lpStr += strlen(lpStr) + 1;
5755         }
5756 
5757         if (lpFailureCommandW)
5758         {
5759             WideCharToMultiByte(CP_ACP,
5760                                 0,
5761                                 lpFailureCommandW,
5762                                 -1,
5763                                 lpStr,
5764                                 (int)wcslen(lpFailureCommandW),
5765                                 NULL,
5766                                 NULL);
5767             lpFailureActions->lpCommand = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5768             /* lpStr += strlen(lpStr) + 1; */
5769         }
5770 
5771         dwError = ERROR_SUCCESS;
5772     }
5773 
5774 done:
5775     /* Unlock the service database */
5776     ScmUnlockDatabase();
5777 
5778     if (lpDescriptionW != NULL)
5779         HeapFree(GetProcessHeap(), 0, lpDescriptionW);
5780 
5781     if (lpRebootMessageW != NULL)
5782         HeapFree(GetProcessHeap(), 0, lpRebootMessageW);
5783 
5784     if (lpFailureCommandW != NULL)
5785         HeapFree(GetProcessHeap(), 0, lpFailureCommandW);
5786 
5787     if (hServiceKey != NULL)
5788         RegCloseKey(hServiceKey);
5789 
5790     DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError);
5791 
5792     return dwError;
5793 }
5794 
5795 
5796 /* Function 39 */
5797 DWORD
5798 WINAPI
5799 RQueryServiceConfig2W(
5800     SC_RPC_HANDLE hService,
5801     DWORD dwInfoLevel,
5802     LPBYTE lpBuffer,
5803     DWORD cbBufSize,
5804     LPBOUNDED_DWORD_8K pcbBytesNeeded)
5805 {
5806     DWORD dwError = ERROR_SUCCESS;
5807     PSERVICE_HANDLE hSvc;
5808     PSERVICE lpService = NULL;
5809     HKEY hServiceKey = NULL;
5810     DWORD dwRequiredSize = 0;
5811     DWORD dwType = 0;
5812     LPWSTR lpDescription = NULL;
5813     LPWSTR lpRebootMessage = NULL;
5814     LPWSTR lpFailureCommand = NULL;
5815 
5816     DPRINT("RQueryServiceConfig2W() called\n");
5817 
5818     if (!lpBuffer)
5819         return ERROR_INVALID_ADDRESS;
5820 
5821     if (ScmShutdown)
5822         return ERROR_SHUTDOWN_IN_PROGRESS;
5823 
5824     if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
5825         (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
5826     {
5827         return ERROR_INVALID_LEVEL;
5828     }
5829 
5830     hSvc = ScmGetServiceFromHandle(hService);
5831     if (hSvc == NULL)
5832     {
5833         DPRINT1("Invalid service handle!\n");
5834         return ERROR_INVALID_HANDLE;
5835     }
5836 
5837     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5838                                   SERVICE_QUERY_CONFIG))
5839     {
5840         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5841         return ERROR_ACCESS_DENIED;
5842     }
5843 
5844     lpService = hSvc->ServiceEntry;
5845     if (lpService == NULL)
5846     {
5847         DPRINT("lpService == NULL!\n");
5848         return ERROR_INVALID_HANDLE;
5849     }
5850 
5851     /* Lock the service database shared */
5852     ScmLockDatabaseShared();
5853 
5854     dwError = ScmOpenServiceKey(lpService->lpServiceName,
5855                                 KEY_READ,
5856                                 &hServiceKey);
5857     if (dwError != ERROR_SUCCESS)
5858         goto done;
5859 
5860     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5861     {
5862         LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
5863         LPWSTR lpStr;
5864 
5865         dwError = ScmReadString(hServiceKey,
5866                                 L"Description",
5867                                 &lpDescription);
5868         if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5869             goto done;
5870 
5871         *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
5872         if (dwError == ERROR_SUCCESS)
5873             *pcbBytesNeeded += (DWORD)((wcslen(lpDescription) + 1) * sizeof(WCHAR));
5874 
5875         if (cbBufSize < *pcbBytesNeeded)
5876         {
5877             dwError = ERROR_INSUFFICIENT_BUFFER;
5878             goto done;
5879         }
5880 
5881         if (dwError == ERROR_SUCCESS)
5882         {
5883             lpStr = (LPWSTR)(lpServiceDescription + 1);
5884             wcscpy(lpStr, lpDescription);
5885             lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
5886         }
5887         else
5888         {
5889             lpServiceDescription->lpDescription = NULL;
5890             dwError = ERROR_SUCCESS;
5891         }
5892     }
5893     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5894     {
5895         LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
5896         LPWSTR lpStr = NULL;
5897 
5898         /* Query value length */
5899         dwError = RegQueryValueExW(hServiceKey,
5900                                    L"FailureActions",
5901                                    NULL,
5902                                    &dwType,
5903                                    NULL,
5904                                    &dwRequiredSize);
5905         if (dwError != ERROR_SUCCESS &&
5906             dwError != ERROR_MORE_DATA &&
5907             dwError != ERROR_FILE_NOT_FOUND)
5908         {
5909             goto done;
5910         }
5911 
5912         dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
5913                                                 : sizeof(SERVICE_FAILURE_ACTIONSW);
5914 
5915         /* Get the strings */
5916         ScmReadString(hServiceKey,
5917                       L"FailureCommand",
5918                       &lpFailureCommand);
5919 
5920         ScmReadString(hServiceKey,
5921                       L"RebootMessage",
5922                       &lpRebootMessage);
5923 
5924         if (lpRebootMessage)
5925             dwRequiredSize += (DWORD)((wcslen(lpRebootMessage) + 1) * sizeof(WCHAR));
5926 
5927         if (lpFailureCommand)
5928             dwRequiredSize += (DWORD)((wcslen(lpFailureCommand) + 1) * sizeof(WCHAR));
5929 
5930         if (cbBufSize < dwRequiredSize)
5931         {
5932             *pcbBytesNeeded = dwRequiredSize;
5933             dwError = ERROR_INSUFFICIENT_BUFFER;
5934             goto done;
5935         }
5936 
5937         /* Now we can fill the buffer */
5938         if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
5939         {
5940             dwError = RegQueryValueExW(hServiceKey,
5941                                        L"FailureActions",
5942                                        NULL,
5943                                        NULL,
5944                                        (LPBYTE)lpFailureActions,
5945                                        &dwRequiredSize);
5946             if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5947                 goto done;
5948 
5949             if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
5950                 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5951         }
5952         else
5953         {
5954             /*
5955              * The value of the error doesn't really matter, the only
5956              * important thing is that it must be != ERROR_SUCCESS .
5957              */
5958             dwError = ERROR_INVALID_DATA;
5959         }
5960 
5961         if (dwError == ERROR_SUCCESS)
5962         {
5963             lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
5964 
5965             /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5966             lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSW) : NULL);
5967 
5968             lpStr = (LPWSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
5969         }
5970         else
5971         {
5972             lpFailureActions->dwResetPeriod = 0;
5973             lpFailureActions->cActions = 0;
5974             lpFailureActions->lpsaActions = NULL;
5975             lpStr = (LPWSTR)(lpFailureActions + 1);
5976         }
5977 
5978         lpFailureActions->lpRebootMsg = NULL;
5979         lpFailureActions->lpCommand   = NULL;
5980 
5981         if (lpRebootMessage)
5982         {
5983             wcscpy(lpStr, lpRebootMessage);
5984             lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5985             lpStr += wcslen(lpStr) + 1;
5986         }
5987 
5988         if (lpFailureCommand)
5989         {
5990             wcscpy(lpStr, lpFailureCommand);
5991             lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5992             /* lpStr += wcslen(lpStr) + 1; */
5993         }
5994 
5995         dwError = ERROR_SUCCESS;
5996     }
5997 
5998 done:
5999     /* Unlock the service database */
6000     ScmUnlockDatabase();
6001 
6002     if (lpDescription != NULL)
6003         HeapFree(GetProcessHeap(), 0, lpDescription);
6004 
6005     if (lpRebootMessage != NULL)
6006         HeapFree(GetProcessHeap(), 0, lpRebootMessage);
6007 
6008     if (lpFailureCommand != NULL)
6009         HeapFree(GetProcessHeap(), 0, lpFailureCommand);
6010 
6011     if (hServiceKey != NULL)
6012         RegCloseKey(hServiceKey);
6013 
6014     DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
6015 
6016     return dwError;
6017 }
6018 
6019 
6020 /* Function 40 */
6021 DWORD
6022 WINAPI
6023 RQueryServiceStatusEx(
6024     SC_RPC_HANDLE hService,
6025     SC_STATUS_TYPE InfoLevel,
6026     LPBYTE lpBuffer,
6027     DWORD cbBufSize,
6028     LPBOUNDED_DWORD_8K pcbBytesNeeded)
6029 {
6030     LPSERVICE_STATUS_PROCESS lpStatus;
6031     PSERVICE_HANDLE hSvc;
6032     PSERVICE lpService;
6033 
6034     DPRINT("RQueryServiceStatusEx() called\n");
6035 
6036     if (ScmShutdown)
6037         return ERROR_SHUTDOWN_IN_PROGRESS;
6038 
6039     if (InfoLevel != SC_STATUS_PROCESS_INFO)
6040         return ERROR_INVALID_LEVEL;
6041 
6042     *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
6043 
6044     if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
6045         return ERROR_INSUFFICIENT_BUFFER;
6046 
6047     hSvc = ScmGetServiceFromHandle(hService);
6048     if (hSvc == NULL)
6049     {
6050         DPRINT1("Invalid service handle!\n");
6051         return ERROR_INVALID_HANDLE;
6052     }
6053 
6054     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
6055                                   SERVICE_QUERY_STATUS))
6056     {
6057         DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
6058         return ERROR_ACCESS_DENIED;
6059     }
6060 
6061     lpService = hSvc->ServiceEntry;
6062     if (lpService == NULL)
6063     {
6064         DPRINT("lpService == NULL!\n");
6065         return ERROR_INVALID_HANDLE;
6066     }
6067 
6068     /* Lock the service database shared */
6069     ScmLockDatabaseShared();
6070 
6071     lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
6072 
6073     /* Return service status information */
6074     RtlCopyMemory(lpStatus,
6075                   &lpService->Status,
6076                   sizeof(SERVICE_STATUS));
6077 
6078     /* Copy the service process ID */
6079     if ((lpService->Status.dwCurrentState == SERVICE_STOPPED) || (lpService->lpImage == NULL))
6080         lpStatus->dwProcessId = 0;
6081     else
6082         lpStatus->dwProcessId = lpService->lpImage->dwProcessId;
6083 
6084     lpStatus->dwServiceFlags = 0;   /* FIXME */
6085 
6086     /* Unlock the service database */
6087     ScmUnlockDatabase();
6088 
6089     return ERROR_SUCCESS;
6090 }
6091 
6092 
6093 /* Function 41 */
6094 DWORD
6095 WINAPI
6096 REnumServicesStatusExA(
6097     SC_RPC_HANDLE hSCManager,
6098     SC_ENUM_TYPE InfoLevel,
6099     DWORD dwServiceType,
6100     DWORD dwServiceState,
6101     LPBYTE lpBuffer,
6102     DWORD cbBufSize,
6103     LPBOUNDED_DWORD_256K pcbBytesNeeded,
6104     LPBOUNDED_DWORD_256K lpServicesReturned,
6105     LPBOUNDED_DWORD_256K lpResumeIndex,
6106     LPCSTR pszGroupName)
6107 {
6108     LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
6109     LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW;
6110     LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
6111     LPWSTR lpStringPtrW;
6112     LPSTR lpStringPtrA;
6113     LPWSTR pszGroupNameW = NULL;
6114     DWORD dwError;
6115     DWORD dwServiceCount;
6116 
6117     DPRINT("REnumServicesStatusExA() called\n");
6118 
6119     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
6120     {
6121         return ERROR_INVALID_ADDRESS;
6122     }
6123 
6124     if (pszGroupName)
6125     {
6126         pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
6127         if (!pszGroupNameW)
6128         {
6129              DPRINT("Failed to allocate buffer!\n");
6130              dwError = ERROR_NOT_ENOUGH_MEMORY;
6131              goto Done;
6132         }
6133 
6134         MultiByteToWideChar(CP_ACP,
6135                             0,
6136                             pszGroupName,
6137                             -1,
6138                             pszGroupNameW,
6139                             (int)(strlen(pszGroupName) + 1));
6140     }
6141 
6142     if ((cbBufSize > 0) && (lpBuffer))
6143     {
6144         lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
6145         if (!lpStatusPtrW)
6146         {
6147             DPRINT("Failed to allocate buffer!\n");
6148             dwError = ERROR_NOT_ENOUGH_MEMORY;
6149             goto Done;
6150         }
6151     }
6152 
6153     dwError = REnumServicesStatusExW(hSCManager,
6154                                      InfoLevel,
6155                                      dwServiceType,
6156                                      dwServiceState,
6157                                      (LPBYTE)lpStatusPtrW,
6158                                      cbBufSize,
6159                                      pcbBytesNeeded,
6160                                      lpServicesReturned,
6161                                      lpResumeIndex,
6162                                      pszGroupNameW);
6163 
6164     /* if no services were returned then we are Done */
6165     if (*lpServicesReturned == 0)
6166         goto Done;
6167 
6168     lpStatusPtrIncrW = lpStatusPtrW;
6169     lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
6170     lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
6171                   *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
6172     lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
6173                   *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
6174 
6175     for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
6176     {
6177         /* Copy the service name */
6178         WideCharToMultiByte(CP_ACP,
6179                             0,
6180                             lpStringPtrW,
6181                             -1,
6182                             lpStringPtrA,
6183                             (int)wcslen(lpStringPtrW),
6184                             0,
6185                             0);
6186 
6187         lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
6188         lpStringPtrA += wcslen(lpStringPtrW) + 1;
6189         lpStringPtrW += wcslen(lpStringPtrW) + 1;
6190 
6191         /* Copy the display name */
6192         WideCharToMultiByte(CP_ACP,
6193                             0,
6194                             lpStringPtrW,
6195                             -1,
6196                             lpStringPtrA,
6197                             (int)wcslen(lpStringPtrW),
6198                             0,
6199                             0);
6200 
6201         lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
6202         lpStringPtrA += wcslen(lpStringPtrW) + 1;
6203         lpStringPtrW += wcslen(lpStringPtrW) + 1;
6204 
6205         /* Copy the status information */
6206         memcpy(&lpStatusPtrA->ServiceStatusProcess,
6207                &lpStatusPtrIncrW->ServiceStatusProcess,
6208                sizeof(SERVICE_STATUS));
6209 
6210         /* Copy the service process ID */
6211         lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrIncrW->ServiceStatusProcess.dwProcessId;
6212 
6213         lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
6214 
6215         lpStatusPtrIncrW++;
6216         lpStatusPtrA++;
6217     }
6218 
6219 Done:
6220     if (pszGroupNameW)
6221         HeapFree(GetProcessHeap(), 0, pszGroupNameW);
6222 
6223     if (lpStatusPtrW)
6224         HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
6225 
6226     DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
6227 
6228     return dwError;
6229 }
6230 
6231 
6232 /* Function 42 */
6233 DWORD
6234 WINAPI
6235 REnumServicesStatusExW(
6236     SC_RPC_HANDLE hSCManager,
6237     SC_ENUM_TYPE InfoLevel,
6238     DWORD dwServiceType,
6239     DWORD dwServiceState,
6240     LPBYTE lpBuffer,
6241     DWORD cbBufSize,
6242     LPBOUNDED_DWORD_256K pcbBytesNeeded,
6243     LPBOUNDED_DWORD_256K lpServicesReturned,
6244     LPBOUNDED_DWORD_256K lpResumeIndex,
6245     LPCWSTR pszGroupName)
6246 {
6247     PMANAGER_HANDLE hManager;
6248     PSERVICE lpService;
6249     DWORD dwError = ERROR_SUCCESS;
6250     PLIST_ENTRY ServiceEntry;
6251     PSERVICE CurrentService;
6252     DWORD dwState;
6253     DWORD dwRequiredSize;
6254     DWORD dwServiceCount;
6255     DWORD dwSize;
6256     DWORD dwLastResumeCount = 0;
6257     LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
6258     LPWSTR lpStringPtr;
6259 
6260     DPRINT("REnumServicesStatusExW() called\n");
6261 
6262     if (ScmShutdown)
6263         return ERROR_SHUTDOWN_IN_PROGRESS;
6264 
6265     if (InfoLevel != SC_ENUM_PROCESS_INFO)
6266         return ERROR_INVALID_LEVEL;
6267 
6268     hManager = ScmGetServiceManagerFromHandle(hSCManager);
6269     if (hManager == NULL)
6270     {
6271         DPRINT1("Invalid service manager handle!\n");
6272         return ERROR_INVALID_HANDLE;
6273     }
6274 
6275     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
6276     {
6277         return ERROR_INVALID_ADDRESS;
6278     }
6279 
6280     *pcbBytesNeeded = 0;
6281     *lpServicesReturned = 0;
6282 
6283     if ((dwServiceType == 0) ||
6284         ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
6285     {
6286         DPRINT("Not a valid Service Type!\n");
6287         return ERROR_INVALID_PARAMETER;
6288     }
6289 
6290     if ((dwServiceState == 0) ||
6291         ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
6292     {
6293         DPRINT("Not a valid Service State!\n");
6294         return ERROR_INVALID_PARAMETER;
6295     }
6296 
6297     /* Check access rights */
6298     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
6299                                   SC_MANAGER_ENUMERATE_SERVICE))
6300     {
6301         DPRINT("Insufficient access rights! 0x%lx\n",
6302                hManager->Handle.DesiredAccess);
6303         return ERROR_ACCESS_DENIED;
6304     }
6305 
6306     if (lpResumeIndex)
6307         dwLastResumeCount = *lpResumeIndex;
6308 
6309     /* Lock the service database shared */
6310     ScmLockDatabaseShared();
6311 
6312     lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
6313     if (lpService == NULL)
6314     {
6315         dwError = ERROR_SUCCESS;
6316         goto Done;
6317     }
6318 
6319     dwRequiredSize = 0;
6320     dwServiceCount = 0;
6321 
6322     for (ServiceEntry = &lpService->ServiceListEntry;
6323          ServiceEntry != &ServiceListHead;
6324          ServiceEntry = ServiceEntry->Flink)
6325     {
6326         CurrentService = CONTAINING_RECORD(ServiceEntry,
6327                                            SERVICE,
6328                                            ServiceListEntry);
6329 
6330         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6331             continue;
6332 
6333         dwState = SERVICE_ACTIVE;
6334         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6335             dwState = SERVICE_INACTIVE;
6336 
6337         if ((dwState & dwServiceState) == 0)
6338             continue;
6339 
6340         if (pszGroupName)
6341         {
6342             if (*pszGroupName == 0)
6343             {
6344                 if (CurrentService->lpGroup != NULL)
6345                     continue;
6346             }
6347             else
6348             {
6349                 if ((CurrentService->lpGroup == NULL) ||
6350                     _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6351                     continue;
6352             }
6353         }
6354 
6355         dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6356                  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6357                  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
6358 
6359         if (dwRequiredSize + dwSize <= cbBufSize)
6360         {
6361             DPRINT("Service name: %S  fit\n", CurrentService->lpServiceName);
6362             dwRequiredSize += dwSize;
6363             dwServiceCount++;
6364             dwLastResumeCount = CurrentService->dwResumeCount;
6365         }
6366         else
6367         {
6368             DPRINT("Service name: %S  no fit\n", CurrentService->lpServiceName);
6369             break;
6370         }
6371 
6372     }
6373 
6374     DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
6375     DPRINT("dwServiceCount: %lu\n", dwServiceCount);
6376 
6377     for (;
6378          ServiceEntry != &ServiceListHead;
6379          ServiceEntry = ServiceEntry->Flink)
6380     {
6381         CurrentService = CONTAINING_RECORD(ServiceEntry,
6382                                            SERVICE,
6383                                            ServiceListEntry);
6384 
6385         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6386             continue;
6387 
6388         dwState = SERVICE_ACTIVE;
6389         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6390             dwState = SERVICE_INACTIVE;
6391 
6392         if ((dwState & dwServiceState) == 0)
6393             continue;
6394 
6395         if (pszGroupName)
6396         {
6397             if (*pszGroupName == 0)
6398             {
6399                 if (CurrentService->lpGroup != NULL)
6400                     continue;
6401             }
6402             else
6403             {
6404                 if ((CurrentService->lpGroup == NULL) ||
6405                     _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6406                     continue;
6407             }
6408         }
6409 
6410         dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6411                            (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6412                            (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
6413 
6414         dwError = ERROR_MORE_DATA;
6415     }
6416 
6417     DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
6418 
6419     if (lpResumeIndex)
6420         *lpResumeIndex = dwLastResumeCount;
6421 
6422     *lpServicesReturned = dwServiceCount;
6423     *pcbBytesNeeded = dwRequiredSize;
6424 
6425     /* If there was no services that matched */
6426     if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
6427     {
6428         dwError = ERROR_SERVICE_DOES_NOT_EXIST;
6429         goto Done;
6430     }
6431 
6432     lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
6433     lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
6434                            dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
6435 
6436     dwRequiredSize = 0;
6437     for (ServiceEntry = &lpService->ServiceListEntry;
6438          ServiceEntry != &ServiceListHead;
6439          ServiceEntry = ServiceEntry->Flink)
6440     {
6441         CurrentService = CONTAINING_RECORD(ServiceEntry,
6442                                            SERVICE,
6443                                            ServiceListEntry);
6444 
6445         if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6446             continue;
6447 
6448         dwState = SERVICE_ACTIVE;
6449         if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6450             dwState = SERVICE_INACTIVE;
6451 
6452         if ((dwState & dwServiceState) == 0)
6453             continue;
6454 
6455         if (pszGroupName)
6456         {
6457             if (*pszGroupName == 0)
6458             {
6459                 if (CurrentService->lpGroup != NULL)
6460                     continue;
6461             }
6462             else
6463             {
6464                 if ((CurrentService->lpGroup == NULL) ||
6465                     _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6466                     continue;
6467             }
6468         }
6469 
6470         dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6471                  (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6472                  (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
6473 
6474         if (dwRequiredSize + dwSize <= cbBufSize)
6475         {
6476             /* Copy the service name */
6477             wcscpy(lpStringPtr,
6478                    CurrentService->lpServiceName);
6479             lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
6480             lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
6481 
6482             /* Copy the display name */
6483             wcscpy(lpStringPtr,
6484                    CurrentService->lpDisplayName);
6485             lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
6486             lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
6487 
6488             /* Copy the status information */
6489             memcpy(&lpStatusPtr->ServiceStatusProcess,
6490                    &CurrentService->Status,
6491                    sizeof(SERVICE_STATUS));
6492 
6493             /* Copy the service process ID */
6494             if ((CurrentService->Status.dwCurrentState == SERVICE_STOPPED) || (CurrentService->lpImage == NULL))
6495                 lpStatusPtr->ServiceStatusProcess.dwProcessId = 0;
6496             else
6497                 lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->lpImage->dwProcessId;
6498 
6499             lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
6500 
6501             lpStatusPtr++;
6502             dwRequiredSize += dwSize;
6503         }
6504         else
6505         {
6506             break;
6507         }
6508     }
6509 
6510     if (dwError == 0)
6511     {
6512         *pcbBytesNeeded = 0;
6513         if (lpResumeIndex)
6514             *lpResumeIndex = 0;
6515     }
6516 
6517 Done:
6518     /* Unlock the service database */
6519     ScmUnlockDatabase();
6520 
6521     DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
6522 
6523     return dwError;
6524 }
6525 
6526 
6527 /* Function 43 */
6528 DWORD
6529 WINAPI
6530 RSendTSMessage(
6531     handle_t BindingHandle)  /* FIXME */
6532 {
6533     UNIMPLEMENTED;
6534     return ERROR_CALL_NOT_IMPLEMENTED;
6535 }
6536 
6537 
6538 /* Function 44 */
6539 DWORD
6540 WINAPI
6541 RCreateServiceWOW64A(
6542     handle_t BindingHandle,
6543     LPSTR lpServiceName,
6544     LPSTR lpDisplayName,
6545     DWORD dwDesiredAccess,
6546     DWORD dwServiceType,
6547     DWORD dwStartType,
6548     DWORD dwErrorControl,
6549     LPSTR lpBinaryPathName,
6550     LPSTR lpLoadOrderGroup,
6551     LPDWORD lpdwTagId,
6552     LPBYTE lpDependencies,
6553     DWORD dwDependSize,
6554     LPSTR lpServiceStartName,
6555     LPBYTE lpPassword,
6556     DWORD dwPwSize,
6557     LPSC_RPC_HANDLE lpServiceHandle)
6558 {
6559     UNIMPLEMENTED;
6560     return ERROR_CALL_NOT_IMPLEMENTED;
6561 }
6562 
6563 
6564 /* Function 45 */
6565 DWORD
6566 WINAPI
6567 RCreateServiceWOW64W(
6568     handle_t BindingHandle,
6569     LPWSTR lpServiceName,
6570     LPWSTR lpDisplayName,
6571     DWORD dwDesiredAccess,
6572     DWORD dwServiceType,
6573     DWORD dwStartType,
6574     DWORD dwErrorControl,
6575     LPWSTR lpBinaryPathName,
6576     LPWSTR lpLoadOrderGroup,
6577     LPDWORD lpdwTagId,
6578     LPBYTE lpDependencies,
6579     DWORD dwDependSize,
6580     LPWSTR lpServiceStartName,
6581     LPBYTE lpPassword,
6582     DWORD dwPwSize,
6583     LPSC_RPC_HANDLE lpServiceHandle)
6584 {
6585     UNIMPLEMENTED;
6586     return ERROR_CALL_NOT_IMPLEMENTED;
6587 }
6588 
6589 
6590 /* Function 46 */
6591 DWORD
6592 WINAPI
6593 RI_ScQueryServiceTagInfo(
6594     SC_RPC_HANDLE hSCManager,
6595     TAG_INFO_LEVEL dwInfoLevel,
6596     PTAG_INFO_NAME_FROM_TAG_IN_PARAMS * lpInParams,
6597     PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS * lpOutParams)
6598 {
6599     PMANAGER_HANDLE hManager;
6600 
6601     /* Validate handle */
6602     hManager = ScmGetServiceManagerFromHandle(hSCManager);
6603     if (hManager == NULL)
6604     {
6605         return ERROR_INVALID_HANDLE;
6606     }
6607 
6608     /* FIXME: should check whether client is local */
6609 
6610     /* Check access rights */
6611     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
6612                                   SC_MANAGER_ENUMERATE_SERVICE))
6613     {
6614         return ERROR_ACCESS_DENIED;
6615     }
6616 
6617     /* Check parameters */
6618     if (lpInParams == NULL || lpOutParams == NULL)
6619     {
6620         return ERROR_INVALID_PARAMETER;
6621     }
6622 
6623     /* Check info level */
6624     if (dwInfoLevel != TagInfoLevelNameFromTag)
6625     {
6626         return ERROR_RETRY;
6627     }
6628 
6629     /* Call internal helper */
6630     return ScmGetServiceNameFromTag(*lpInParams, lpOutParams);
6631 }
6632 
6633 
6634 /* Function 47 */
6635 DWORD
6636 WINAPI
6637 RNotifyServiceStatusChange(
6638     SC_RPC_HANDLE hService,
6639     SC_RPC_NOTIFY_PARAMS NotifyParams,
6640     GUID *pClientProcessGuid,
6641     GUID *pSCMProcessGuid,
6642     PBOOL pfCreateRemoteQueue,
6643     LPSC_NOTIFY_RPC_HANDLE phNotify)
6644 {
6645     UNIMPLEMENTED;
6646     return ERROR_CALL_NOT_IMPLEMENTED;
6647 }
6648 
6649 
6650 /* Function 48 */
6651 DWORD
6652 WINAPI
6653 RGetNotifyResults(
6654     SC_NOTIFY_RPC_HANDLE hNotify,
6655     PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
6656 {
6657     UNIMPLEMENTED;
6658     return ERROR_CALL_NOT_IMPLEMENTED;
6659 }
6660 
6661 
6662 /* Function 49 */
6663 DWORD
6664 WINAPI
6665 RCloseNotifyHandle(
6666     LPSC_NOTIFY_RPC_HANDLE phNotify,
6667     PBOOL pfApcFired)
6668 {
6669     UNIMPLEMENTED;
6670     return ERROR_CALL_NOT_IMPLEMENTED;
6671 }
6672 
6673 
6674 /* Function 50 */
6675 DWORD
6676 WINAPI
6677 RControlServiceExA(
6678     SC_RPC_HANDLE hService,
6679     DWORD dwControl,
6680     DWORD dwInfoLevel)
6681 {
6682     UNIMPLEMENTED;
6683     return ERROR_CALL_NOT_IMPLEMENTED;
6684 }
6685 
6686 
6687 /* Function 51 */
6688 DWORD
6689 WINAPI
6690 RControlServiceExW(
6691     SC_RPC_HANDLE hService,
6692     DWORD dwControl,
6693     DWORD dwInfoLevel)
6694 {
6695     UNIMPLEMENTED;
6696     return ERROR_CALL_NOT_IMPLEMENTED;
6697 }
6698 
6699 
6700 /* Function 52 */
6701 DWORD
6702 WINAPI
6703 RSendPnPMessage(
6704     handle_t BindingHandle)  /* FIXME */
6705 {
6706     UNIMPLEMENTED;
6707     return ERROR_CALL_NOT_IMPLEMENTED;
6708 }
6709 
6710 
6711 /* Function 53 */
6712 DWORD
6713 WINAPI
6714 RValidatePnPService(
6715     handle_t BindingHandle)  /* FIXME */
6716 {
6717     UNIMPLEMENTED;
6718     return ERROR_CALL_NOT_IMPLEMENTED;
6719 }
6720 
6721 
6722 /* Function 54 */
6723 DWORD
6724 WINAPI
6725 ROpenServiceStatusHandle(
6726     handle_t BindingHandle)  /* FIXME */
6727 {
6728     UNIMPLEMENTED;
6729     return ERROR_CALL_NOT_IMPLEMENTED;
6730 }
6731 
6732 
6733 /* Function 55 */
6734 DWORD
6735 WINAPI
6736 RFunction55(
6737     handle_t BindingHandle)  /* FIXME */
6738 {
6739     UNIMPLEMENTED;
6740     return ERROR_CALL_NOT_IMPLEMENTED;
6741 }
6742 
6743 
6744 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
6745 {
6746     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
6747 }
6748 
6749 
6750 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
6751 {
6752     HeapFree(GetProcessHeap(), 0, ptr);
6753 }
6754 
6755 
6756 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
6757 {
6758     /* Close the handle */
6759     RCloseServiceHandle(&hSCObject);
6760 }
6761 
6762 
6763 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
6764 {
6765     /* Unlock the database */
6766     RUnlockServiceDatabase(&Lock);
6767 }
6768 
6769 
6770 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
6771 {
6772 }
6773 
6774 /* EOF */
6775