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