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