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