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