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