xref: /reactos/dll/win32/advapi32/service/scm.c (revision 0c2cdcae)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            lib/advapi32/service/scm.c
5  * PURPOSE:         Service control manager functions
6  * PROGRAMMER:      Emanuele Aliberti
7  *                  Eric Kohl
8  *                  Pierre Schweitzer
9  */
10 
11 /* INCLUDES ******************************************************************/
12 
13 #include <advapi32.h>
14 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
15 
16 NTSTATUS
17 WINAPI
18 SystemFunction004(
19     const struct ustring *in,
20     const struct ustring *key,
21     struct ustring *out);
22 
23 NTSTATUS
24 WINAPI
25 SystemFunction028(
26     IN PVOID ContextHandle,
27     OUT LPBYTE SessionKey);
28 
29 /* FUNCTIONS *****************************************************************/
30 
31 handle_t __RPC_USER
32 SVCCTL_HANDLEA_bind(SVCCTL_HANDLEA szMachineName)
33 {
34     handle_t hBinding = NULL;
35     RPC_CSTR pszStringBinding;
36     RPC_STATUS status;
37 
38     TRACE("SVCCTL_HANDLEA_bind(%s)\n",
39           debugstr_a(szMachineName));
40 
41     status = RpcStringBindingComposeA(NULL,
42                                       (RPC_CSTR)"ncacn_np",
43                                       (RPC_CSTR)szMachineName,
44                                       (RPC_CSTR)"\\pipe\\ntsvcs",
45                                       NULL,
46                                       &pszStringBinding);
47     if (status != RPC_S_OK)
48     {
49         ERR("RpcStringBindingCompose returned 0x%x\n", status);
50         return NULL;
51     }
52 
53     /* Set the binding handle that will be used to bind to the server. */
54     status = RpcBindingFromStringBindingA(pszStringBinding,
55                                           &hBinding);
56     if (status != RPC_S_OK)
57     {
58         ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
59     }
60 
61     status = RpcStringFreeA(&pszStringBinding);
62     if (status != RPC_S_OK)
63     {
64         ERR("RpcStringFree returned 0x%x\n", status);
65     }
66 
67     return hBinding;
68 }
69 
70 
71 void __RPC_USER
72 SVCCTL_HANDLEA_unbind(SVCCTL_HANDLEA szMachineName,
73                       handle_t hBinding)
74 {
75     RPC_STATUS status;
76 
77     TRACE("SVCCTL_HANDLEA_unbind(%s %p)\n",
78           debugstr_a(szMachineName), hBinding);
79 
80     status = RpcBindingFree(&hBinding);
81     if (status != RPC_S_OK)
82     {
83         ERR("RpcBindingFree returned 0x%x\n", status);
84     }
85 }
86 
87 
88 handle_t __RPC_USER
89 SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW szMachineName)
90 {
91     handle_t hBinding = NULL;
92     RPC_WSTR pszStringBinding;
93     RPC_STATUS status;
94 
95     TRACE("SVCCTL_HANDLEW_bind(%s)\n",
96           debugstr_w(szMachineName));
97 
98     status = RpcStringBindingComposeW(NULL,
99                                       L"ncacn_np",
100                                       szMachineName,
101                                       L"\\pipe\\ntsvcs",
102                                       NULL,
103                                       &pszStringBinding);
104     if (status != RPC_S_OK)
105     {
106         ERR("RpcStringBindingCompose returned 0x%x\n", status);
107         return NULL;
108     }
109 
110     /* Set the binding handle that will be used to bind to the server. */
111     status = RpcBindingFromStringBindingW(pszStringBinding,
112                                           &hBinding);
113     if (status != RPC_S_OK)
114     {
115         ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
116     }
117 
118     status = RpcStringFreeW(&pszStringBinding);
119     if (status != RPC_S_OK)
120     {
121         ERR("RpcStringFree returned 0x%x\n", status);
122     }
123 
124     return hBinding;
125 }
126 
127 
128 void __RPC_USER
129 SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW szMachineName,
130                       handle_t hBinding)
131 {
132     RPC_STATUS status;
133 
134     TRACE("SVCCTL_HANDLEW_unbind(%s %p)\n",
135           debugstr_w(szMachineName), hBinding);
136 
137     status = RpcBindingFree(&hBinding);
138     if (status != RPC_S_OK)
139     {
140         ERR("RpcBindingFree returned 0x%x\n", status);
141     }
142 }
143 
144 
145 DWORD
146 ScmRpcStatusToWinError(RPC_STATUS Status)
147 {
148     TRACE("ScmRpcStatusToWinError(%lx)\n",
149           Status);
150 
151     switch (Status)
152     {
153         case STATUS_ACCESS_VIOLATION:
154         case RPC_S_INVALID_BINDING:
155         case RPC_X_SS_IN_NULL_CONTEXT:
156             return ERROR_INVALID_HANDLE;
157 
158         case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
159         case RPC_X_BYTE_COUNT_TOO_SMALL:
160             return ERROR_INVALID_PARAMETER;
161 
162         case RPC_X_NULL_REF_POINTER:
163             return ERROR_INVALID_ADDRESS;
164 
165         default:
166             return (DWORD)Status;
167     }
168 }
169 
170 
171 static
172 DWORD
173 ScmEncryptPassword(
174     _In_ PVOID ContextHandle,
175     _In_ PCWSTR pClearTextPassword,
176     _Out_ PBYTE *pEncryptedPassword,
177     _Out_ PDWORD pEncryptedPasswordSize)
178 {
179     struct ustring inData, keyData, outData;
180     BYTE SessionKey[16];
181     PBYTE pBuffer;
182     NTSTATUS Status;
183 
184     /* Get the session key */
185     Status = SystemFunction028(ContextHandle,
186                                SessionKey);
187     if (!NT_SUCCESS(Status))
188     {
189         ERR("SystemFunction028 failed (Status 0x%08lx)\n", Status);
190         return RtlNtStatusToDosError(Status);
191     }
192 
193     inData.Length = (wcslen(pClearTextPassword) + 1) * sizeof(WCHAR);
194     inData.MaximumLength = inData.Length;
195     inData.Buffer = (unsigned char *)pClearTextPassword;
196 
197     keyData.Length = sizeof(SessionKey);
198     keyData.MaximumLength = keyData.Length;
199     keyData.Buffer = SessionKey;
200 
201     outData.Length = 0;
202     outData.MaximumLength = 0;
203     outData.Buffer = NULL;
204 
205     /* Get the required buffer size */
206     Status = SystemFunction004(&inData,
207                                &keyData,
208                                &outData);
209     if (Status != STATUS_BUFFER_TOO_SMALL)
210     {
211         ERR("SystemFunction004 failed (Status 0x%08lx)\n", Status);
212         return RtlNtStatusToDosError(Status);
213     }
214 
215     /* Allocate a buffer for the encrypted password */
216     pBuffer = HeapAlloc(GetProcessHeap(), 0, outData.Length);
217     if (pBuffer == NULL)
218         return ERROR_OUTOFMEMORY;
219 
220     outData.MaximumLength = outData.Length;
221     outData.Buffer = pBuffer;
222 
223     /* Encrypt the password */
224     Status = SystemFunction004(&inData,
225                                &keyData,
226                                &outData);
227     if (!NT_SUCCESS(Status))
228     {
229         ERR("SystemFunction004 failed (Status 0x%08lx)\n", Status);
230         HeapFree(GetProcessHeap(), 0, pBuffer);
231         return RtlNtStatusToDosError(Status);
232     }
233 
234     *pEncryptedPassword = outData.Buffer;
235     *pEncryptedPasswordSize = outData.Length;
236 
237     return ERROR_SUCCESS;
238 }
239 
240 
241 /**********************************************************************
242  *  ChangeServiceConfig2A
243  *
244  * @implemented
245  */
246 BOOL WINAPI
247 ChangeServiceConfig2A(SC_HANDLE hService,
248                       DWORD dwInfoLevel,
249                       LPVOID lpInfo)
250 {
251     SC_RPC_CONFIG_INFOA Info;
252     DWORD dwError;
253 
254     TRACE("ChangeServiceConfig2A(%p %lu %p)\n",
255           hService, dwInfoLevel, lpInfo);
256 
257     if (lpInfo == NULL) return TRUE;
258 
259     /* Fill relevant field of the Info structure */
260     Info.dwInfoLevel = dwInfoLevel;
261     switch (dwInfoLevel)
262     {
263         case SERVICE_CONFIG_DESCRIPTION:
264             Info.psd = lpInfo;
265             break;
266 
267         case SERVICE_CONFIG_FAILURE_ACTIONS:
268             Info.psfa = lpInfo;
269             break;
270 
271         default:
272             WARN("Unknown info level 0x%lx\n", dwInfoLevel);
273             SetLastError(ERROR_INVALID_PARAMETER);
274             return FALSE;
275     }
276 
277     RpcTryExcept
278     {
279         dwError = RChangeServiceConfig2A((SC_RPC_HANDLE)hService,
280                                          Info);
281     }
282     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
283     {
284         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
285     }
286     RpcEndExcept;
287 
288     if (dwError != ERROR_SUCCESS)
289     {
290         TRACE("RChangeServiceConfig2A() failed (Error %lu)\n", dwError);
291         SetLastError(dwError);
292         return FALSE;
293     }
294 
295     return TRUE;
296 }
297 
298 
299 /**********************************************************************
300  *  ChangeServiceConfig2W
301  *
302  * @implemented
303  */
304 BOOL WINAPI
305 ChangeServiceConfig2W(SC_HANDLE hService,
306                       DWORD dwInfoLevel,
307                       LPVOID lpInfo)
308 {
309     SC_RPC_CONFIG_INFOW Info;
310     DWORD dwError;
311 
312     TRACE("ChangeServiceConfig2W(%p %lu %p)\n",
313           hService, dwInfoLevel, lpInfo);
314 
315     if (lpInfo == NULL) return TRUE;
316 
317     /* Fill relevant field of the Info structure */
318     Info.dwInfoLevel = dwInfoLevel;
319     switch (dwInfoLevel)
320     {
321         case SERVICE_CONFIG_DESCRIPTION:
322             Info.psd = lpInfo;
323             break;
324 
325         case SERVICE_CONFIG_FAILURE_ACTIONS:
326             Info.psfa = lpInfo;
327             break;
328 
329         default:
330             WARN("Unknown info level 0x%lx\n", dwInfoLevel);
331             SetLastError(ERROR_INVALID_PARAMETER);
332             return FALSE;
333     }
334 
335     RpcTryExcept
336     {
337         dwError = RChangeServiceConfig2W((SC_RPC_HANDLE)hService,
338                                          Info);
339     }
340     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
341     {
342         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
343     }
344     RpcEndExcept;
345 
346     if (dwError != ERROR_SUCCESS)
347     {
348         TRACE("RChangeServiceConfig2W() failed (Error %lu)\n", dwError);
349         SetLastError(dwError);
350         return FALSE;
351     }
352 
353     return TRUE;
354 }
355 
356 
357 /**********************************************************************
358  *  ChangeServiceConfigA
359  *
360  * @implemented
361  */
362 BOOL WINAPI
363 ChangeServiceConfigA(SC_HANDLE hService,
364                      DWORD dwServiceType,
365                      DWORD dwStartType,
366                      DWORD dwErrorControl,
367                      LPCSTR lpBinaryPathName,
368                      LPCSTR lpLoadOrderGroup,
369                      LPDWORD lpdwTagId,
370                      LPCSTR lpDependencies,
371                      LPCSTR lpServiceStartName,
372                      LPCSTR lpPassword,
373                      LPCSTR lpDisplayName)
374 {
375     DWORD dwError;
376     DWORD dwDependenciesLength = 0;
377     SIZE_T cchLength;
378     LPCSTR lpStr;
379     DWORD dwPasswordSize = 0;
380     LPWSTR lpPasswordW = NULL;
381     LPBYTE lpEncryptedPassword = NULL;
382 
383     TRACE("ChangeServiceConfigA(%p %lu %lu %lu %s %s %p %s %s %s %s)\n",
384           hService, dwServiceType, dwStartType, dwErrorControl, debugstr_a(lpBinaryPathName),
385           debugstr_a(lpLoadOrderGroup), lpdwTagId, debugstr_a(lpDependencies),
386           debugstr_a(lpServiceStartName), debugstr_a(lpPassword), debugstr_a(lpDisplayName));
387 
388     /* Calculate the Dependencies length*/
389     if (lpDependencies != NULL)
390     {
391         lpStr = lpDependencies;
392         while (*lpStr)
393         {
394             cchLength = strlen(lpStr) + 1;
395             dwDependenciesLength += (DWORD)cchLength;
396             lpStr = lpStr + cchLength;
397         }
398         dwDependenciesLength++;
399     }
400 
401     if (lpPassword != NULL)
402     {
403         /* Convert the password to unicode */
404         lpPasswordW = HeapAlloc(GetProcessHeap(),
405                                 HEAP_ZERO_MEMORY,
406                                 (strlen(lpPassword) + 1) * sizeof(WCHAR));
407         if (lpPasswordW == NULL)
408         {
409             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
410             return FALSE;
411         }
412 
413         MultiByteToWideChar(CP_ACP,
414                             0,
415                             lpPassword,
416                             -1,
417                             lpPasswordW,
418                             (int)(strlen(lpPassword) + 1));
419 
420         /* Encrypt the unicode password */
421         dwError = ScmEncryptPassword(hService,
422                                      lpPasswordW,
423                                      &lpEncryptedPassword,
424                                      &dwPasswordSize);
425         if (dwError != ERROR_SUCCESS)
426             goto done;
427     }
428 
429     RpcTryExcept
430     {
431         dwError = RChangeServiceConfigA((SC_RPC_HANDLE)hService,
432                                         dwServiceType,
433                                         dwStartType,
434                                         dwErrorControl,
435                                         (LPSTR)lpBinaryPathName,
436                                         (LPSTR)lpLoadOrderGroup,
437                                         lpdwTagId,
438                                         (LPBYTE)lpDependencies,
439                                         dwDependenciesLength,
440                                         (LPSTR)lpServiceStartName,
441                                         lpEncryptedPassword,
442                                         dwPasswordSize,
443                                         (LPSTR)lpDisplayName);
444     }
445     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
446     {
447         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
448     }
449     RpcEndExcept;
450 
451 done:
452     if (lpPasswordW != NULL)
453     {
454         /* Wipe and release the password buffers */
455         SecureZeroMemory(lpPasswordW, (wcslen(lpPasswordW) + 1) * sizeof(WCHAR));
456         HeapFree(GetProcessHeap(), 0, lpPasswordW);
457 
458         if (lpEncryptedPassword != NULL)
459         {
460             SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
461             HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
462         }
463     }
464 
465     if (dwError != ERROR_SUCCESS)
466     {
467         TRACE("RChangeServiceConfigA() failed (Error %lu)\n", dwError);
468         SetLastError(dwError);
469         return FALSE;
470     }
471 
472     return TRUE;
473 }
474 
475 
476 /**********************************************************************
477  *  ChangeServiceConfigW
478  *
479  * @implemented
480  */
481 BOOL WINAPI
482 ChangeServiceConfigW(SC_HANDLE hService,
483                      DWORD dwServiceType,
484                      DWORD dwStartType,
485                      DWORD dwErrorControl,
486                      LPCWSTR lpBinaryPathName,
487                      LPCWSTR lpLoadOrderGroup,
488                      LPDWORD lpdwTagId,
489                      LPCWSTR lpDependencies,
490                      LPCWSTR lpServiceStartName,
491                      LPCWSTR lpPassword,
492                      LPCWSTR lpDisplayName)
493 {
494     DWORD dwError;
495     DWORD dwDependenciesLength = 0;
496     SIZE_T cchLength;
497     LPCWSTR lpStr;
498     DWORD dwPasswordSize = 0;
499     LPBYTE lpEncryptedPassword = NULL;
500 
501     TRACE("ChangeServiceConfigW(%p %lu %lu %lu %s %s %p %s %s %s %s)\n",
502           hService, dwServiceType, dwStartType, dwErrorControl, debugstr_w(lpBinaryPathName),
503           debugstr_w(lpLoadOrderGroup), lpdwTagId, debugstr_w(lpDependencies),
504           debugstr_w(lpServiceStartName), debugstr_w(lpPassword), debugstr_w(lpDisplayName));
505 
506     /* Calculate the Dependencies length*/
507     if (lpDependencies != NULL)
508     {
509         lpStr = lpDependencies;
510         while (*lpStr)
511         {
512             cchLength = wcslen(lpStr) + 1;
513             dwDependenciesLength += (DWORD)cchLength;
514             lpStr = lpStr + cchLength;
515         }
516         dwDependenciesLength++;
517         dwDependenciesLength *= sizeof(WCHAR);
518     }
519 
520     if (lpPassword != NULL)
521     {
522         dwError = ScmEncryptPassword(hService,
523                                      lpPassword,
524                                      &lpEncryptedPassword,
525                                      &dwPasswordSize);
526         if (dwError != ERROR_SUCCESS)
527         {
528             ERR("ScmEncryptPassword failed (Error %lu)\n", dwError);
529             goto done;
530         }
531     }
532 
533     RpcTryExcept
534     {
535         dwError = RChangeServiceConfigW((SC_RPC_HANDLE)hService,
536                                         dwServiceType,
537                                         dwStartType,
538                                         dwErrorControl,
539                                         (LPWSTR)lpBinaryPathName,
540                                         (LPWSTR)lpLoadOrderGroup,
541                                         lpdwTagId,
542                                         (LPBYTE)lpDependencies,
543                                         dwDependenciesLength,
544                                         (LPWSTR)lpServiceStartName,
545                                         lpEncryptedPassword,
546                                         dwPasswordSize,
547                                         (LPWSTR)lpDisplayName);
548     }
549     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
550     {
551         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
552     }
553     RpcEndExcept;
554 
555 done:
556     if (lpEncryptedPassword != NULL)
557     {
558         /* Wipe and release the password buffer */
559         SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
560         HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
561     }
562 
563     if (dwError != ERROR_SUCCESS)
564     {
565         TRACE("RChangeServiceConfigW() failed (Error %lu)\n", dwError);
566         SetLastError(dwError);
567         return FALSE;
568     }
569 
570     return TRUE;
571 }
572 
573 
574 /**********************************************************************
575  *  CloseServiceHandle
576  *
577  * @implemented
578  */
579 BOOL WINAPI
580 CloseServiceHandle(SC_HANDLE hSCObject)
581 {
582     DWORD dwError;
583 
584     TRACE("CloseServiceHandle(%p)\n",
585           hSCObject);
586 
587     if (!hSCObject)
588     {
589         SetLastError(ERROR_INVALID_HANDLE);
590         return FALSE;
591     }
592 
593     RpcTryExcept
594     {
595         dwError = RCloseServiceHandle((LPSC_RPC_HANDLE)&hSCObject);
596     }
597     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
598     {
599         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
600     }
601     RpcEndExcept;
602 
603     if (dwError)
604     {
605         TRACE("RCloseServiceHandle() failed (Error %lu)\n", dwError);
606         SetLastError(dwError);
607         return FALSE;
608     }
609 
610     TRACE("CloseServiceHandle() done\n");
611 
612     return TRUE;
613 }
614 
615 
616 /**********************************************************************
617  *  ControlService
618  *
619  * @implemented
620  */
621 BOOL WINAPI
622 ControlService(SC_HANDLE hService,
623                DWORD dwControl,
624                LPSERVICE_STATUS lpServiceStatus)
625 {
626     DWORD dwError;
627 
628     TRACE("ControlService(%p %lu %p)\n",
629           hService, dwControl, lpServiceStatus);
630 
631     RpcTryExcept
632     {
633         dwError = RControlService((SC_RPC_HANDLE)hService,
634                                   dwControl,
635                                   lpServiceStatus);
636     }
637     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
638     {
639         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
640     }
641     RpcEndExcept;
642 
643     if (dwError != ERROR_SUCCESS)
644     {
645         TRACE("RControlService() failed (Error %lu)\n", dwError);
646         SetLastError(dwError);
647         return FALSE;
648     }
649 
650     TRACE("ControlService() done\n");
651 
652     return TRUE;
653 }
654 
655 
656 /**********************************************************************
657  *  ControlServiceEx
658  *
659  * @unimplemented
660  */
661 BOOL WINAPI
662 ControlServiceEx(IN SC_HANDLE hService,
663                  IN DWORD dwControl,
664                  IN DWORD dwInfoLevel,
665                  IN OUT PVOID pControlParams)
666 {
667     FIXME("ControlServiceEx(%p %lu %lu %p)\n",
668           hService, dwControl, dwInfoLevel, pControlParams);
669     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
670     return FALSE;
671 }
672 
673 
674 /**********************************************************************
675  *  CreateServiceA
676  *
677  * @implemented
678  */
679 SC_HANDLE WINAPI
680 CreateServiceA(SC_HANDLE hSCManager,
681                LPCSTR lpServiceName,
682                LPCSTR lpDisplayName,
683                DWORD dwDesiredAccess,
684                DWORD dwServiceType,
685                DWORD dwStartType,
686                DWORD dwErrorControl,
687                LPCSTR lpBinaryPathName,
688                LPCSTR lpLoadOrderGroup,
689                LPDWORD lpdwTagId,
690                LPCSTR lpDependencies,
691                LPCSTR lpServiceStartName,
692                LPCSTR lpPassword)
693 {
694     SC_HANDLE hService = NULL;
695     DWORD dwDependenciesLength = 0;
696     DWORD dwError;
697     SIZE_T cchLength;
698     LPCSTR lpStr;
699     DWORD dwPasswordSize = 0;
700     LPWSTR lpPasswordW = NULL;
701     LPBYTE lpEncryptedPassword = NULL;
702 
703     TRACE("CreateServiceA(%p %s %s %lx %lu %lu %lu %s %s %p %s %s %s)\n",
704           hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName),
705           dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
706           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup), lpdwTagId,
707           debugstr_a(lpDependencies), debugstr_a(lpServiceStartName), debugstr_a(lpPassword));
708 
709     if (!hSCManager)
710     {
711         SetLastError(ERROR_INVALID_HANDLE);
712         return NULL;
713     }
714 
715     /* Calculate the Dependencies length */
716     if (lpDependencies != NULL)
717     {
718         lpStr = lpDependencies;
719         while (*lpStr)
720         {
721             cchLength = strlen(lpStr) + 1;
722             dwDependenciesLength += (DWORD)cchLength;
723             lpStr = lpStr + cchLength;
724         }
725         dwDependenciesLength++;
726     }
727 
728     if (lpPassword != NULL)
729     {
730         /* Convert the password to unicode */
731         lpPasswordW = HeapAlloc(GetProcessHeap(),
732                                 HEAP_ZERO_MEMORY,
733                                 (strlen(lpPassword) + 1) * sizeof(WCHAR));
734         if (lpPasswordW == NULL)
735         {
736             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
737             return FALSE;
738         }
739 
740         MultiByteToWideChar(CP_ACP,
741                             0,
742                             lpPassword,
743                             -1,
744                             lpPasswordW,
745                             (int)(strlen(lpPassword) + 1));
746 
747         /* Encrypt the password */
748         dwError = ScmEncryptPassword(hSCManager,
749                                      lpPasswordW,
750                                      &lpEncryptedPassword,
751                                      &dwPasswordSize);
752         if (dwError != ERROR_SUCCESS)
753             goto done;
754     }
755 
756     RpcTryExcept
757     {
758         dwError = RCreateServiceA((SC_RPC_HANDLE)hSCManager,
759                                   (LPSTR)lpServiceName,
760                                   (LPSTR)lpDisplayName,
761                                   dwDesiredAccess,
762                                   dwServiceType,
763                                   dwStartType,
764                                   dwErrorControl,
765                                   (LPSTR)lpBinaryPathName,
766                                   (LPSTR)lpLoadOrderGroup,
767                                   lpdwTagId,
768                                   (LPBYTE)lpDependencies,
769                                   dwDependenciesLength,
770                                   (LPSTR)lpServiceStartName,
771                                   lpEncryptedPassword,
772                                   dwPasswordSize,
773                                   (SC_RPC_HANDLE *)&hService);
774     }
775     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
776     {
777         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
778     }
779     RpcEndExcept;
780 
781 done:
782     if (lpPasswordW != NULL)
783     {
784         /* Wipe and release the password buffers */
785         SecureZeroMemory(lpPasswordW, (wcslen(lpPasswordW) + 1) * sizeof(WCHAR));
786         HeapFree(GetProcessHeap(), 0, lpPasswordW);
787 
788         if (lpEncryptedPassword != NULL)
789         {
790             SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
791             HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
792         }
793     }
794 
795     SetLastError(dwError);
796     if (dwError != ERROR_SUCCESS)
797     {
798         TRACE("RCreateServiceA() failed (Error %lu)\n", dwError);
799         return NULL;
800     }
801 
802     return hService;
803 }
804 
805 
806 /**********************************************************************
807  *  CreateServiceW
808  *
809  * @implemented
810  */
811 SC_HANDLE WINAPI
812 CreateServiceW(SC_HANDLE hSCManager,
813                LPCWSTR lpServiceName,
814                LPCWSTR lpDisplayName,
815                DWORD dwDesiredAccess,
816                DWORD dwServiceType,
817                DWORD dwStartType,
818                DWORD dwErrorControl,
819                LPCWSTR lpBinaryPathName,
820                LPCWSTR lpLoadOrderGroup,
821                LPDWORD lpdwTagId,
822                LPCWSTR lpDependencies,
823                LPCWSTR lpServiceStartName,
824                LPCWSTR lpPassword)
825 {
826     SC_HANDLE hService = NULL;
827     DWORD dwDependenciesLength = 0;
828     DWORD dwError;
829     SIZE_T cchLength;
830     LPCWSTR lpStr;
831     DWORD dwPasswordSize = 0;
832     LPBYTE lpEncryptedPassword = NULL;
833 
834     TRACE("CreateServiceW(%p %s %s %lx %lu %lu %lu %s %s %p %s %s %s)\n",
835           hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName),
836           dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
837           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup), lpdwTagId,
838           debugstr_w(lpDependencies), debugstr_w(lpServiceStartName), debugstr_w(lpPassword));
839 
840     if (!hSCManager)
841     {
842         SetLastError(ERROR_INVALID_HANDLE);
843         return NULL;
844     }
845 
846     /* Calculate the Dependencies length */
847     if (lpDependencies != NULL)
848     {
849         lpStr = lpDependencies;
850         while (*lpStr)
851         {
852             cchLength = wcslen(lpStr) + 1;
853             dwDependenciesLength += (DWORD)cchLength;
854             lpStr = lpStr + cchLength;
855         }
856         dwDependenciesLength++;
857         dwDependenciesLength *= sizeof(WCHAR);
858     }
859 
860     if (lpPassword != NULL)
861     {
862         /* Encrypt the password */
863         dwError = ScmEncryptPassword(hSCManager,
864                                      lpPassword,
865                                      &lpEncryptedPassword,
866                                      &dwPasswordSize);
867         if (dwError != ERROR_SUCCESS)
868             goto done;
869     }
870 
871     RpcTryExcept
872     {
873         dwError = RCreateServiceW((SC_RPC_HANDLE)hSCManager,
874                                   lpServiceName,
875                                   lpDisplayName,
876                                   dwDesiredAccess,
877                                   dwServiceType,
878                                   dwStartType,
879                                   dwErrorControl,
880                                   lpBinaryPathName,
881                                   lpLoadOrderGroup,
882                                   lpdwTagId,
883                                   (LPBYTE)lpDependencies,
884                                   dwDependenciesLength,
885                                   lpServiceStartName,
886                                   lpEncryptedPassword,
887                                   dwPasswordSize,
888                                   (SC_RPC_HANDLE *)&hService);
889     }
890     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
891     {
892         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
893     }
894     RpcEndExcept;
895 
896 done:
897     if (lpEncryptedPassword != NULL)
898     {
899         /* Wipe and release the password buffers */
900         SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
901         HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
902     }
903 
904     SetLastError(dwError);
905     if (dwError != ERROR_SUCCESS)
906     {
907         TRACE("RCreateServiceW() failed (Error %lu)\n", dwError);
908         return NULL;
909     }
910 
911     return hService;
912 }
913 
914 
915 /**********************************************************************
916  *  DeleteService
917  *
918  * @implemented
919  */
920 BOOL WINAPI
921 DeleteService(SC_HANDLE hService)
922 {
923     DWORD dwError;
924 
925     TRACE("DeleteService(%p)\n",
926           hService);
927 
928     RpcTryExcept
929     {
930         dwError = RDeleteService((SC_RPC_HANDLE)hService);
931     }
932     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
933     {
934         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
935     }
936     RpcEndExcept;
937 
938     if (dwError != ERROR_SUCCESS)
939     {
940         TRACE("RDeleteService() failed (Error %lu)\n", dwError);
941         SetLastError(dwError);
942         return FALSE;
943     }
944 
945     return TRUE;
946 }
947 
948 
949 /**********************************************************************
950  *  EnumDependentServicesA
951  *
952  * @implemented
953  */
954 BOOL WINAPI
955 EnumDependentServicesA(SC_HANDLE hService,
956                        DWORD dwServiceState,
957                        LPENUM_SERVICE_STATUSA lpServices,
958                        DWORD cbBufSize,
959                        LPDWORD pcbBytesNeeded,
960                        LPDWORD lpServicesReturned)
961 {
962     ENUM_SERVICE_STATUSA ServiceStatus;
963     LPENUM_SERVICE_STATUSA lpStatusPtr;
964     DWORD dwBufferSize;
965     DWORD dwError;
966     DWORD dwCount;
967 
968     TRACE("EnumDependentServicesA(%p %lu %p %lu %p %p)\n",
969           hService, dwServiceState, lpServices, cbBufSize,
970           pcbBytesNeeded, lpServicesReturned);
971 
972     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSA))
973     {
974         lpStatusPtr = &ServiceStatus;
975         dwBufferSize = sizeof(ENUM_SERVICE_STATUSA);
976     }
977     else
978     {
979         lpStatusPtr = lpServices;
980         dwBufferSize = cbBufSize;
981     }
982 
983     RpcTryExcept
984     {
985         dwError = REnumDependentServicesA((SC_RPC_HANDLE)hService,
986                                           dwServiceState,
987                                           (LPBYTE)lpStatusPtr,
988                                           dwBufferSize,
989                                           pcbBytesNeeded,
990                                           lpServicesReturned);
991     }
992     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
993     {
994         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
995     }
996     RpcEndExcept;
997 
998     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
999     {
1000         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1001         {
1002             if (lpStatusPtr->lpServiceName)
1003                 lpStatusPtr->lpServiceName =
1004                     (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1005 
1006             if (lpStatusPtr->lpDisplayName)
1007                 lpStatusPtr->lpDisplayName =
1008                     (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1009 
1010             lpStatusPtr++;
1011         }
1012     }
1013 
1014     if (dwError != ERROR_SUCCESS)
1015     {
1016         TRACE("REnumDependentServicesA() failed (Error %lu)\n", dwError);
1017         SetLastError(dwError);
1018         return FALSE;
1019     }
1020 
1021     TRACE("EnumDependentServicesA() done\n");
1022 
1023     return TRUE;
1024 }
1025 
1026 
1027 /**********************************************************************
1028  *  EnumDependentServicesW
1029  *
1030  * @implemented
1031  */
1032 BOOL WINAPI
1033 EnumDependentServicesW(SC_HANDLE hService,
1034                        DWORD dwServiceState,
1035                        LPENUM_SERVICE_STATUSW lpServices,
1036                        DWORD cbBufSize,
1037                        LPDWORD pcbBytesNeeded,
1038                        LPDWORD lpServicesReturned)
1039 {
1040     ENUM_SERVICE_STATUSW ServiceStatus;
1041     LPENUM_SERVICE_STATUSW lpStatusPtr;
1042     DWORD dwBufferSize;
1043     DWORD dwError;
1044     DWORD dwCount;
1045 
1046     TRACE("EnumDependentServicesW(%p %lu %p %lu %p %p)\n",
1047           hService, dwServiceState, lpServices, cbBufSize,
1048           pcbBytesNeeded, lpServicesReturned);
1049 
1050     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
1051     {
1052         lpStatusPtr = &ServiceStatus;
1053         dwBufferSize = sizeof(ENUM_SERVICE_STATUSW);
1054     }
1055     else
1056     {
1057         lpStatusPtr = lpServices;
1058         dwBufferSize = cbBufSize;
1059     }
1060 
1061     RpcTryExcept
1062     {
1063         dwError = REnumDependentServicesW((SC_RPC_HANDLE)hService,
1064                                           dwServiceState,
1065                                           (LPBYTE)lpStatusPtr,
1066                                           dwBufferSize,
1067                                           pcbBytesNeeded,
1068                                           lpServicesReturned);
1069     }
1070     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1071     {
1072         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1073     }
1074     RpcEndExcept;
1075 
1076     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1077     {
1078         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1079         {
1080             if (lpStatusPtr->lpServiceName)
1081                 lpStatusPtr->lpServiceName =
1082                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1083 
1084             if (lpStatusPtr->lpDisplayName)
1085                 lpStatusPtr->lpDisplayName =
1086                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1087 
1088             lpStatusPtr++;
1089         }
1090     }
1091 
1092     if (dwError != ERROR_SUCCESS)
1093     {
1094         TRACE("REnumDependentServicesW() failed (Error %lu)\n", dwError);
1095         SetLastError(dwError);
1096         return FALSE;
1097     }
1098 
1099     TRACE("EnumDependentServicesW() done\n");
1100 
1101     return TRUE;
1102 }
1103 
1104 
1105 /**********************************************************************
1106  *  EnumServiceGroupW
1107  *
1108  * @implemented
1109  */
1110 BOOL WINAPI
1111 EnumServiceGroupW(SC_HANDLE hSCManager,
1112                   DWORD dwServiceType,
1113                   DWORD dwServiceState,
1114                   LPENUM_SERVICE_STATUSW lpServices,
1115                   DWORD cbBufSize,
1116                   LPDWORD pcbBytesNeeded,
1117                   LPDWORD lpServicesReturned,
1118                   LPDWORD lpResumeHandle,
1119                   LPCWSTR lpGroup)
1120 {
1121     ENUM_SERVICE_STATUSW ServiceStatus;
1122     LPENUM_SERVICE_STATUSW lpStatusPtr;
1123     DWORD dwBufferSize;
1124     DWORD dwError;
1125     DWORD dwCount;
1126 
1127     TRACE("EnumServiceGroupW(%p %lu %lu %p %lu %p %p %p %s)\n",
1128           hSCManager, dwServiceType, dwServiceState, lpServices,
1129           cbBufSize, pcbBytesNeeded, lpServicesReturned,
1130           lpResumeHandle, debugstr_w(lpGroup));
1131 
1132     if (!hSCManager)
1133     {
1134         SetLastError(ERROR_INVALID_HANDLE);
1135         return FALSE;
1136     }
1137 
1138     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
1139     {
1140         SetLastError(ERROR_INVALID_ADDRESS);
1141         return FALSE;
1142     }
1143 
1144     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
1145     {
1146         lpStatusPtr = &ServiceStatus;
1147         dwBufferSize = sizeof(ENUM_SERVICE_STATUSW);
1148     }
1149     else
1150     {
1151         lpStatusPtr = lpServices;
1152         dwBufferSize = cbBufSize;
1153     }
1154 
1155     RpcTryExcept
1156     {
1157         if (lpGroup == NULL)
1158         {
1159             dwError = REnumServicesStatusW((SC_RPC_HANDLE)hSCManager,
1160                                            dwServiceType,
1161                                            dwServiceState,
1162                                            (LPBYTE)lpStatusPtr,
1163                                            dwBufferSize,
1164                                            pcbBytesNeeded,
1165                                            lpServicesReturned,
1166                                            lpResumeHandle);
1167         }
1168         else
1169         {
1170             dwError = REnumServiceGroupW((SC_RPC_HANDLE)hSCManager,
1171                                          dwServiceType,
1172                                          dwServiceState,
1173                                          (LPBYTE)lpStatusPtr,
1174                                          dwBufferSize,
1175                                          pcbBytesNeeded,
1176                                          lpServicesReturned,
1177                                          lpResumeHandle,
1178                                          lpGroup);
1179         }
1180     }
1181     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1182     {
1183         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1184     }
1185     RpcEndExcept;
1186 
1187     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1188     {
1189         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1190         {
1191             if (lpStatusPtr->lpServiceName)
1192                 lpStatusPtr->lpServiceName =
1193                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1194 
1195             if (lpStatusPtr->lpDisplayName)
1196                 lpStatusPtr->lpDisplayName =
1197                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1198 
1199             lpStatusPtr++;
1200         }
1201     }
1202 
1203     if (dwError != ERROR_SUCCESS)
1204     {
1205         TRACE("REnumServiceGroupW() failed (Error %lu)\n", dwError);
1206         SetLastError(dwError);
1207         return FALSE;
1208     }
1209 
1210     TRACE("EnumServiceGroupW() done\n");
1211 
1212     return TRUE;
1213 }
1214 
1215 
1216 /**********************************************************************
1217  *  EnumServicesStatusA
1218  *
1219  * @implemented
1220  */
1221 BOOL WINAPI
1222 EnumServicesStatusA(SC_HANDLE hSCManager,
1223                     DWORD dwServiceType,
1224                     DWORD dwServiceState,
1225                     LPENUM_SERVICE_STATUSA lpServices,
1226                     DWORD cbBufSize,
1227                     LPDWORD pcbBytesNeeded,
1228                     LPDWORD lpServicesReturned,
1229                     LPDWORD lpResumeHandle)
1230 {
1231     ENUM_SERVICE_STATUSA ServiceStatus;
1232     LPENUM_SERVICE_STATUSA lpStatusPtr;
1233     DWORD dwBufferSize;
1234     DWORD dwError;
1235     DWORD dwCount;
1236 
1237     TRACE("EnumServicesStatusA(%p %lu %lu %p %lu %p %p %p)\n",
1238           hSCManager, dwServiceType, dwServiceState, lpServices,
1239           cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1240 
1241     if (!hSCManager)
1242     {
1243         SetLastError(ERROR_INVALID_HANDLE);
1244         return FALSE;
1245     }
1246 
1247     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
1248     {
1249         SetLastError(ERROR_INVALID_ADDRESS);
1250         return FALSE;
1251     }
1252 
1253     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSA))
1254     {
1255         lpStatusPtr = &ServiceStatus;
1256         dwBufferSize = sizeof(ENUM_SERVICE_STATUSA);
1257     }
1258     else
1259     {
1260         lpStatusPtr = lpServices;
1261         dwBufferSize = cbBufSize;
1262     }
1263 
1264     RpcTryExcept
1265     {
1266         dwError = REnumServicesStatusA((SC_RPC_HANDLE)hSCManager,
1267                                        dwServiceType,
1268                                        dwServiceState,
1269                                        (LPBYTE)lpStatusPtr,
1270                                        dwBufferSize,
1271                                        pcbBytesNeeded,
1272                                        lpServicesReturned,
1273                                        lpResumeHandle);
1274     }
1275     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1276     {
1277         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1278     }
1279     RpcEndExcept;
1280 
1281     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1282     {
1283         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1284         {
1285             if (lpStatusPtr->lpServiceName)
1286                 lpStatusPtr->lpServiceName =
1287                     (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1288 
1289             if (lpStatusPtr->lpDisplayName)
1290                 lpStatusPtr->lpDisplayName =
1291                     (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1292 
1293             lpStatusPtr++;
1294         }
1295     }
1296 
1297     if (dwError != ERROR_SUCCESS)
1298     {
1299         TRACE("REnumServicesStatusA() failed (Error %lu)\n", dwError);
1300         SetLastError(dwError);
1301         return FALSE;
1302     }
1303 
1304     TRACE("EnumServicesStatusA() done\n");
1305 
1306     return TRUE;
1307 }
1308 
1309 
1310 /**********************************************************************
1311  *  EnumServicesStatusW
1312  *
1313  * @implemented
1314  */
1315 BOOL WINAPI
1316 EnumServicesStatusW(SC_HANDLE hSCManager,
1317                     DWORD dwServiceType,
1318                     DWORD dwServiceState,
1319                     LPENUM_SERVICE_STATUSW lpServices,
1320                     DWORD cbBufSize,
1321                     LPDWORD pcbBytesNeeded,
1322                     LPDWORD lpServicesReturned,
1323                     LPDWORD lpResumeHandle)
1324 {
1325     ENUM_SERVICE_STATUSW ServiceStatus;
1326     LPENUM_SERVICE_STATUSW lpStatusPtr;
1327     DWORD dwBufferSize;
1328     DWORD dwError;
1329     DWORD dwCount;
1330 
1331     TRACE("EnumServicesStatusW(%p %lu %lu %p %lu %p %p %p)\n",
1332           hSCManager, dwServiceType, dwServiceState, lpServices,
1333           cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1334 
1335     if (!hSCManager)
1336     {
1337         SetLastError(ERROR_INVALID_HANDLE);
1338         return FALSE;
1339     }
1340 
1341     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
1342     {
1343         SetLastError(ERROR_INVALID_ADDRESS);
1344         return FALSE;
1345     }
1346 
1347     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
1348     {
1349         lpStatusPtr = &ServiceStatus;
1350         dwBufferSize = sizeof(ENUM_SERVICE_STATUSW);
1351     }
1352     else
1353     {
1354         lpStatusPtr = lpServices;
1355         dwBufferSize = cbBufSize;
1356     }
1357 
1358     RpcTryExcept
1359     {
1360         dwError = REnumServicesStatusW((SC_RPC_HANDLE)hSCManager,
1361                                        dwServiceType,
1362                                        dwServiceState,
1363                                        (LPBYTE)lpStatusPtr,
1364                                        dwBufferSize,
1365                                        pcbBytesNeeded,
1366                                        lpServicesReturned,
1367                                        lpResumeHandle);
1368     }
1369     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1370     {
1371         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1372     }
1373     RpcEndExcept;
1374 
1375     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1376     {
1377         for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1378         {
1379             if (lpStatusPtr->lpServiceName)
1380                 lpStatusPtr->lpServiceName =
1381                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1382 
1383             if (lpStatusPtr->lpDisplayName)
1384                 lpStatusPtr->lpDisplayName =
1385                     (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1386 
1387             lpStatusPtr++;
1388         }
1389     }
1390 
1391     if (dwError != ERROR_SUCCESS)
1392     {
1393         TRACE("REnumServicesStatusW() failed (Error %lu)\n", dwError);
1394         SetLastError(dwError);
1395         return FALSE;
1396     }
1397 
1398     TRACE("EnumServicesStatusW() done\n");
1399 
1400     return TRUE;
1401 }
1402 
1403 
1404 /**********************************************************************
1405  *  EnumServicesStatusExA
1406  *
1407  * @implemented
1408  */
1409 BOOL WINAPI
1410 EnumServicesStatusExA(SC_HANDLE hSCManager,
1411                       SC_ENUM_TYPE InfoLevel,
1412                       DWORD dwServiceType,
1413                       DWORD dwServiceState,
1414                       LPBYTE lpServices,
1415                       DWORD cbBufSize,
1416                       LPDWORD pcbBytesNeeded,
1417                       LPDWORD lpServicesReturned,
1418                       LPDWORD lpResumeHandle,
1419                       LPCSTR pszGroupName)
1420 {
1421     ENUM_SERVICE_STATUS_PROCESSA ServiceStatus;
1422     LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtr;
1423     DWORD dwBufferSize;
1424     DWORD dwError;
1425     DWORD dwCount;
1426 
1427     TRACE("EnumServicesStatusExA(%p %lu %lu %p %lu %p %p %p %s)\n",
1428           hSCManager, dwServiceType, dwServiceState, lpServices,
1429           cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle,
1430           debugstr_a(pszGroupName));
1431 
1432     if (InfoLevel != SC_ENUM_PROCESS_INFO)
1433     {
1434         SetLastError(ERROR_INVALID_LEVEL);
1435         return FALSE;
1436     }
1437 
1438     if (!hSCManager)
1439     {
1440         SetLastError(ERROR_INVALID_HANDLE);
1441         return FALSE;
1442     }
1443 
1444     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
1445     {
1446         SetLastError(ERROR_INVALID_ADDRESS);
1447         return FALSE;
1448     }
1449 
1450     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSA))
1451     {
1452         lpStatusPtr = &ServiceStatus;
1453         dwBufferSize = sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1454     }
1455     else
1456     {
1457         lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSA)lpServices;
1458         dwBufferSize = cbBufSize;
1459     }
1460 
1461     RpcTryExcept
1462     {
1463         dwError = REnumServicesStatusExA((SC_RPC_HANDLE)hSCManager,
1464                                          InfoLevel,
1465                                          dwServiceType,
1466                                          dwServiceState,
1467                                          (LPBYTE)lpStatusPtr,
1468                                          dwBufferSize,
1469                                          pcbBytesNeeded,
1470                                          lpServicesReturned,
1471                                          lpResumeHandle,
1472                                          (LPSTR)pszGroupName);
1473     }
1474     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1475     {
1476         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1477     }
1478     RpcEndExcept;
1479 
1480     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1481     {
1482         if (InfoLevel == SC_ENUM_PROCESS_INFO)
1483         {
1484             for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1485             {
1486                 if (lpStatusPtr->lpServiceName)
1487                     lpStatusPtr->lpServiceName =
1488                         (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1489 
1490                 if (lpStatusPtr->lpDisplayName)
1491                     lpStatusPtr->lpDisplayName =
1492                         (LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1493 
1494                 lpStatusPtr++;
1495             }
1496         }
1497     }
1498 
1499     if (dwError != ERROR_SUCCESS)
1500     {
1501         TRACE("REnumServicesStatusExA() failed (Error %lu)\n", dwError);
1502         SetLastError(dwError);
1503         return FALSE;
1504     }
1505 
1506     TRACE("EnumServicesStatusExA() done\n");
1507 
1508     return TRUE;
1509 }
1510 
1511 
1512 /**********************************************************************
1513  *  EnumServicesStatusExW
1514  *
1515  * @implemented
1516  */
1517 BOOL WINAPI
1518 EnumServicesStatusExW(SC_HANDLE hSCManager,
1519                       SC_ENUM_TYPE InfoLevel,
1520                       DWORD dwServiceType,
1521                       DWORD dwServiceState,
1522                       LPBYTE lpServices,
1523                       DWORD cbBufSize,
1524                       LPDWORD pcbBytesNeeded,
1525                       LPDWORD lpServicesReturned,
1526                       LPDWORD lpResumeHandle,
1527                       LPCWSTR pszGroupName)
1528 {
1529     ENUM_SERVICE_STATUS_PROCESSW ServiceStatus;
1530     LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
1531     DWORD dwBufferSize;
1532     DWORD dwError;
1533     DWORD dwCount;
1534 
1535     TRACE("EnumServicesStatusExW(%p %lu %lu %p %lu %p %p %p %s)\n",
1536           hSCManager, dwServiceType, dwServiceState, lpServices,
1537           cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle,
1538           debugstr_w(pszGroupName));
1539 
1540     if (InfoLevel != SC_ENUM_PROCESS_INFO)
1541     {
1542         SetLastError(ERROR_INVALID_LEVEL);
1543         return FALSE;
1544     }
1545 
1546     if (!hSCManager)
1547     {
1548         SetLastError(ERROR_INVALID_HANDLE);
1549         return FALSE;
1550     }
1551 
1552     if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
1553     {
1554         SetLastError(ERROR_INVALID_ADDRESS);
1555         return FALSE;
1556     }
1557 
1558     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSW))
1559     {
1560         lpStatusPtr = &ServiceStatus;
1561         dwBufferSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1562     }
1563     else
1564     {
1565         lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpServices;
1566         dwBufferSize = cbBufSize;
1567     }
1568 
1569     RpcTryExcept
1570     {
1571         dwError = REnumServicesStatusExW((SC_RPC_HANDLE)hSCManager,
1572                                          InfoLevel,
1573                                          dwServiceType,
1574                                          dwServiceState,
1575                                          (LPBYTE)lpStatusPtr,
1576                                          dwBufferSize,
1577                                          pcbBytesNeeded,
1578                                          lpServicesReturned,
1579                                          lpResumeHandle,
1580                                          (LPWSTR)pszGroupName);
1581     }
1582     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1583     {
1584         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1585     }
1586     RpcEndExcept;
1587 
1588     if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
1589     {
1590         if (InfoLevel == SC_ENUM_PROCESS_INFO)
1591         {
1592             for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
1593             {
1594                 if (lpStatusPtr->lpServiceName)
1595                     lpStatusPtr->lpServiceName =
1596                         (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
1597 
1598                 if (lpStatusPtr->lpDisplayName)
1599                     lpStatusPtr->lpDisplayName =
1600                         (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
1601 
1602                 lpStatusPtr++;
1603             }
1604         }
1605     }
1606 
1607     if (dwError != ERROR_SUCCESS)
1608     {
1609         TRACE("REnumServicesStatusExW() failed (Error %lu)\n", dwError);
1610         SetLastError(dwError);
1611         return FALSE;
1612     }
1613 
1614     TRACE("EnumServicesStatusExW() done\n");
1615 
1616     return TRUE;
1617 }
1618 
1619 
1620 /**********************************************************************
1621  *  GetServiceDisplayNameA
1622  *
1623  * @implemented
1624  */
1625 BOOL WINAPI
1626 GetServiceDisplayNameA(SC_HANDLE hSCManager,
1627                        LPCSTR lpServiceName,
1628                        LPSTR lpDisplayName,
1629                        LPDWORD lpcchBuffer)
1630 {
1631     DWORD dwError;
1632     LPSTR lpNameBuffer;
1633     CHAR szEmptyName[] = "";
1634 
1635     TRACE("GetServiceDisplayNameA(%p %s %p %p)\n",
1636           hSCManager, debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1637 
1638     if (!hSCManager)
1639     {
1640         SetLastError(ERROR_INVALID_HANDLE);
1641         return FALSE;
1642     }
1643 
1644     if (!lpDisplayName || *lpcchBuffer < sizeof(CHAR))
1645     {
1646         lpNameBuffer = szEmptyName;
1647         *lpcchBuffer = sizeof(CHAR);
1648     }
1649     else
1650     {
1651         lpNameBuffer = lpDisplayName;
1652     }
1653 
1654     RpcTryExcept
1655     {
1656         dwError = RGetServiceDisplayNameA((SC_RPC_HANDLE)hSCManager,
1657                                           lpServiceName,
1658                                           lpNameBuffer,
1659                                           lpcchBuffer);
1660     }
1661     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1662     {
1663         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1664     }
1665     RpcEndExcept;
1666 
1667     if (dwError != ERROR_SUCCESS)
1668     {
1669         TRACE("RGetServiceDisplayNameA() failed (Error %lu)\n", dwError);
1670         SetLastError(dwError);
1671         return FALSE;
1672     }
1673 
1674     return TRUE;
1675 }
1676 
1677 
1678 /**********************************************************************
1679  *  GetServiceDisplayNameW
1680  *
1681  * @implemented
1682  */
1683 BOOL WINAPI
1684 GetServiceDisplayNameW(SC_HANDLE hSCManager,
1685                        LPCWSTR lpServiceName,
1686                        LPWSTR lpDisplayName,
1687                        LPDWORD lpcchBuffer)
1688 {
1689     DWORD dwError;
1690     LPWSTR lpNameBuffer;
1691     WCHAR szEmptyName[] = L"";
1692 
1693     TRACE("GetServiceDisplayNameW(%p %s %p %p)\n",
1694           hSCManager, debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1695 
1696     if (!hSCManager)
1697     {
1698         SetLastError(ERROR_INVALID_HANDLE);
1699         return FALSE;
1700     }
1701 
1702     /*
1703      * NOTE: A size of 1 character would be enough, but tests show that
1704      * Windows returns 2 characters instead, certainly due to a WCHAR/bytes
1705      * mismatch in their code.
1706      */
1707     if (!lpDisplayName || *lpcchBuffer < sizeof(WCHAR))
1708     {
1709         lpNameBuffer = szEmptyName;
1710         *lpcchBuffer = sizeof(WCHAR);
1711     }
1712     else
1713     {
1714         lpNameBuffer = lpDisplayName;
1715     }
1716 
1717     RpcTryExcept
1718     {
1719         dwError = RGetServiceDisplayNameW((SC_RPC_HANDLE)hSCManager,
1720                                           lpServiceName,
1721                                           lpNameBuffer,
1722                                           lpcchBuffer);
1723     }
1724     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1725     {
1726         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1727     }
1728     RpcEndExcept;
1729 
1730     if (dwError != ERROR_SUCCESS)
1731     {
1732         TRACE("RGetServiceDisplayNameW() failed (Error %lu)\n", dwError);
1733         SetLastError(dwError);
1734         return FALSE;
1735     }
1736 
1737     return TRUE;
1738 }
1739 
1740 
1741 /**********************************************************************
1742  *  GetServiceKeyNameA
1743  *
1744  * @implemented
1745  */
1746 BOOL WINAPI
1747 GetServiceKeyNameA(SC_HANDLE hSCManager,
1748                    LPCSTR lpDisplayName,
1749                    LPSTR lpServiceName,
1750                    LPDWORD lpcchBuffer)
1751 {
1752     DWORD dwError;
1753     LPSTR lpNameBuffer;
1754     CHAR szEmptyName[] = "";
1755 
1756     TRACE("GetServiceKeyNameA(%p %s %p %p)\n",
1757           hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1758 
1759     if (!hSCManager)
1760     {
1761         SetLastError(ERROR_INVALID_HANDLE);
1762         return FALSE;
1763     }
1764 
1765     if (!lpServiceName || *lpcchBuffer < sizeof(CHAR))
1766     {
1767         lpNameBuffer = szEmptyName;
1768         *lpcchBuffer = sizeof(CHAR);
1769     }
1770     else
1771     {
1772         lpNameBuffer = lpServiceName;
1773     }
1774 
1775     RpcTryExcept
1776     {
1777         dwError = RGetServiceKeyNameA((SC_RPC_HANDLE)hSCManager,
1778                                       lpDisplayName,
1779                                       lpNameBuffer,
1780                                       lpcchBuffer);
1781     }
1782     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1783     {
1784         /* HACK: because of a problem with rpcrt4, rpcserver is hacked to return 6 for ERROR_SERVICE_DOES_NOT_EXIST */
1785         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1786     }
1787     RpcEndExcept;
1788 
1789     if (dwError != ERROR_SUCCESS)
1790     {
1791         TRACE("RGetServiceKeyNameA() failed (Error %lu)\n", dwError);
1792         SetLastError(dwError);
1793         return FALSE;
1794     }
1795 
1796     return TRUE;
1797 }
1798 
1799 
1800 /**********************************************************************
1801  *  GetServiceKeyNameW
1802  *
1803  * @implemented
1804  */
1805 BOOL WINAPI
1806 GetServiceKeyNameW(SC_HANDLE hSCManager,
1807                    LPCWSTR lpDisplayName,
1808                    LPWSTR lpServiceName,
1809                    LPDWORD lpcchBuffer)
1810 {
1811     DWORD dwError;
1812     LPWSTR lpNameBuffer;
1813     WCHAR szEmptyName[] = L"";
1814 
1815     TRACE("GetServiceKeyNameW(%p %s %p %p)\n",
1816           hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1817 
1818     if (!hSCManager)
1819     {
1820         SetLastError(ERROR_INVALID_HANDLE);
1821         return FALSE;
1822     }
1823 
1824     /*
1825      * NOTE: A size of 1 character would be enough, but tests show that
1826      * Windows returns 2 characters instead, certainly due to a WCHAR/bytes
1827      * mismatch in their code.
1828      */
1829     if (!lpServiceName || *lpcchBuffer < sizeof(WCHAR))
1830     {
1831         lpNameBuffer = szEmptyName;
1832         *lpcchBuffer = sizeof(WCHAR);
1833     }
1834     else
1835     {
1836         lpNameBuffer = lpServiceName;
1837     }
1838 
1839     RpcTryExcept
1840     {
1841         dwError = RGetServiceKeyNameW((SC_RPC_HANDLE)hSCManager,
1842                                       lpDisplayName,
1843                                       lpNameBuffer,
1844                                       lpcchBuffer);
1845     }
1846     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1847     {
1848         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1849     }
1850     RpcEndExcept;
1851 
1852     if (dwError != ERROR_SUCCESS)
1853     {
1854         TRACE("RGetServiceKeyNameW() failed (Error %lu)\n", dwError);
1855         SetLastError(dwError);
1856         return FALSE;
1857     }
1858 
1859     return TRUE;
1860 }
1861 
1862 
1863 /**********************************************************************
1864  *  I_ScGetCurrentGroupStateW
1865  *
1866  * @implemented
1867  */
1868 DWORD WINAPI
1869 I_ScGetCurrentGroupStateW(SC_HANDLE hSCManager,
1870                           LPWSTR pszGroupName,
1871                           LPDWORD pdwGroupState)
1872 {
1873     DWORD dwError;
1874 
1875     TRACE("I_ScGetCurrentGroupStateW(%p %s %p)\n",
1876           hSCManager, debugstr_w(pszGroupName), pdwGroupState);
1877 
1878     RpcTryExcept
1879     {
1880         dwError = RI_ScGetCurrentGroupStateW((SC_RPC_HANDLE)hSCManager,
1881                                              pszGroupName,
1882                                              pdwGroupState);
1883     }
1884     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1885     {
1886         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1887     }
1888     RpcEndExcept
1889 
1890     if (dwError != ERROR_SUCCESS)
1891     {
1892         TRACE("RI_ScGetCurrentGroupStateW() failed (Error %lu)\n", dwError);
1893         SetLastError(dwError);
1894     }
1895 
1896     return dwError;
1897 }
1898 
1899 
1900 /**********************************************************************
1901  *  I_ScValidatePnpService
1902  *
1903  * Undocumented
1904  *
1905  * @implemented
1906  */
1907 DWORD
1908 WINAPI
1909 I_ScValidatePnpService(
1910     _In_ LPCWSTR pszMachineName,
1911     _In_ LPCWSTR pszServiceName,
1912     _Out_ SERVICE_STATUS_HANDLE *phServiceStatus)
1913 {
1914     SC_RPC_HANDLE hSCManager = NULL;
1915     SERVICE_STATUS_HANDLE hServiceStatus = NULL;
1916     DWORD dwError;
1917 
1918     TRACE("I_ScValidatePnpService(%S %S %p)\n",
1919          pszMachineName, pszServiceName, phServiceStatus);
1920 
1921     hSCManager = OpenSCManagerW(pszMachineName,
1922                                 SERVICES_ACTIVE_DATABASEW,
1923                                 SC_MANAGER_CONNECT);
1924     if (hSCManager == NULL)
1925     {
1926         dwError = GetLastError();
1927         goto done;
1928     }
1929 
1930     RpcTryExcept
1931     {
1932         dwError = RI_ScValidatePnPService(hSCManager,
1933                                           (LPWSTR)pszServiceName,
1934                                           (RPC_SERVICE_STATUS_HANDLE *)&hServiceStatus);
1935     }
1936     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1937     {
1938         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1939     }
1940     RpcEndExcept
1941 
1942     *phServiceStatus = hServiceStatus;
1943 
1944 done:
1945     if (hSCManager != NULL)
1946         CloseServiceHandle(hSCManager);
1947 
1948     return dwError;
1949 }
1950 
1951 
1952 /**********************************************************************
1953  *  LockServiceDatabase
1954  *
1955  * @implemented
1956  */
1957 SC_LOCK WINAPI
1958 LockServiceDatabase(SC_HANDLE hSCManager)
1959 {
1960     SC_LOCK hLock;
1961     DWORD dwError;
1962 
1963     TRACE("LockServiceDatabase(%p)\n",
1964           hSCManager);
1965 
1966     RpcTryExcept
1967     {
1968         dwError = RLockServiceDatabase((SC_RPC_HANDLE)hSCManager,
1969                                        (SC_RPC_LOCK *)&hLock);
1970     }
1971     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1972     {
1973         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
1974     }
1975     RpcEndExcept;
1976 
1977     if (dwError != ERROR_SUCCESS)
1978     {
1979         TRACE("RLockServiceDatabase() failed (Error %lu)\n", dwError);
1980         SetLastError(dwError);
1981         return NULL;
1982     }
1983 
1984     TRACE("hLock = %p\n", hLock);
1985 
1986     return hLock;
1987 }
1988 
1989 
1990 static VOID
1991 WaitForSCManager(VOID)
1992 {
1993     HANDLE hEvent;
1994 
1995     TRACE("WaitForSCManager()\n");
1996 
1997     /* Try to open the existing event */
1998     hEvent = OpenEventW(SYNCHRONIZE, FALSE, SCM_START_EVENT);
1999     if (hEvent == NULL)
2000     {
2001         if (GetLastError() != ERROR_FILE_NOT_FOUND)
2002             return;
2003 
2004         /* Try to create a new event */
2005         hEvent = CreateEventW(NULL, TRUE, FALSE, SCM_START_EVENT);
2006         if (hEvent == NULL)
2007             return;
2008     }
2009 
2010     /* Wait for 3 minutes */
2011     WaitForSingleObject(hEvent, 180000);
2012     CloseHandle(hEvent);
2013 
2014     TRACE("ScmWaitForSCManager() done\n");
2015 }
2016 
2017 
2018 /**********************************************************************
2019  *  OpenSCManagerA
2020  *
2021  * @implemented
2022  */
2023 SC_HANDLE WINAPI
2024 OpenSCManagerA(LPCSTR lpMachineName,
2025                LPCSTR lpDatabaseName,
2026                DWORD dwDesiredAccess)
2027 {
2028     SC_HANDLE hScm = NULL;
2029     DWORD dwError;
2030 
2031     TRACE("OpenSCManagerA(%s %s %lx)\n",
2032           debugstr_a(lpMachineName), debugstr_a(lpDatabaseName), dwDesiredAccess);
2033 
2034     WaitForSCManager();
2035 
2036     RpcTryExcept
2037     {
2038         dwError = ROpenSCManagerA((LPSTR)lpMachineName,
2039                                   (LPSTR)lpDatabaseName,
2040                                   dwDesiredAccess,
2041                                   (SC_RPC_HANDLE *)&hScm);
2042     }
2043     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2044     {
2045         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2046     }
2047     RpcEndExcept;
2048 
2049     SetLastError(dwError);
2050     if (dwError != ERROR_SUCCESS)
2051     {
2052         TRACE("ROpenSCManagerA() failed (Error %lu)\n", dwError);
2053         return NULL;
2054     }
2055 
2056     TRACE("hScm = %p\n", hScm);
2057 
2058     return hScm;
2059 }
2060 
2061 
2062 /**********************************************************************
2063  *  OpenSCManagerW
2064  *
2065  * @implemented
2066  */
2067 SC_HANDLE WINAPI
2068 OpenSCManagerW(LPCWSTR lpMachineName,
2069                LPCWSTR lpDatabaseName,
2070                DWORD dwDesiredAccess)
2071 {
2072     SC_HANDLE hScm = NULL;
2073     DWORD dwError;
2074 
2075     TRACE("OpenSCManagerW(%s %s %lx)\n",
2076           debugstr_w(lpMachineName), debugstr_w(lpDatabaseName), dwDesiredAccess);
2077 
2078     WaitForSCManager();
2079 
2080     RpcTryExcept
2081     {
2082         dwError = ROpenSCManagerW((LPWSTR)lpMachineName,
2083                                   (LPWSTR)lpDatabaseName,
2084                                   dwDesiredAccess,
2085                                   (SC_RPC_HANDLE *)&hScm);
2086     }
2087     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2088     {
2089         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2090     }
2091     RpcEndExcept;
2092 
2093     SetLastError(dwError);
2094     if (dwError != ERROR_SUCCESS)
2095     {
2096         TRACE("ROpenSCManagerW() failed (Error %lu)\n", dwError);
2097         return NULL;
2098     }
2099 
2100     TRACE("hScm = %p\n", hScm);
2101 
2102     return hScm;
2103 }
2104 
2105 
2106 /**********************************************************************
2107  *  OpenServiceA
2108  *
2109  * @implemented
2110  */
2111 SC_HANDLE WINAPI
2112 OpenServiceA(SC_HANDLE hSCManager,
2113              LPCSTR lpServiceName,
2114              DWORD dwDesiredAccess)
2115 {
2116     SC_HANDLE hService = NULL;
2117     DWORD dwError;
2118 
2119     TRACE("OpenServiceA(%p %s %lx)\n",
2120            hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
2121 
2122     if (!hSCManager)
2123     {
2124         SetLastError(ERROR_INVALID_HANDLE);
2125         return NULL;
2126     }
2127 
2128     RpcTryExcept
2129     {
2130         dwError = ROpenServiceA((SC_RPC_HANDLE)hSCManager,
2131                                 (LPSTR)lpServiceName,
2132                                 dwDesiredAccess,
2133                                 (SC_RPC_HANDLE *)&hService);
2134     }
2135     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2136     {
2137         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2138     }
2139     RpcEndExcept;
2140 
2141     SetLastError(dwError);
2142     if (dwError != ERROR_SUCCESS)
2143     {
2144         TRACE("ROpenServiceA() failed (Error %lu)\n", dwError);
2145         return NULL;
2146     }
2147 
2148     TRACE("hService = %p\n", hService);
2149 
2150     return hService;
2151 }
2152 
2153 
2154 /**********************************************************************
2155  *  OpenServiceW
2156  *
2157  * @implemented
2158  */
2159 SC_HANDLE WINAPI
2160 OpenServiceW(SC_HANDLE hSCManager,
2161              LPCWSTR lpServiceName,
2162              DWORD dwDesiredAccess)
2163 {
2164     SC_HANDLE hService = NULL;
2165     DWORD dwError;
2166 
2167     TRACE("OpenServiceW(%p %s %lx)\n",
2168            hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
2169 
2170     if (!hSCManager)
2171     {
2172         SetLastError(ERROR_INVALID_HANDLE);
2173         return NULL;
2174     }
2175 
2176     RpcTryExcept
2177     {
2178         dwError = ROpenServiceW((SC_RPC_HANDLE)hSCManager,
2179                                 (LPWSTR)lpServiceName,
2180                                 dwDesiredAccess,
2181                                 (SC_RPC_HANDLE *)&hService);
2182     }
2183     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2184     {
2185         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2186     }
2187     RpcEndExcept;
2188 
2189     SetLastError(dwError);
2190     if (dwError != ERROR_SUCCESS)
2191     {
2192         TRACE("ROpenServiceW() failed (Error %lu)\n", dwError);
2193         return NULL;
2194     }
2195 
2196     TRACE("hService = %p\n", hService);
2197 
2198     return hService;
2199 }
2200 
2201 
2202 /**********************************************************************
2203  *  QueryServiceConfigA
2204  *
2205  * @implemented
2206  */
2207 BOOL WINAPI
2208 QueryServiceConfigA(SC_HANDLE hService,
2209                     LPQUERY_SERVICE_CONFIGA lpServiceConfig,
2210                     DWORD cbBufSize,
2211                     LPDWORD pcbBytesNeeded)
2212 {
2213     QUERY_SERVICE_CONFIGA ServiceConfig;
2214     LPQUERY_SERVICE_CONFIGA lpConfigPtr;
2215     DWORD dwBufferSize;
2216     DWORD dwError;
2217 
2218     TRACE("QueryServiceConfigA(%p %p %lu %p)\n",
2219            hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
2220 
2221     if (lpServiceConfig == NULL ||
2222         cbBufSize < sizeof(QUERY_SERVICE_CONFIGA))
2223     {
2224         lpConfigPtr = &ServiceConfig;
2225         dwBufferSize = sizeof(QUERY_SERVICE_CONFIGA);
2226     }
2227     else
2228     {
2229         lpConfigPtr = lpServiceConfig;
2230         dwBufferSize = cbBufSize;
2231     }
2232 
2233     RpcTryExcept
2234     {
2235         dwError = RQueryServiceConfigA((SC_RPC_HANDLE)hService,
2236                                        (LPBYTE)lpConfigPtr,
2237                                        dwBufferSize,
2238                                        pcbBytesNeeded);
2239     }
2240     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2241     {
2242         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2243     }
2244     RpcEndExcept;
2245 
2246     if (dwError != ERROR_SUCCESS)
2247     {
2248         TRACE("RQueryServiceConfigA() failed (Error %lu)\n", dwError);
2249         SetLastError(dwError);
2250         return FALSE;
2251     }
2252 
2253     /* Adjust the pointers */
2254     if (lpConfigPtr->lpBinaryPathName)
2255         lpConfigPtr->lpBinaryPathName =
2256             (LPSTR)((ULONG_PTR)lpConfigPtr +
2257                     (ULONG_PTR)lpConfigPtr->lpBinaryPathName);
2258 
2259     if (lpConfigPtr->lpLoadOrderGroup)
2260         lpConfigPtr->lpLoadOrderGroup =
2261             (LPSTR)((ULONG_PTR)lpConfigPtr +
2262                     (ULONG_PTR)lpConfigPtr->lpLoadOrderGroup);
2263 
2264     if (lpConfigPtr->lpDependencies)
2265         lpConfigPtr->lpDependencies =
2266             (LPSTR)((ULONG_PTR)lpConfigPtr +
2267                     (ULONG_PTR)lpConfigPtr->lpDependencies);
2268 
2269     if (lpConfigPtr->lpServiceStartName)
2270         lpConfigPtr->lpServiceStartName =
2271             (LPSTR)((ULONG_PTR)lpConfigPtr +
2272                     (ULONG_PTR)lpConfigPtr->lpServiceStartName);
2273 
2274     if (lpConfigPtr->lpDisplayName)
2275         lpConfigPtr->lpDisplayName =
2276            (LPSTR)((ULONG_PTR)lpConfigPtr +
2277                    (ULONG_PTR)lpConfigPtr->lpDisplayName);
2278 
2279     TRACE("QueryServiceConfigA() done\n");
2280 
2281     return TRUE;
2282 }
2283 
2284 
2285 /**********************************************************************
2286  *  QueryServiceConfigW
2287  *
2288  * @implemented
2289  */
2290 BOOL WINAPI
2291 QueryServiceConfigW(SC_HANDLE hService,
2292                     LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2293                     DWORD cbBufSize,
2294                     LPDWORD pcbBytesNeeded)
2295 {
2296     QUERY_SERVICE_CONFIGW ServiceConfig;
2297     LPQUERY_SERVICE_CONFIGW lpConfigPtr;
2298     DWORD dwBufferSize;
2299     DWORD dwError;
2300 
2301     TRACE("QueryServiceConfigW(%p %p %lu %p)\n",
2302            hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
2303 
2304     if (lpServiceConfig == NULL ||
2305         cbBufSize < sizeof(QUERY_SERVICE_CONFIGW))
2306     {
2307         lpConfigPtr = &ServiceConfig;
2308         dwBufferSize = sizeof(QUERY_SERVICE_CONFIGW);
2309     }
2310     else
2311     {
2312         lpConfigPtr = lpServiceConfig;
2313         dwBufferSize = cbBufSize;
2314     }
2315 
2316     RpcTryExcept
2317     {
2318         dwError = RQueryServiceConfigW((SC_RPC_HANDLE)hService,
2319                                        (LPBYTE)lpConfigPtr,
2320                                        dwBufferSize,
2321                                        pcbBytesNeeded);
2322     }
2323     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2324     {
2325         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2326     }
2327     RpcEndExcept;
2328 
2329     if (dwError != ERROR_SUCCESS)
2330     {
2331         TRACE("RQueryServiceConfigW() failed (Error %lu)\n", dwError);
2332         SetLastError(dwError);
2333         return FALSE;
2334     }
2335 
2336     /* Adjust the pointers */
2337     if (lpConfigPtr->lpBinaryPathName)
2338         lpConfigPtr->lpBinaryPathName =
2339             (LPWSTR)((ULONG_PTR)lpConfigPtr +
2340                      (ULONG_PTR)lpConfigPtr->lpBinaryPathName);
2341 
2342     if (lpConfigPtr->lpLoadOrderGroup)
2343         lpConfigPtr->lpLoadOrderGroup =
2344             (LPWSTR)((ULONG_PTR)lpConfigPtr +
2345                      (ULONG_PTR)lpConfigPtr->lpLoadOrderGroup);
2346 
2347     if (lpConfigPtr->lpDependencies)
2348         lpConfigPtr->lpDependencies =
2349             (LPWSTR)((ULONG_PTR)lpConfigPtr +
2350                      (ULONG_PTR)lpConfigPtr->lpDependencies);
2351 
2352     if (lpConfigPtr->lpServiceStartName)
2353         lpConfigPtr->lpServiceStartName =
2354             (LPWSTR)((ULONG_PTR)lpConfigPtr +
2355                      (ULONG_PTR)lpConfigPtr->lpServiceStartName);
2356 
2357     if (lpConfigPtr->lpDisplayName)
2358         lpConfigPtr->lpDisplayName =
2359            (LPWSTR)((ULONG_PTR)lpConfigPtr +
2360                     (ULONG_PTR)lpConfigPtr->lpDisplayName);
2361 
2362     TRACE("QueryServiceConfigW() done\n");
2363 
2364     return TRUE;
2365 }
2366 
2367 
2368 /**********************************************************************
2369  *  QueryServiceConfig2A
2370  *
2371  * @implemented
2372  */
2373 BOOL WINAPI
2374 QueryServiceConfig2A(SC_HANDLE hService,
2375                      DWORD dwInfoLevel,
2376                      LPBYTE lpBuffer,
2377                      DWORD cbBufSize,
2378                      LPDWORD pcbBytesNeeded)
2379 {
2380     SERVICE_DESCRIPTIONA ServiceDescription;
2381     SERVICE_FAILURE_ACTIONSA ServiceFailureActions;
2382     LPBYTE lpTempBuffer;
2383     BOOL bUseTempBuffer = FALSE;
2384     DWORD dwBufferSize;
2385     DWORD dwError;
2386 
2387     TRACE("QueryServiceConfig2A(%p %lu %p %lu %p)\n",
2388           hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
2389 
2390     lpTempBuffer = lpBuffer;
2391     dwBufferSize = cbBufSize;
2392 
2393     switch (dwInfoLevel)
2394     {
2395         case SERVICE_CONFIG_DESCRIPTION:
2396             if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_DESCRIPTIONA)))
2397             {
2398                 lpTempBuffer = (LPBYTE)&ServiceDescription;
2399                 dwBufferSize = sizeof(SERVICE_DESCRIPTIONA);
2400                 bUseTempBuffer = TRUE;
2401             }
2402             break;
2403 
2404         case SERVICE_CONFIG_FAILURE_ACTIONS:
2405             if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONSA)))
2406             {
2407                 lpTempBuffer = (LPBYTE)&ServiceFailureActions;
2408                 dwBufferSize = sizeof(SERVICE_FAILURE_ACTIONSA);
2409                 bUseTempBuffer = TRUE;
2410             }
2411             break;
2412 
2413         default:
2414             WARN("Unknown info level 0x%lx\n", dwInfoLevel);
2415             SetLastError(ERROR_INVALID_LEVEL);
2416             return FALSE;
2417     }
2418 
2419     RpcTryExcept
2420     {
2421         dwError = RQueryServiceConfig2A((SC_RPC_HANDLE)hService,
2422                                         dwInfoLevel,
2423                                         lpTempBuffer,
2424                                         dwBufferSize,
2425                                         pcbBytesNeeded);
2426     }
2427     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2428     {
2429         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2430     }
2431     RpcEndExcept;
2432 
2433     if (dwError != ERROR_SUCCESS)
2434     {
2435         TRACE("RQueryServiceConfig2A() failed (Error %lu)\n", dwError);
2436         SetLastError(dwError);
2437         return FALSE;
2438     }
2439 
2440     if (bUseTempBuffer != FALSE)
2441     {
2442         TRACE("RQueryServiceConfig2A() returns ERROR_INSUFFICIENT_BUFFER\n");
2443         *pcbBytesNeeded = dwBufferSize;
2444         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2445         return FALSE;
2446     }
2447 
2448     switch (dwInfoLevel)
2449     {
2450         case SERVICE_CONFIG_DESCRIPTION:
2451             {
2452                 LPSERVICE_DESCRIPTIONA lpPtr = (LPSERVICE_DESCRIPTIONA)lpTempBuffer;
2453 
2454                 if (lpPtr->lpDescription != NULL)
2455                     lpPtr->lpDescription =
2456                         (LPSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpDescription);
2457             }
2458             break;
2459 
2460         case SERVICE_CONFIG_FAILURE_ACTIONS:
2461             {
2462                 LPSERVICE_FAILURE_ACTIONSA lpPtr = (LPSERVICE_FAILURE_ACTIONSA)lpTempBuffer;
2463 
2464                 if (lpPtr->lpRebootMsg != NULL)
2465                     lpPtr->lpRebootMsg =
2466                         (LPSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpRebootMsg);
2467 
2468                 if (lpPtr->lpCommand != NULL)
2469                     lpPtr->lpCommand =
2470                         (LPSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpCommand);
2471 
2472                 if (lpPtr->lpsaActions != NULL)
2473                     lpPtr->lpsaActions =
2474                         (LPSC_ACTION)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpsaActions);
2475             }
2476             break;
2477     }
2478 
2479     TRACE("QueryServiceConfig2A() done\n");
2480 
2481     return TRUE;
2482 }
2483 
2484 
2485 /**********************************************************************
2486  *  QueryServiceConfig2W
2487  *
2488  * @implemented
2489  */
2490 BOOL WINAPI
2491 QueryServiceConfig2W(SC_HANDLE hService,
2492                      DWORD dwInfoLevel,
2493                      LPBYTE lpBuffer,
2494                      DWORD cbBufSize,
2495                      LPDWORD pcbBytesNeeded)
2496 {
2497     SERVICE_DESCRIPTIONW ServiceDescription;
2498     SERVICE_FAILURE_ACTIONSW ServiceFailureActions;
2499     LPBYTE lpTempBuffer;
2500     BOOL bUseTempBuffer = FALSE;
2501     DWORD dwBufferSize;
2502     DWORD dwError;
2503 
2504     TRACE("QueryServiceConfig2W(%p %lu %p %lu %p)\n",
2505           hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
2506 
2507     lpTempBuffer = lpBuffer;
2508     dwBufferSize = cbBufSize;
2509 
2510     switch (dwInfoLevel)
2511     {
2512         case SERVICE_CONFIG_DESCRIPTION:
2513             if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_DESCRIPTIONW)))
2514             {
2515                 lpTempBuffer = (LPBYTE)&ServiceDescription;
2516                 dwBufferSize = sizeof(SERVICE_DESCRIPTIONW);
2517                 bUseTempBuffer = TRUE;
2518             }
2519             break;
2520 
2521         case SERVICE_CONFIG_FAILURE_ACTIONS:
2522             if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONSW)))
2523             {
2524                 lpTempBuffer = (LPBYTE)&ServiceFailureActions;
2525                 dwBufferSize = sizeof(SERVICE_FAILURE_ACTIONSW);
2526                 bUseTempBuffer = TRUE;
2527             }
2528             break;
2529 
2530         default:
2531             WARN("Unknown info level 0x%lx\n", dwInfoLevel);
2532             SetLastError(ERROR_INVALID_LEVEL);
2533             return FALSE;
2534     }
2535 
2536     RpcTryExcept
2537     {
2538         dwError = RQueryServiceConfig2W((SC_RPC_HANDLE)hService,
2539                                         dwInfoLevel,
2540                                         lpTempBuffer,
2541                                         dwBufferSize,
2542                                         pcbBytesNeeded);
2543     }
2544     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2545     {
2546         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2547     }
2548     RpcEndExcept;
2549 
2550     if (dwError != ERROR_SUCCESS)
2551     {
2552         TRACE("RQueryServiceConfig2W() failed (Error %lu)\n", dwError);
2553         SetLastError(dwError);
2554         return FALSE;
2555     }
2556 
2557     if (bUseTempBuffer != FALSE)
2558     {
2559         TRACE("RQueryServiceConfig2W() returns ERROR_INSUFFICIENT_BUFFER\n");
2560         *pcbBytesNeeded = dwBufferSize;
2561         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2562         return FALSE;
2563     }
2564 
2565     switch (dwInfoLevel)
2566     {
2567         case SERVICE_CONFIG_DESCRIPTION:
2568             {
2569                 LPSERVICE_DESCRIPTIONW lpPtr = (LPSERVICE_DESCRIPTIONW)lpTempBuffer;
2570 
2571                 if (lpPtr->lpDescription != NULL)
2572                     lpPtr->lpDescription =
2573                         (LPWSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpDescription);
2574             }
2575             break;
2576 
2577         case SERVICE_CONFIG_FAILURE_ACTIONS:
2578             {
2579                 LPSERVICE_FAILURE_ACTIONSW lpPtr = (LPSERVICE_FAILURE_ACTIONSW)lpTempBuffer;
2580 
2581                 if (lpPtr->lpRebootMsg != NULL)
2582                     lpPtr->lpRebootMsg =
2583                         (LPWSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpRebootMsg);
2584 
2585                 if (lpPtr->lpCommand != NULL)
2586                     lpPtr->lpCommand =
2587                         (LPWSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpCommand);
2588 
2589                 if (lpPtr->lpsaActions != NULL)
2590                     lpPtr->lpsaActions =
2591                         (LPSC_ACTION)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpsaActions);
2592             }
2593             break;
2594     }
2595 
2596     TRACE("QueryServiceConfig2W() done\n");
2597 
2598     return TRUE;
2599 }
2600 
2601 
2602 /**********************************************************************
2603  *  QueryServiceLockStatusA
2604  *
2605  * @implemented
2606  */
2607 BOOL WINAPI
2608 QueryServiceLockStatusA(SC_HANDLE hSCManager,
2609                         LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2610                         DWORD cbBufSize,
2611                         LPDWORD pcbBytesNeeded)
2612 {
2613     QUERY_SERVICE_LOCK_STATUSA LockStatus;
2614     LPQUERY_SERVICE_LOCK_STATUSA lpStatusPtr;
2615     DWORD dwBufferSize;
2616     DWORD dwError;
2617 
2618     TRACE("QueryServiceLockStatusA(%p %p %lu %p)\n",
2619           hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2620 
2621     if (lpLockStatus == NULL || cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSA))
2622     {
2623         lpStatusPtr = &LockStatus;
2624         dwBufferSize = sizeof(QUERY_SERVICE_LOCK_STATUSA);
2625     }
2626     else
2627     {
2628         lpStatusPtr = lpLockStatus;
2629         dwBufferSize = cbBufSize;
2630     }
2631 
2632     RpcTryExcept
2633     {
2634         dwError = RQueryServiceLockStatusA((SC_RPC_HANDLE)hSCManager,
2635                                            (LPBYTE)lpStatusPtr,
2636                                            dwBufferSize,
2637                                            pcbBytesNeeded);
2638     }
2639     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2640     {
2641         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2642     }
2643     RpcEndExcept;
2644 
2645     if (dwError != ERROR_SUCCESS)
2646     {
2647         TRACE("RQueryServiceLockStatusA() failed (Error %lu)\n", dwError);
2648         SetLastError(dwError);
2649         return FALSE;
2650     }
2651 
2652     if (lpStatusPtr->lpLockOwner != NULL)
2653     {
2654         lpStatusPtr->lpLockOwner =
2655             (LPSTR)((ULONG_PTR)lpStatusPtr + (ULONG_PTR)lpStatusPtr->lpLockOwner);
2656     }
2657 
2658     TRACE("QueryServiceLockStatusA() done\n");
2659 
2660     return TRUE;
2661 }
2662 
2663 
2664 /**********************************************************************
2665  *  QueryServiceLockStatusW
2666  *
2667  * @implemented
2668  */
2669 BOOL WINAPI
2670 QueryServiceLockStatusW(SC_HANDLE hSCManager,
2671                         LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2672                         DWORD cbBufSize,
2673                         LPDWORD pcbBytesNeeded)
2674 {
2675     QUERY_SERVICE_LOCK_STATUSW LockStatus;
2676     LPQUERY_SERVICE_LOCK_STATUSW lpStatusPtr;
2677     DWORD dwBufferSize;
2678     DWORD dwError;
2679 
2680     TRACE("QueryServiceLockStatusW(%p %p %lu %p)\n",
2681           hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2682 
2683     if (lpLockStatus == NULL || cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSW))
2684     {
2685         lpStatusPtr = &LockStatus;
2686         dwBufferSize = sizeof(QUERY_SERVICE_LOCK_STATUSW);
2687     }
2688     else
2689     {
2690         lpStatusPtr = lpLockStatus;
2691         dwBufferSize = cbBufSize;
2692     }
2693 
2694     RpcTryExcept
2695     {
2696         dwError = RQueryServiceLockStatusW((SC_RPC_HANDLE)hSCManager,
2697                                            (LPBYTE)lpStatusPtr,
2698                                            dwBufferSize,
2699                                            pcbBytesNeeded);
2700     }
2701     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2702     {
2703         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2704     }
2705     RpcEndExcept;
2706 
2707     if (dwError != ERROR_SUCCESS)
2708     {
2709         TRACE("RQueryServiceLockStatusW() failed (Error %lu)\n", dwError);
2710         SetLastError(dwError);
2711         return FALSE;
2712     }
2713 
2714     if (lpStatusPtr->lpLockOwner != NULL)
2715     {
2716         lpStatusPtr->lpLockOwner =
2717             (LPWSTR)((ULONG_PTR)lpStatusPtr + (ULONG_PTR)lpStatusPtr->lpLockOwner);
2718     }
2719 
2720     TRACE("QueryServiceLockStatusW() done\n");
2721 
2722     return TRUE;
2723 }
2724 
2725 
2726 /**********************************************************************
2727  *  QueryServiceObjectSecurity
2728  *
2729  * @implemented
2730  */
2731 BOOL WINAPI
2732 QueryServiceObjectSecurity(SC_HANDLE hService,
2733                            SECURITY_INFORMATION dwSecurityInformation,
2734                            PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2735                            DWORD cbBufSize,
2736                            LPDWORD pcbBytesNeeded)
2737 {
2738     DWORD dwError;
2739 
2740     TRACE("QueryServiceObjectSecurity(%p %lu %p)\n",
2741            hService, dwSecurityInformation, lpSecurityDescriptor);
2742 
2743     RpcTryExcept
2744     {
2745         dwError = RQueryServiceObjectSecurity((SC_RPC_HANDLE)hService,
2746                                               dwSecurityInformation,
2747                                               (LPBYTE)lpSecurityDescriptor,
2748                                               cbBufSize,
2749                                               pcbBytesNeeded);
2750     }
2751     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2752     {
2753         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2754     }
2755     RpcEndExcept;
2756 
2757     if (dwError != ERROR_SUCCESS)
2758     {
2759         TRACE("QueryServiceObjectSecurity() failed (Error %lu)\n", dwError);
2760         SetLastError(dwError);
2761         return FALSE;
2762     }
2763 
2764     return TRUE;
2765 }
2766 
2767 
2768 /**********************************************************************
2769  *  SetServiceObjectSecurity
2770  *
2771  * @implemented
2772  */
2773 BOOL WINAPI
2774 SetServiceObjectSecurity(SC_HANDLE hService,
2775                          SECURITY_INFORMATION dwSecurityInformation,
2776                          PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2777 {
2778     PSECURITY_DESCRIPTOR SelfRelativeSD = NULL;
2779     ULONG Length;
2780     NTSTATUS Status;
2781     DWORD dwError;
2782 
2783     TRACE("SetServiceObjectSecurity(%p %lu %p)\n",
2784           hService, dwSecurityInformation, lpSecurityDescriptor);
2785 
2786     Length = 0;
2787     Status = RtlMakeSelfRelativeSD(lpSecurityDescriptor,
2788                                    SelfRelativeSD,
2789                                    &Length);
2790     if (Status != STATUS_BUFFER_TOO_SMALL)
2791     {
2792         SetLastError(ERROR_INVALID_PARAMETER);
2793         return FALSE;
2794     }
2795 
2796     SelfRelativeSD = HeapAlloc(GetProcessHeap(), 0, Length);
2797     if (SelfRelativeSD == NULL)
2798     {
2799         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2800         return FALSE;
2801     }
2802 
2803     Status = RtlMakeSelfRelativeSD(lpSecurityDescriptor,
2804                                    SelfRelativeSD,
2805                                    &Length);
2806     if (!NT_SUCCESS(Status))
2807     {
2808         HeapFree(GetProcessHeap(), 0, SelfRelativeSD);
2809         SetLastError(RtlNtStatusToDosError(Status));
2810         return FALSE;
2811     }
2812 
2813     RpcTryExcept
2814     {
2815         dwError = RSetServiceObjectSecurity((SC_RPC_HANDLE)hService,
2816                                             dwSecurityInformation,
2817                                             (LPBYTE)SelfRelativeSD,
2818                                             Length);
2819     }
2820     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2821     {
2822         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2823     }
2824     RpcEndExcept;
2825 
2826     HeapFree(GetProcessHeap(), 0, SelfRelativeSD);
2827 
2828     if (dwError != ERROR_SUCCESS)
2829     {
2830         TRACE("RServiceObjectSecurity() failed (Error %lu)\n", dwError);
2831         SetLastError(dwError);
2832         return FALSE;
2833     }
2834 
2835     return TRUE;
2836 }
2837 
2838 
2839 /**********************************************************************
2840  *  QueryServiceStatus
2841  *
2842  * @implemented
2843  */
2844 BOOL WINAPI
2845 QueryServiceStatus(SC_HANDLE hService,
2846                    LPSERVICE_STATUS lpServiceStatus)
2847 {
2848     DWORD dwError;
2849 
2850     TRACE("QueryServiceStatus(%p %p)\n",
2851           hService, lpServiceStatus);
2852 
2853     if (!hService)
2854     {
2855         SetLastError(ERROR_INVALID_HANDLE);
2856         return FALSE;
2857     }
2858 
2859     RpcTryExcept
2860     {
2861         dwError = RQueryServiceStatus((SC_RPC_HANDLE)hService,
2862                                       lpServiceStatus);
2863     }
2864     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2865     {
2866         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2867     }
2868     RpcEndExcept;
2869 
2870     if (dwError != ERROR_SUCCESS)
2871     {
2872         TRACE("RQueryServiceStatus() failed (Error %lu)\n", dwError);
2873         SetLastError(dwError);
2874         return FALSE;
2875     }
2876 
2877     return TRUE;
2878 }
2879 
2880 
2881 /**********************************************************************
2882  *  QueryServiceStatusEx
2883  *
2884  * @implemented
2885  */
2886 BOOL WINAPI
2887 QueryServiceStatusEx(SC_HANDLE hService,
2888                      SC_STATUS_TYPE InfoLevel,
2889                      LPBYTE lpBuffer,
2890                      DWORD cbBufSize,
2891                      LPDWORD pcbBytesNeeded)
2892 {
2893     DWORD dwError;
2894 
2895     TRACE("QueryServiceStatusEx(%p %lu %p %lu %p)\n",
2896           hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
2897 
2898     if (InfoLevel != SC_STATUS_PROCESS_INFO)
2899     {
2900         SetLastError(ERROR_INVALID_LEVEL);
2901         return FALSE;
2902     }
2903 
2904     if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
2905     {
2906         *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
2907         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2908         return FALSE;
2909     }
2910 
2911     RpcTryExcept
2912     {
2913         dwError = RQueryServiceStatusEx((SC_RPC_HANDLE)hService,
2914                                         InfoLevel,
2915                                         lpBuffer,
2916                                         cbBufSize,
2917                                         pcbBytesNeeded);
2918     }
2919     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2920     {
2921         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2922     }
2923     RpcEndExcept;
2924 
2925     if (dwError != ERROR_SUCCESS)
2926     {
2927         TRACE("RQueryServiceStatusEx() failed (Error %lu)\n", dwError);
2928         SetLastError(dwError);
2929         return FALSE;
2930     }
2931 
2932     return TRUE;
2933 }
2934 
2935 
2936 /**********************************************************************
2937  *  StartServiceA
2938  *
2939  * @implemented
2940  */
2941 BOOL WINAPI
2942 StartServiceA(SC_HANDLE hService,
2943               DWORD dwNumServiceArgs,
2944               LPCSTR *lpServiceArgVectors)
2945 {
2946     DWORD dwError;
2947 
2948     TRACE("StartServiceA(%p %lu %p)\n",
2949           hService, dwNumServiceArgs, lpServiceArgVectors);
2950 
2951     RpcTryExcept
2952     {
2953         dwError = RStartServiceA((SC_RPC_HANDLE)hService,
2954                                  dwNumServiceArgs,
2955                                  (LPSTRING_PTRSA)lpServiceArgVectors);
2956     }
2957     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2958     {
2959         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2960     }
2961     RpcEndExcept;
2962 
2963     if (dwError != ERROR_SUCCESS)
2964     {
2965         ERR("RStartServiceA() failed (Error %lu)\n", dwError);
2966         SetLastError(dwError);
2967         return FALSE;
2968     }
2969 
2970     return TRUE;
2971 }
2972 
2973 
2974 /**********************************************************************
2975  *  StartServiceW
2976  *
2977  * @implemented
2978  */
2979 BOOL WINAPI
2980 StartServiceW(SC_HANDLE hService,
2981               DWORD dwNumServiceArgs,
2982               LPCWSTR *lpServiceArgVectors)
2983 {
2984     DWORD dwError;
2985 
2986     TRACE("StartServiceW(%p %lu %p)\n",
2987           hService, dwNumServiceArgs, lpServiceArgVectors);
2988 
2989     RpcTryExcept
2990     {
2991         dwError = RStartServiceW((SC_RPC_HANDLE)hService,
2992                                  dwNumServiceArgs,
2993                                  (LPSTRING_PTRSW)lpServiceArgVectors);
2994     }
2995     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2996     {
2997         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
2998     }
2999     RpcEndExcept;
3000 
3001     if (dwError != ERROR_SUCCESS)
3002     {
3003         ERR("RStartServiceW() failed (Error %lu)\n", dwError);
3004         SetLastError(dwError);
3005         return FALSE;
3006     }
3007 
3008     return TRUE;
3009 }
3010 
3011 
3012 /**********************************************************************
3013  *  UnlockServiceDatabase
3014  *
3015  * @implemented
3016  */
3017 BOOL WINAPI
3018 UnlockServiceDatabase(SC_LOCK ScLock)
3019 {
3020     DWORD dwError;
3021 
3022     TRACE("UnlockServiceDatabase(%x)\n",
3023           ScLock);
3024 
3025     RpcTryExcept
3026     {
3027         dwError = RUnlockServiceDatabase((LPSC_RPC_LOCK)&ScLock);
3028     }
3029     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
3030     {
3031         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
3032     }
3033     RpcEndExcept;
3034 
3035     if (dwError == ERROR_INVALID_HANDLE)
3036         dwError = ERROR_INVALID_SERVICE_LOCK;
3037 
3038     if (dwError != ERROR_SUCCESS)
3039     {
3040         TRACE("RUnlockServiceDatabase() failed (Error %lu)\n", dwError);
3041         SetLastError(dwError);
3042         return FALSE;
3043     }
3044 
3045     return TRUE;
3046 }
3047 
3048 
3049 /**********************************************************************
3050  *  NotifyBootConfigStatus
3051  *
3052  * @implemented
3053  */
3054 BOOL WINAPI
3055 NotifyBootConfigStatus(BOOL BootAcceptable)
3056 {
3057     DWORD dwError;
3058 
3059     TRACE("NotifyBootConfigStatus(%u)\n",
3060           BootAcceptable);
3061 
3062     RpcTryExcept
3063     {
3064         dwError = RNotifyBootConfigStatus(NULL,
3065                                           BootAcceptable);
3066     }
3067     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
3068     {
3069         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
3070     }
3071     RpcEndExcept;
3072 
3073     if (dwError != ERROR_SUCCESS)
3074     {
3075         TRACE("NotifyBootConfigStatus() failed (Error %lu)\n", dwError);
3076         SetLastError(dwError);
3077         return FALSE;
3078     }
3079 
3080     return TRUE;
3081 }
3082 
3083 DWORD
3084 I_ScQueryServiceTagInfo(PVOID Unused,
3085                         TAG_INFO_LEVEL dwInfoLevel,
3086                         PTAG_INFO_NAME_FROM_TAG InOutParams)
3087 {
3088     SC_HANDLE hScm;
3089     DWORD dwError;
3090     PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams;
3091     PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutParams;
3092     LPWSTR lpszName;
3093 
3094     /* We only support one class */
3095     if (dwInfoLevel != TagInfoLevelNameFromTag)
3096     {
3097         return ERROR_RETRY;
3098     }
3099 
3100     /* Validate input structure */
3101     if (InOutParams->InParams.dwPid == 0 || InOutParams->InParams.dwTag == 0)
3102     {
3103         return ERROR_INVALID_PARAMETER;
3104     }
3105 
3106     /* Validate output structure */
3107     if (InOutParams->OutParams.pszName != NULL)
3108     {
3109         return ERROR_INVALID_PARAMETER;
3110     }
3111 
3112     /* Open service manager */
3113     hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
3114     if (hScm == NULL)
3115     {
3116         return GetLastError();
3117     }
3118 
3119     /* Setup call parameters */
3120     InParams = &InOutParams->InParams;
3121     OutParams = NULL;
3122 
3123     /* Call SCM to query tag information */
3124     RpcTryExcept
3125     {
3126         dwError = RI_ScQueryServiceTagInfo(hScm, TagInfoLevelNameFromTag, &InParams, &OutParams);
3127     }
3128     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
3129     {
3130         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
3131     }
3132     RpcEndExcept;
3133 
3134     /* Quit if not a success */
3135     if (dwError != ERROR_SUCCESS)
3136     {
3137         goto Cleanup;
3138     }
3139 
3140     /* OutParams must be set now and we must have a name */
3141     if (OutParams == NULL ||
3142         OutParams->pszName == NULL)
3143     {
3144         dwError = ERROR_INVALID_DATA;
3145         goto Cleanup;
3146     }
3147 
3148     /* Copy back what SCM returned */
3149     lpszName = LocalAlloc(LPTR,
3150                           sizeof(WCHAR) * wcslen(OutParams->pszName) + sizeof(UNICODE_NULL));
3151     if (lpszName == NULL)
3152     {
3153         dwError = GetLastError();
3154         goto Cleanup;
3155     }
3156 
3157     wcscpy(lpszName, OutParams->pszName);
3158     InOutParams->OutParams.pszName = lpszName;
3159     InOutParams->OutParams.TagType = OutParams->TagType;
3160 
3161 Cleanup:
3162     CloseServiceHandle(hScm);
3163 
3164     /* Free memory allocated by SCM */
3165     if (OutParams != NULL)
3166     {
3167         if (OutParams->pszName != NULL)
3168         {
3169             midl_user_free(OutParams->pszName);
3170         }
3171 
3172         midl_user_free(OutParams);
3173     }
3174 
3175     return dwError;
3176 }
3177 
3178 /**********************************************************************
3179  *  I_QueryTagInformation
3180  *
3181  * @implemented
3182  */
3183 DWORD WINAPI
3184 I_QueryTagInformation(PVOID Unused,
3185                       TAG_INFO_LEVEL dwInfoLevel,
3186                       PTAG_INFO_NAME_FROM_TAG InOutParams)
3187 {
3188     /*
3189      * We only support one information class and it
3190      * needs parameters
3191      */
3192     if (dwInfoLevel != TagInfoLevelNameFromTag ||
3193         InOutParams == NULL)
3194     {
3195         return ERROR_INVALID_PARAMETER;
3196     }
3197 
3198     /* Validate input structure */
3199     if (InOutParams->InParams.dwPid == 0 || InOutParams->InParams.dwTag == 0)
3200     {
3201         return ERROR_INVALID_PARAMETER;
3202     }
3203 
3204     /* Validate output structure */
3205     if (InOutParams->OutParams.pszName != NULL)
3206     {
3207         return ERROR_INVALID_PARAMETER;
3208     }
3209 
3210     /* Call internal function for the RPC call */
3211     return I_ScQueryServiceTagInfo(Unused, TagInfoLevelNameFromTag, InOutParams);
3212 }
3213 
3214 /* EOF */
3215