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