2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/rpcserver.c
5 * PURPOSE: RPC server interface for the advapi32 calls
6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl
7 * Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
11 /* INCLUDES ****************************************************************/
18 /* GLOBALS *****************************************************************/
20 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
21 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
23 typedef struct _SCMGR_HANDLE
30 typedef struct _MANAGER_HANDLE
33 WCHAR DatabaseName
[1];
34 } MANAGER_HANDLE
, *PMANAGER_HANDLE
;
37 typedef struct _SERVICE_HANDLE
40 PSERVICE ServiceEntry
;
41 } SERVICE_HANDLE
, *PSERVICE_HANDLE
;
44 #define SC_MANAGER_READ \
45 (STANDARD_RIGHTS_READ | \
46 SC_MANAGER_QUERY_LOCK_STATUS | \
47 SC_MANAGER_ENUMERATE_SERVICE)
49 #define SC_MANAGER_WRITE \
50 (STANDARD_RIGHTS_WRITE | \
51 SC_MANAGER_MODIFY_BOOT_CONFIG | \
52 SC_MANAGER_CREATE_SERVICE)
54 #define SC_MANAGER_EXECUTE \
55 (STANDARD_RIGHTS_EXECUTE | \
57 SC_MANAGER_ENUMERATE_SERVICE | \
58 SC_MANAGER_CONNECT | \
59 SC_MANAGER_CREATE_SERVICE)
62 #define SERVICE_READ \
63 (STANDARD_RIGHTS_READ | \
64 SERVICE_INTERROGATE | \
65 SERVICE_ENUMERATE_DEPENDENTS | \
66 SERVICE_QUERY_STATUS | \
69 #define SERVICE_WRITE \
70 (STANDARD_RIGHTS_WRITE | \
71 SERVICE_CHANGE_CONFIG)
73 #define SERVICE_EXECUTE \
74 (STANDARD_RIGHTS_EXECUTE | \
75 SERVICE_USER_DEFINED_CONTROL | \
76 SERVICE_PAUSE_CONTINUE | \
81 /* VARIABLES ***************************************************************/
83 static GENERIC_MAPPING
84 ScmManagerMapping
= {SC_MANAGER_READ
,
87 SC_MANAGER_ALL_ACCESS
};
89 static GENERIC_MAPPING
90 ScmServiceMapping
= {SERVICE_READ
,
96 /* FUNCTIONS ***************************************************************/
99 ScmStartRpcServer(VOID
)
103 DPRINT("ScmStartRpcServer() called\n");
105 Status
= RpcServerUseProtseqEpW(L
"ncacn_np",
109 if (Status
!= RPC_S_OK
)
111 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status
);
115 Status
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
,
118 if (Status
!= RPC_S_OK
)
120 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status
);
124 Status
= RpcServerListen(1, 20, TRUE
);
125 if (Status
!= RPC_S_OK
)
127 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status
);
131 DPRINT("ScmStartRpcServer() done\n");
136 ScmCreateManagerHandle(LPWSTR lpDatabaseName
,
141 if (lpDatabaseName
== NULL
)
142 lpDatabaseName
= SERVICES_ACTIVE_DATABASEW
;
144 if (_wcsicmp(lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0)
146 DPRINT("Database %S, does not exist\n",lpDatabaseName
);
147 return ERROR_DATABASE_DOES_NOT_EXIST
;
149 else if (_wcsicmp(lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) != 0)
151 DPRINT("Invalid Database name %S.\n",lpDatabaseName
);
152 return ERROR_INVALID_NAME
;
155 Ptr
= (MANAGER_HANDLE
*) HeapAlloc(GetProcessHeap(),
157 sizeof(MANAGER_HANDLE
) + (wcslen(lpDatabaseName
) + 1) * sizeof(WCHAR
));
159 return ERROR_NOT_ENOUGH_MEMORY
;
161 Ptr
->Handle
.Tag
= MANAGER_TAG
;
163 wcscpy(Ptr
->DatabaseName
, lpDatabaseName
);
165 *Handle
= (SC_HANDLE
)Ptr
;
167 return ERROR_SUCCESS
;
172 ScmCreateServiceHandle(PSERVICE lpServiceEntry
,
177 Ptr
= (SERVICE_HANDLE
*) HeapAlloc(GetProcessHeap(),
179 sizeof(SERVICE_HANDLE
));
181 return ERROR_NOT_ENOUGH_MEMORY
;
183 Ptr
->Handle
.Tag
= SERVICE_TAG
;
185 Ptr
->ServiceEntry
= lpServiceEntry
;
187 *Handle
= (SC_HANDLE
)Ptr
;
189 return ERROR_SUCCESS
;
193 static PMANAGER_HANDLE
194 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle
)
196 PMANAGER_HANDLE pManager
= NULL
;
200 if (((PMANAGER_HANDLE
)Handle
)->Handle
.Tag
== MANAGER_TAG
)
201 pManager
= (PMANAGER_HANDLE
)Handle
;
203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
205 DPRINT1("Exception: Invalid Service Manager handle!\n");
213 static PSERVICE_HANDLE
214 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle
)
216 PSERVICE_HANDLE pService
= NULL
;
220 if (((PSERVICE_HANDLE
)Handle
)->Handle
.Tag
== SERVICE_TAG
)
221 pService
= (PSERVICE_HANDLE
)Handle
;
223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
225 DPRINT1("Exception: Invalid Service handle!\n");
234 ScmCheckAccess(SC_HANDLE Handle
,
235 DWORD dwDesiredAccess
)
237 PMANAGER_HANDLE hMgr
;
239 hMgr
= (PMANAGER_HANDLE
)Handle
;
240 if (hMgr
->Handle
.Tag
== MANAGER_TAG
)
242 RtlMapGenericMask(&dwDesiredAccess
,
245 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
247 return ERROR_SUCCESS
;
249 else if (hMgr
->Handle
.Tag
== SERVICE_TAG
)
251 RtlMapGenericMask(&dwDesiredAccess
,
254 hMgr
->Handle
.DesiredAccess
= dwDesiredAccess
;
256 return ERROR_SUCCESS
;
259 return ERROR_INVALID_HANDLE
;
264 ScmAssignNewTag(PSERVICE lpService
)
267 DPRINT("Assigning new tag to service %S\n", lpService
->lpServiceName
);
268 lpService
->dwTag
= 0;
269 return ERROR_SUCCESS
;
273 /* Internal recursive function */
274 /* Need to search for every dependency on every service */
276 Int_EnumDependentServicesW(HKEY hServicesKey
,
278 DWORD dwServiceState
,
279 PSERVICE
*lpServices
,
280 LPDWORD pcbBytesNeeded
,
281 LPDWORD lpServicesReturned
)
283 DWORD dwError
= ERROR_SUCCESS
;
284 WCHAR szNameBuf
[MAX_PATH
];
285 WCHAR szValueBuf
[MAX_PATH
];
286 WCHAR
*lpszNameBuf
= szNameBuf
;
287 WCHAR
*lpszValueBuf
= szValueBuf
;
291 PSERVICE lpCurrentService
;
292 HKEY hServiceEnumKey
;
293 DWORD dwCurrentServiceState
= SERVICE_ACTIVE
;
294 DWORD dwDependServiceStrPtr
= 0;
295 DWORD dwRequiredSize
= 0;
297 /* Get the number of service keys */
298 dwError
= RegQueryInfoKeyW(hServicesKey
,
310 if (dwError
!= ERROR_SUCCESS
)
312 DPRINT("ERROR! Unable to get number of services keys.\n");
316 /* Iterate the service keys to see if another service depends on the this service */
317 for (dwIteration
= 0; dwIteration
< dwNumSubKeys
; dwIteration
++)
320 dwError
= RegEnumKeyExW(hServicesKey
,
328 if (dwError
!= ERROR_SUCCESS
)
331 /* Open the Service key */
332 dwError
= RegOpenKeyExW(hServicesKey
,
337 if (dwError
!= ERROR_SUCCESS
)
342 /* Check for the DependOnService Value */
343 dwError
= RegQueryValueExW(hServiceEnumKey
,
347 (LPBYTE
)lpszValueBuf
,
350 /* FIXME: Handle load order. */
352 /* If the service found has a DependOnService value */
353 if (dwError
== ERROR_SUCCESS
)
355 dwDependServiceStrPtr
= 0;
357 /* Can be more than one Dependencies in the DependOnService string */
358 while (wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) > 0)
360 if (_wcsicmp(lpszValueBuf
+ dwDependServiceStrPtr
, lpService
->lpServiceName
) == 0)
362 /* Get the current enumed service pointer */
363 lpCurrentService
= ScmGetServiceEntryByName(lpszNameBuf
);
365 /* Check for valid Service */
366 if (!lpCurrentService
)
368 /* This should never happen! */
369 DPRINT("This should not happen at this point, report to Developer\n");
370 return ERROR_NOT_FOUND
;
373 /* Determine state the service is in */
374 if (lpCurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
375 dwCurrentServiceState
= SERVICE_INACTIVE
;
377 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
378 if ((dwCurrentServiceState
== dwServiceState
) ||
379 (dwServiceState
== SERVICE_STATE_ALL
))
381 /* Calculate the required size */
382 dwRequiredSize
+= sizeof(SERVICE_STATUS
);
383 dwRequiredSize
+= ((wcslen(lpCurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
));
384 dwRequiredSize
+= ((wcslen(lpCurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
386 /* Add the size for service name and display name pointers */
387 dwRequiredSize
+= (2 * sizeof(PVOID
));
389 /* increase the BytesNeeded size */
390 *pcbBytesNeeded
= *pcbBytesNeeded
+ dwRequiredSize
;
392 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
395 /* Recursive call to check for its dependencies */
396 Int_EnumDependentServicesW(hServicesKey
,
403 /* If the lpServices is valid set the service pointer */
405 lpServices
[*lpServicesReturned
] = lpCurrentService
;
407 *lpServicesReturned
= *lpServicesReturned
+ 1;
411 dwDependServiceStrPtr
+= (wcslen(lpszValueBuf
+ dwDependServiceStrPtr
) + 1);
414 else if (*pcbBytesNeeded
)
416 dwError
= ERROR_SUCCESS
;
419 RegCloseKey(hServiceEnumKey
);
427 DWORD
RCloseServiceHandle(
428 LPSC_RPC_HANDLE hSCObject
)
430 PMANAGER_HANDLE hManager
;
431 PSERVICE_HANDLE hService
;
435 DWORD pcbBytesNeeded
= 0;
436 DWORD dwServicesReturned
= 0;
438 DPRINT("RCloseServiceHandle() called\n");
440 DPRINT("hSCObject = %p\n", *hSCObject
);
443 return ERROR_INVALID_HANDLE
;
445 hManager
= ScmGetServiceManagerFromHandle(*hSCObject
);
446 hService
= ScmGetServiceFromHandle(*hSCObject
);
448 if (hManager
!= NULL
)
450 DPRINT("Found manager handle\n");
452 /* FIXME: add handle cleanup code */
454 HeapFree(GetProcessHeap(), 0, hManager
);
459 DPRINT("RCloseServiceHandle() done\n");
460 return ERROR_SUCCESS
;
462 else if (hService
!= NULL
)
464 DPRINT("Found service handle\n");
466 /* Lock the service database exlusively */
467 ScmLockDatabaseExclusive();
469 /* Get the pointer to the service record */
470 lpService
= hService
->ServiceEntry
;
472 /* FIXME: add handle cleanup code */
474 /* Free the handle */
475 HeapFree(GetProcessHeap(), 0, hService
);
478 ASSERT(lpService
->dwRefCount
> 0);
480 lpService
->dwRefCount
--;
481 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
482 lpService
->dwRefCount
);
484 if (lpService
->dwRefCount
== 0)
486 /* If this service has been marked for deletion */
487 if (lpService
->bDeleted
)
489 /* Open the Services Reg key */
490 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
491 L
"System\\CurrentControlSet\\Services",
493 KEY_SET_VALUE
| KEY_READ
,
495 if (dwError
!= ERROR_SUCCESS
)
497 DPRINT("Failed to open services key\n");
502 /* Call the internal function with NULL, just to get bytes we need */
503 Int_EnumDependentServicesW(hServicesKey
,
508 &dwServicesReturned
);
510 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service*/
513 DPRINT("Deletion failed due to running dependencies.\n");
514 RegCloseKey(hServicesKey
);
516 return ERROR_SUCCESS
;
519 /* There are no references and no runnning dependencies,
520 it is now safe to delete the service */
522 /* Delete the Service Key */
523 dwError
= RegDeleteKeyW(hServicesKey
,
524 lpService
->lpServiceName
);
526 RegCloseKey(hServicesKey
);
528 if (dwError
!= ERROR_SUCCESS
)
530 DPRINT("Failed to Delete the Service Registry key\n");
535 /* Delete the Service */
536 ScmDeleteServiceRecord(lpService
);
544 DPRINT("RCloseServiceHandle() done\n");
545 return ERROR_SUCCESS
;
548 DPRINT("Invalid handle tag (Tag %lx)\n", hManager
->Handle
.Tag
);
550 return ERROR_INVALID_HANDLE
;
555 DWORD
RControlService(
556 SC_RPC_HANDLE hService
,
558 LPSERVICE_STATUS lpServiceStatus
)
560 PSERVICE_HANDLE hSvc
;
562 ACCESS_MASK DesiredAccess
;
563 DWORD dwError
= ERROR_SUCCESS
;
564 DWORD pcbBytesNeeded
= 0;
565 DWORD dwServicesReturned
= 0;
566 DWORD dwControlsAccepted
;
567 DWORD dwCurrentState
;
568 HKEY hServicesKey
= NULL
;
570 DPRINT("RControlService() called\n");
573 return ERROR_SHUTDOWN_IN_PROGRESS
;
575 /* Check the service handle */
576 hSvc
= ScmGetServiceFromHandle(hService
);
579 DPRINT1("Invalid service handle!\n");
580 return ERROR_INVALID_HANDLE
;
584 /* Check the service entry point */
585 lpService
= hSvc
->ServiceEntry
;
586 if (lpService
== NULL
)
588 DPRINT1("lpService == NULL!\n");
589 return ERROR_INVALID_HANDLE
;
592 /* Check access rights */
595 case SERVICE_CONTROL_STOP
:
596 DesiredAccess
= SERVICE_STOP
;
599 case SERVICE_CONTROL_PAUSE
:
600 case SERVICE_CONTROL_CONTINUE
:
601 DesiredAccess
= SERVICE_PAUSE_CONTINUE
;
604 case SERVICE_INTERROGATE
:
605 DesiredAccess
= SERVICE_INTERROGATE
;
609 if (dwControl
>= 128 && dwControl
<= 255)
610 DesiredAccess
= SERVICE_USER_DEFINED_CONTROL
;
612 DesiredAccess
= SERVICE_QUERY_CONFIG
|
613 SERVICE_CHANGE_CONFIG
|
614 SERVICE_QUERY_STATUS
|
616 SERVICE_PAUSE_CONTINUE
;
620 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
622 return ERROR_ACCESS_DENIED
;
624 if (dwControl
== SERVICE_CONTROL_STOP
)
626 /* Check if the service has dependencies running as windows
627 doesn't stop a service that does */
629 /* Open the Services Reg key */
630 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
631 L
"System\\CurrentControlSet\\Services",
635 if (dwError
!= ERROR_SUCCESS
)
637 DPRINT("Failed to open services key\n");
641 /* Call the internal function with NULL, just to get bytes we need */
642 Int_EnumDependentServicesW(hServicesKey
,
647 &dwServicesReturned
);
649 RegCloseKey(hServicesKey
);
651 /* If pcbBytesNeeded is not zero then there are services running that
652 are dependent on this service */
653 if (pcbBytesNeeded
!= 0)
655 DPRINT("Service has running dependencies. Failed to stop service.\n");
656 return ERROR_DEPENDENT_SERVICES_RUNNING
;
660 if (lpService
->Status
.dwServiceType
& SERVICE_DRIVER
)
662 /* Send control code to the driver */
663 dwError
= ScmControlDriver(lpService
,
669 dwControlsAccepted
= lpService
->Status
.dwControlsAccepted
;
670 dwCurrentState
= lpService
->Status
.dwCurrentState
;
672 /* Check the current state before sending a control request */
673 switch (dwCurrentState
)
675 case SERVICE_STOP_PENDING
:
676 case SERVICE_STOPPED
:
677 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
679 case SERVICE_START_PENDING
:
682 case SERVICE_CONTROL_STOP
:
685 case SERVICE_CONTROL_INTERROGATE
:
686 RtlCopyMemory(lpServiceStatus
,
688 sizeof(SERVICE_STATUS
));
689 return ERROR_SUCCESS
;
692 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
697 /* Check if the control code is acceptable to the service */
700 case SERVICE_CONTROL_STOP
:
701 if ((dwControlsAccepted
& SERVICE_ACCEPT_STOP
) == 0)
702 return ERROR_INVALID_SERVICE_CONTROL
;
705 case SERVICE_CONTROL_PAUSE
:
706 case SERVICE_CONTROL_CONTINUE
:
707 if ((dwControlsAccepted
& SERVICE_ACCEPT_PAUSE_CONTINUE
) == 0)
708 return ERROR_INVALID_SERVICE_CONTROL
;
712 /* Send control code to the service */
713 dwError
= ScmControlService(lpService
,
716 /* Return service status information */
717 RtlCopyMemory(lpServiceStatus
,
719 sizeof(SERVICE_STATUS
));
722 if ((dwError
== ERROR_SUCCESS
) && (pcbBytesNeeded
))
723 dwError
= ERROR_DEPENDENT_SERVICES_RUNNING
;
730 DWORD
RDeleteService(
731 SC_RPC_HANDLE hService
)
733 PSERVICE_HANDLE hSvc
;
737 DPRINT("RDeleteService() called\n");
740 return ERROR_SHUTDOWN_IN_PROGRESS
;
742 hSvc
= ScmGetServiceFromHandle(hService
);
745 DPRINT1("Invalid service handle!\n");
746 return ERROR_INVALID_HANDLE
;
749 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
751 return ERROR_ACCESS_DENIED
;
753 lpService
= hSvc
->ServiceEntry
;
754 if (lpService
== NULL
)
756 DPRINT("lpService == NULL!\n");
757 return ERROR_INVALID_HANDLE
;
760 /* Lock the service database exclusively */
761 ScmLockDatabaseExclusive();
763 if (lpService
->bDeleted
)
765 DPRINT("The service has already been marked for delete!\n");
766 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
770 /* Mark service for delete */
771 lpService
->bDeleted
= TRUE
;
773 dwError
= ScmMarkServiceForDelete(lpService
);
776 /* Unlock the service database */
779 DPRINT("RDeleteService() done\n");
786 DWORD
RLockServiceDatabase(
787 SC_RPC_HANDLE hSCManager
,
788 LPSC_RPC_LOCK lpLock
)
790 PMANAGER_HANDLE hMgr
;
792 DPRINT("RLockServiceDatabase() called\n");
796 hMgr
= ScmGetServiceManagerFromHandle(hSCManager
);
799 DPRINT1("Invalid service manager handle!\n");
800 return ERROR_INVALID_HANDLE
;
803 if (!RtlAreAllAccessesGranted(hMgr
->Handle
.DesiredAccess
,
805 return ERROR_ACCESS_DENIED
;
807 // return ScmLockDatabase(0, hMgr->0xC, hLock);
809 /* FIXME: Lock the database */
810 *lpLock
= (SC_RPC_LOCK
)0x12345678; /* Dummy! */
812 return ERROR_SUCCESS
;
817 DWORD
RQueryServiceObjectSecurity(
818 SC_RPC_HANDLE hService
,
819 SECURITY_INFORMATION dwSecurityInformation
,
820 LPBYTE lpSecurityDescriptor
,
822 LPBOUNDED_DWORD_256K pcbBytesNeeded
)
824 PSERVICE_HANDLE hSvc
;
826 ULONG DesiredAccess
= 0;
832 SECURITY_DESCRIPTOR ObjectDescriptor
;
834 DPRINT("RQueryServiceObjectSecurity() called\n");
836 hSvc
= ScmGetServiceFromHandle(hService
);
839 DPRINT1("Invalid service handle!\n");
840 return ERROR_INVALID_HANDLE
;
843 if (dwSecurityInformation
& (DACL_SECURITY_INFORMATION
|
844 GROUP_SECURITY_INFORMATION
|
845 OWNER_SECURITY_INFORMATION
))
846 DesiredAccess
|= READ_CONTROL
;
848 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
849 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
851 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
854 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
855 return ERROR_ACCESS_DENIED
;
858 lpService
= hSvc
->ServiceEntry
;
859 if (lpService
== NULL
)
861 DPRINT("lpService == NULL!\n");
862 return ERROR_INVALID_HANDLE
;
865 /* FIXME: Lock the service list */
868 Status
= RtlCreateSecurityDescriptor(&ObjectDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
870 Status
= RtlQuerySecurityObject(&ObjectDescriptor
/* lpService->lpSecurityDescriptor */,
871 dwSecurityInformation
,
872 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
876 /* FIXME: Unlock the service list */
878 if (NT_SUCCESS(Status
))
880 *pcbBytesNeeded
= dwBytesNeeded
;
881 dwError
= STATUS_SUCCESS
;
883 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
885 *pcbBytesNeeded
= dwBytesNeeded
;
886 dwError
= ERROR_INSUFFICIENT_BUFFER
;
888 else if (Status
== STATUS_BAD_DESCRIPTOR_FORMAT
)
890 dwError
= ERROR_GEN_FAILURE
;
894 dwError
= RtlNtStatusToDosError(Status
);
902 DWORD
RSetServiceObjectSecurity(
903 SC_RPC_HANDLE hService
,
904 DWORD dwSecurityInformation
,
905 LPBYTE lpSecurityDescriptor
,
906 DWORD dwSecuityDescriptorSize
)
908 PSERVICE_HANDLE hSvc
;
910 ULONG DesiredAccess
= 0;
911 /* HANDLE hToken = NULL; */
913 /* NTSTATUS Status; */
916 DPRINT("RSetServiceObjectSecurity() called\n");
918 hSvc
= ScmGetServiceFromHandle(hService
);
921 DPRINT1("Invalid service handle!\n");
922 return ERROR_INVALID_HANDLE
;
925 if (dwSecurityInformation
== 0 ||
926 dwSecurityInformation
& ~(OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
927 | DACL_SECURITY_INFORMATION
| SACL_SECURITY_INFORMATION
))
928 return ERROR_INVALID_PARAMETER
;
930 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
))
931 return ERROR_INVALID_PARAMETER
;
933 if (dwSecurityInformation
& SACL_SECURITY_INFORMATION
)
934 DesiredAccess
|= ACCESS_SYSTEM_SECURITY
;
936 if (dwSecurityInformation
& DACL_SECURITY_INFORMATION
)
937 DesiredAccess
|= WRITE_DAC
;
939 if (dwSecurityInformation
& (OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
))
940 DesiredAccess
|= WRITE_OWNER
;
942 if ((dwSecurityInformation
& OWNER_SECURITY_INFORMATION
) &&
943 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Owner
== NULL
))
944 return ERROR_INVALID_PARAMETER
;
946 if ((dwSecurityInformation
& GROUP_SECURITY_INFORMATION
) &&
947 (((PISECURITY_DESCRIPTOR
)lpSecurityDescriptor
)->Group
== NULL
))
948 return ERROR_INVALID_PARAMETER
;
950 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
953 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
954 return ERROR_ACCESS_DENIED
;
957 lpService
= hSvc
->ServiceEntry
;
958 if (lpService
== NULL
)
960 DPRINT("lpService == NULL!\n");
961 return ERROR_INVALID_HANDLE
;
964 if (lpService
->bDeleted
)
965 return ERROR_SERVICE_MARKED_FOR_DELETE
;
968 RpcImpersonateClient(NULL
);
970 Status
= NtOpenThreadToken(NtCurrentThread(),
974 if (!NT_SUCCESS(Status
))
975 return RtlNtStatusToDosError(Status
);
979 /* FIXME: Lock service database */
981 Status
= RtlSetSecurityObject(dwSecurityInformation
,
982 (PSECURITY_DESCRIPTOR
)lpSecurityDescriptor
,
983 &lpService
->lpSecurityDescriptor
,
986 if (!NT_SUCCESS(Status
))
988 dwError
= RtlNtStatusToDosError(Status
);
993 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
994 READ_CONTROL
| KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
996 if (dwError
!= ERROR_SUCCESS
)
1000 dwError
= ERROR_SUCCESS
;
1001 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
1002 // lpService->lpSecurityDescriptor);
1004 RegFlushKey(hServiceKey
);
1005 RegCloseKey(hServiceKey
);
1014 /* FIXME: Unlock service database */
1016 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError
);
1023 DWORD
RQueryServiceStatus(
1024 SC_RPC_HANDLE hService
,
1025 LPSERVICE_STATUS lpServiceStatus
)
1027 PSERVICE_HANDLE hSvc
;
1030 DPRINT("RQueryServiceStatus() called\n");
1033 return ERROR_SHUTDOWN_IN_PROGRESS
;
1035 hSvc
= ScmGetServiceFromHandle(hService
);
1038 DPRINT1("Invalid service handle!\n");
1039 return ERROR_INVALID_HANDLE
;
1042 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1043 SERVICE_QUERY_STATUS
))
1045 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1046 return ERROR_ACCESS_DENIED
;
1049 lpService
= hSvc
->ServiceEntry
;
1050 if (lpService
== NULL
)
1052 DPRINT("lpService == NULL!\n");
1053 return ERROR_INVALID_HANDLE
;
1056 /* Lock the srevice database shared */
1057 ScmLockDatabaseShared();
1059 /* Return service status information */
1060 RtlCopyMemory(lpServiceStatus
,
1062 sizeof(SERVICE_STATUS
));
1064 /* Unlock the service database */
1065 ScmUnlockDatabase();
1067 return ERROR_SUCCESS
;
1072 ScmIsValidServiceState(DWORD dwCurrentState
)
1074 switch (dwCurrentState
)
1076 case SERVICE_STOPPED
:
1077 case SERVICE_START_PENDING
:
1078 case SERVICE_STOP_PENDING
:
1079 case SERVICE_RUNNING
:
1080 case SERVICE_CONTINUE_PENDING
:
1081 case SERVICE_PAUSE_PENDING
:
1082 case SERVICE_PAUSED
:
1092 DWORD
RSetServiceStatus(
1093 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1094 LPSERVICE_STATUS lpServiceStatus
)
1098 DPRINT("RSetServiceStatus() called\n");
1099 DPRINT("hServiceStatus = %p\n", hServiceStatus
);
1100 DPRINT("dwServiceType = %lu\n", lpServiceStatus
->dwServiceType
);
1101 DPRINT("dwCurrentState = %lu\n", lpServiceStatus
->dwCurrentState
);
1102 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus
->dwControlsAccepted
);
1103 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus
->dwWin32ExitCode
);
1104 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus
->dwServiceSpecificExitCode
);
1105 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus
->dwCheckPoint
);
1106 DPRINT("dwWaitHint = %lu\n", lpServiceStatus
->dwWaitHint
);
1108 if (hServiceStatus
== 0)
1110 DPRINT("hServiceStatus == NULL!\n");
1111 return ERROR_INVALID_HANDLE
;
1114 lpService
= (PSERVICE
)hServiceStatus
;
1115 if (lpService
== NULL
)
1117 DPRINT("lpService == NULL!\n");
1118 return ERROR_INVALID_HANDLE
;
1121 /* Check current state */
1122 if (!ScmIsValidServiceState(lpServiceStatus
->dwCurrentState
))
1124 DPRINT("Invalid service state!\n");
1125 return ERROR_INVALID_DATA
;
1128 /* Check service type */
1129 if (!(lpServiceStatus
->dwServiceType
& SERVICE_WIN32
) &&
1130 (lpServiceStatus
->dwServiceType
& SERVICE_DRIVER
))
1132 DPRINT("Invalid service type!\n");
1133 return ERROR_INVALID_DATA
;
1136 /* Check accepted controls */
1137 if (lpServiceStatus
->dwControlsAccepted
& ~0xFF)
1139 DPRINT("Invalid controls accepted!\n");
1140 return ERROR_INVALID_DATA
;
1143 /* Lock the service database exclusively */
1144 ScmLockDatabaseExclusive();
1146 RtlCopyMemory(&lpService
->Status
,
1148 sizeof(SERVICE_STATUS
));
1150 /* Unlock the service database */
1151 ScmUnlockDatabase();
1153 DPRINT("Set %S to %lu\n", lpService
->lpDisplayName
, lpService
->Status
.dwCurrentState
);
1154 DPRINT("RSetServiceStatus() done\n");
1156 return ERROR_SUCCESS
;
1161 DWORD
RUnlockServiceDatabase(
1165 return ERROR_SUCCESS
;
1170 DWORD
RNotifyBootConfigStatus(
1171 SVCCTL_HANDLEW lpMachineName
,
1172 DWORD BootAcceptable
)
1174 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName
, BootAcceptable
);
1175 return ERROR_SUCCESS
;
1178 // return ERROR_CALL_NOT_IMPLEMENTED;
1183 DWORD
RI_ScSetServiceBitsW(
1184 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
1185 DWORD dwServiceBits
,
1187 int bUpdateImmediately
,
1191 return ERROR_CALL_NOT_IMPLEMENTED
;
1196 DWORD
RChangeServiceConfigW(
1197 SC_RPC_HANDLE hService
,
1198 DWORD dwServiceType
,
1200 DWORD dwErrorControl
,
1201 LPWSTR lpBinaryPathName
,
1202 LPWSTR lpLoadOrderGroup
,
1204 LPBYTE lpDependencies
,
1206 LPWSTR lpServiceStartName
,
1209 LPWSTR lpDisplayName
)
1211 DWORD dwError
= ERROR_SUCCESS
;
1212 PSERVICE_HANDLE hSvc
;
1213 PSERVICE lpService
= NULL
;
1214 HKEY hServiceKey
= NULL
;
1215 LPWSTR lpDisplayNameW
= NULL
;
1217 DPRINT("RChangeServiceConfigW() called\n");
1218 DPRINT("dwServiceType = %lu\n", dwServiceType
);
1219 DPRINT("dwStartType = %lu\n", dwStartType
);
1220 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1221 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1222 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1223 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1226 return ERROR_SHUTDOWN_IN_PROGRESS
;
1228 hSvc
= ScmGetServiceFromHandle(hService
);
1231 DPRINT1("Invalid service handle!\n");
1232 return ERROR_INVALID_HANDLE
;
1235 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
1236 SERVICE_CHANGE_CONFIG
))
1238 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
1239 return ERROR_ACCESS_DENIED
;
1242 lpService
= hSvc
->ServiceEntry
;
1243 if (lpService
== NULL
)
1245 DPRINT("lpService == NULL!\n");
1246 return ERROR_INVALID_HANDLE
;
1249 /* Lock the service database exclusively */
1250 ScmLockDatabaseExclusive();
1252 if (lpService
->bDeleted
)
1254 DPRINT("The service has already been marked for delete!\n");
1255 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
1259 /* Open the service key */
1260 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
1263 if (dwError
!= ERROR_SUCCESS
)
1266 /* Write service data to the registry */
1267 /* Set the display name */
1268 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
1270 RegSetValueExW(hServiceKey
,
1274 (LPBYTE
)lpDisplayName
,
1275 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1277 /* Update the display name */
1278 lpDisplayNameW
= (LPWSTR
)HeapAlloc(GetProcessHeap(),
1280 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1281 if (lpDisplayNameW
== NULL
)
1283 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1287 if (lpService
->lpDisplayName
!= lpService
->lpServiceName
)
1288 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
1290 lpService
->lpDisplayName
= lpDisplayNameW
;
1293 if (dwServiceType
!= SERVICE_NO_CHANGE
)
1295 /* Set the service type */
1296 dwError
= RegSetValueExW(hServiceKey
,
1300 (LPBYTE
)&dwServiceType
,
1302 if (dwError
!= ERROR_SUCCESS
)
1305 lpService
->Status
.dwServiceType
= dwServiceType
;
1308 if (dwStartType
!= SERVICE_NO_CHANGE
)
1310 /* Set the start value */
1311 dwError
= RegSetValueExW(hServiceKey
,
1315 (LPBYTE
)&dwStartType
,
1317 if (dwError
!= ERROR_SUCCESS
)
1320 lpService
->dwStartType
= dwStartType
;
1323 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
1325 /* Set the error control value */
1326 dwError
= RegSetValueExW(hServiceKey
,
1330 (LPBYTE
)&dwErrorControl
,
1332 if (dwError
!= ERROR_SUCCESS
)
1335 lpService
->dwErrorControl
= dwErrorControl
;
1339 /* FIXME: set the new ImagePath value */
1341 /* Set the image path */
1342 if (dwServiceType
& SERVICE_WIN32
)
1344 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
1346 dwError
= RegSetValueExW(hServiceKey
,
1350 (LPBYTE
)lpBinaryPathName
,
1351 (wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
1352 if (dwError
!= ERROR_SUCCESS
)
1356 else if (dwServiceType
& SERVICE_DRIVER
)
1358 if (lpImagePath
!= NULL
&& *lpImagePath
!= 0)
1360 dwError
= RegSetValueExW(hServiceKey
,
1364 (LPBYTE
)lpImagePath
,
1365 (wcslen(lpImagePath
) + 1) *sizeof(WCHAR
));
1366 if (dwError
!= ERROR_SUCCESS
)
1372 /* Set the group name */
1373 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
1375 dwError
= RegSetValueExW(hServiceKey
,
1379 (LPBYTE
)lpLoadOrderGroup
,
1380 (wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
1381 if (dwError
!= ERROR_SUCCESS
)
1384 dwError
= ScmSetServiceGroup(lpService
,
1386 if (dwError
!= ERROR_SUCCESS
)
1390 if (lpdwTagId
!= NULL
)
1392 dwError
= ScmAssignNewTag(lpService
);
1393 if (dwError
!= ERROR_SUCCESS
)
1396 dwError
= RegSetValueExW(hServiceKey
,
1400 (LPBYTE
)&lpService
->dwTag
,
1402 if (dwError
!= ERROR_SUCCESS
)
1405 *lpdwTagId
= lpService
->dwTag
;
1408 /* Write dependencies */
1409 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
1411 dwError
= ScmWriteDependencies(hServiceKey
,
1412 (LPWSTR
)lpDependencies
,
1414 if (dwError
!= ERROR_SUCCESS
)
1418 if (lpPassword
!= NULL
)
1420 /* FIXME: Write password */
1424 if (hServiceKey
!= NULL
)
1425 RegCloseKey(hServiceKey
);
1427 /* Unlock the service database */
1428 ScmUnlockDatabase();
1430 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError
);
1436 /* Create a path suitable for the bootloader out of the full path */
1438 ScmConvertToBootPathName(wchar_t *CanonName
, wchar_t **RelativeName
)
1440 DWORD ServiceNameLen
, BufferSize
, ExpandedLen
;
1443 UNICODE_STRING NtPathName
, SystemRoot
, LinkTarget
;
1444 OBJECT_ATTRIBUTES ObjectAttributes
;
1446 HANDLE SymbolicLinkHandle
;
1448 DPRINT("ScmConvertToBootPathName %S\n", CanonName
);
1450 ServiceNameLen
= wcslen(CanonName
);
1452 /* First check, if it's already good */
1453 if (ServiceNameLen
> 12 &&
1454 !_wcsnicmp(L
"\\SystemRoot\\", CanonName
, 12))
1456 *RelativeName
= LocalAlloc(LMEM_ZEROINIT
, ServiceNameLen
* sizeof(WCHAR
) + sizeof(WCHAR
));
1457 if (*RelativeName
== NULL
)
1459 DPRINT("Error allocating memory for boot driver name!\n");
1460 return ERROR_NOT_ENOUGH_MEMORY
;
1464 wcscpy(*RelativeName
, CanonName
);
1466 DPRINT("Bootdriver name %S\n", *RelativeName
);
1467 return ERROR_SUCCESS
;
1470 /* If it has %SystemRoot% prefix, substitute it to \System*/
1471 if (ServiceNameLen
> 13 &&
1472 !_wcsnicmp(L
"%SystemRoot%\\", CanonName
, 13))
1474 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
1475 *RelativeName
= LocalAlloc(LMEM_ZEROINIT
, ServiceNameLen
* sizeof(WCHAR
));
1477 if (*RelativeName
== NULL
)
1479 DPRINT("Error allocating memory for boot driver name!\n");
1480 return ERROR_NOT_ENOUGH_MEMORY
;
1484 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
1485 wcscat(*RelativeName
, CanonName
+ 13);
1487 DPRINT("Bootdriver name %S\n", *RelativeName
);
1488 return ERROR_SUCCESS
;
1491 /* Get buffer size needed for expanding env strings */
1492 BufferSize
= ExpandEnvironmentStringsW(L
"%SystemRoot%\\", &Dest
, 1);
1494 if (BufferSize
<= 1)
1496 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1497 return ERROR_INVALID_ENVIRONMENT
;
1500 /* Allocate memory, since the size is known now */
1501 Expanded
= LocalAlloc(LMEM_ZEROINIT
, BufferSize
* sizeof(WCHAR
) + sizeof(WCHAR
));
1504 DPRINT("Error allocating memory for boot driver name!\n");
1505 return ERROR_NOT_ENOUGH_MEMORY
;
1509 if (ExpandEnvironmentStringsW(L
"%SystemRoot%\\", Expanded
, BufferSize
) >
1512 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1513 LocalFree(Expanded
);
1514 return ERROR_NOT_ENOUGH_MEMORY
;
1517 /* Convert to NY-style path */
1518 if (!RtlDosPathNameToNtPathName_U(Expanded
, &NtPathName
, NULL
, NULL
))
1520 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
1521 return ERROR_INVALID_ENVIRONMENT
;
1524 DPRINT("Converted to NT-style %wZ\n", &NtPathName
);
1526 /* No need to keep the dos-path anymore */
1527 LocalFree(Expanded
);
1529 /* Copy it to the allocated place */
1530 Expanded
= LocalAlloc(LMEM_ZEROINIT
, NtPathName
.Length
+ sizeof(WCHAR
));
1533 DPRINT("Error allocating memory for boot driver name!\n");
1534 return ERROR_NOT_ENOUGH_MEMORY
;
1537 ExpandedLen
= NtPathName
.Length
/ sizeof(WCHAR
);
1538 wcsncpy(Expanded
, NtPathName
.Buffer
, ExpandedLen
);
1539 Expanded
[ExpandedLen
] = 0;
1541 if (ServiceNameLen
> ExpandedLen
&&
1542 !_wcsnicmp(Expanded
, CanonName
, ExpandedLen
))
1544 /* Only \SystemRoot\ is missing */
1545 *RelativeName
= LocalAlloc(LMEM_ZEROINIT
,
1546 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
1547 if (*RelativeName
== NULL
)
1549 DPRINT("Error allocating memory for boot driver name!\n");
1550 LocalFree(Expanded
);
1551 return ERROR_NOT_ENOUGH_MEMORY
;
1554 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
1555 wcscat(*RelativeName
, CanonName
+ ExpandedLen
);
1557 RtlFreeUnicodeString(&NtPathName
);
1558 return ERROR_SUCCESS
;
1561 /* The most complex case starts here */
1562 RtlInitUnicodeString(&SystemRoot
, L
"\\SystemRoot");
1563 InitializeObjectAttributes(&ObjectAttributes
,
1565 OBJ_CASE_INSENSITIVE
,
1569 /* Open this symlink */
1570 Status
= NtOpenSymbolicLinkObject(&SymbolicLinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1572 if (NT_SUCCESS(Status
))
1574 LinkTarget
.Length
= 0;
1575 LinkTarget
.MaximumLength
= 0;
1577 DPRINT("Opened symbolic link object\n");
1579 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
1580 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_TOO_SMALL
)
1582 /* Check if required buffer size is sane */
1583 if (BufferSize
> 0xFFFD)
1585 DPRINT("Too large buffer required\n");
1588 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
1589 LocalFree(Expanded
);
1590 return ERROR_NOT_ENOUGH_MEMORY
;
1593 /* Alloc the string */
1594 LinkTarget
.Buffer
= LocalAlloc(LMEM_ZEROINIT
, BufferSize
+ sizeof(WCHAR
));
1595 if (!LinkTarget
.Buffer
)
1597 DPRINT("Unable to alloc buffer\n");
1598 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
1599 LocalFree(Expanded
);
1600 return ERROR_NOT_ENOUGH_MEMORY
;
1603 /* Do a real query now */
1604 LinkTarget
.Length
= (USHORT
)BufferSize
;
1605 LinkTarget
.MaximumLength
= LinkTarget
.Length
+ sizeof(WCHAR
);
1607 Status
= NtQuerySymbolicLinkObject(SymbolicLinkHandle
, &LinkTarget
, &BufferSize
);
1608 if (NT_SUCCESS(Status
))
1610 DPRINT("LinkTarget: %wZ\n", &LinkTarget
);
1612 ExpandedLen
= LinkTarget
.Length
/ sizeof(WCHAR
);
1613 if ((ServiceNameLen
> ExpandedLen
) &&
1614 !_wcsnicmp(LinkTarget
.Buffer
, CanonName
, ExpandedLen
))
1616 *RelativeName
= LocalAlloc(LMEM_ZEROINIT
,
1617 (ServiceNameLen
- ExpandedLen
) * sizeof(WCHAR
) + 13*sizeof(WCHAR
));
1619 if (*RelativeName
== NULL
)
1621 DPRINT("Unable to alloc buffer\n");
1622 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
1623 LocalFree(Expanded
);
1624 RtlFreeUnicodeString(&NtPathName
);
1625 return ERROR_NOT_ENOUGH_MEMORY
;
1628 /* Copy it over, substituting the first part
1630 wcscpy(*RelativeName
, L
"\\SystemRoot\\");
1631 wcscat(*RelativeName
, CanonName
+ExpandedLen
+1);
1634 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
1635 LocalFree(Expanded
);
1636 RtlFreeUnicodeString(&NtPathName
);
1638 /* Return success */
1639 return ERROR_SUCCESS
;
1643 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
1644 LocalFree(Expanded
);
1645 RtlFreeUnicodeString(&NtPathName
);
1646 return ERROR_INVALID_PARAMETER
;
1651 DPRINT("Error, Status = %08X\n", Status
);
1652 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
1653 LocalFree(Expanded
);
1654 RtlFreeUnicodeString(&NtPathName
);
1655 return ERROR_INVALID_PARAMETER
;
1660 DPRINT("Error, Status = %08X\n", Status
);
1661 if (SymbolicLinkHandle
) NtClose(SymbolicLinkHandle
);
1662 LocalFree(Expanded
);
1663 RtlFreeUnicodeString(&NtPathName
);
1664 return ERROR_INVALID_PARAMETER
;
1669 DPRINT("Error, Status = %08X\n", Status
);
1670 LocalFree(Expanded
);
1671 return ERROR_INVALID_PARAMETER
;
1675 *RelativeName
= NULL
;
1676 return ERROR_INVALID_PARAMETER
;
1680 ScmCanonDriverImagePath(DWORD dwStartType
,
1681 const wchar_t *lpServiceName
,
1682 wchar_t **lpCanonName
)
1684 DWORD ServiceNameLen
, Result
;
1685 UNICODE_STRING NtServiceName
;
1686 WCHAR
*RelativeName
;
1687 const WCHAR
*SourceName
= lpServiceName
;
1689 /* Calculate the length of the service's name */
1690 ServiceNameLen
= wcslen(lpServiceName
);
1692 /* 12 is wcslen(L"\\SystemRoot\\") */
1693 if (ServiceNameLen
> 12 &&
1694 !_wcsnicmp(L
"\\SystemRoot\\", lpServiceName
, 12))
1696 /* SystemRoot prefix is already included */
1698 *lpCanonName
= LocalAlloc(LMEM_ZEROINIT
, ServiceNameLen
* sizeof(WCHAR
) + sizeof(WCHAR
));
1700 if (*lpCanonName
== NULL
)
1702 DPRINT("Error allocating memory for canonized service name!\n");
1703 return ERROR_NOT_ENOUGH_MEMORY
;
1706 /* If it's a boot-time driver, it must be systemroot relative */
1707 if (dwStartType
== SERVICE_BOOT_START
)
1711 wcscpy(*lpCanonName
, SourceName
);
1713 DPRINT("Canonicalized name %S\n", *lpCanonName
);
1717 /* Check if it has %SystemRoot% (len=13) */
1718 if (ServiceNameLen
> 13 &&
1719 !_wcsnicmp(L
"%%SystemRoot%%\\", lpServiceName
, 13))
1721 /* Substitute %SystemRoot% with \\SystemRoot\\ */
1722 *lpCanonName
= LocalAlloc(LMEM_ZEROINIT
, ServiceNameLen
* sizeof(WCHAR
) + sizeof(WCHAR
));
1724 if (*lpCanonName
== NULL
)
1726 DPRINT("Error allocating memory for canonized service name!\n");
1727 return ERROR_NOT_ENOUGH_MEMORY
;
1730 /* If it's a boot-time driver, it must be systemroot relative */
1731 if (dwStartType
== SERVICE_BOOT_START
)
1732 wcscpy(*lpCanonName
, L
"\\SystemRoot\\");
1734 wcscat(*lpCanonName
, lpServiceName
+ 13);
1736 DPRINT("Canonicalized name %S\n", *lpCanonName
);
1740 /* Check if it's a relative path name */
1741 if (lpServiceName
[0] != L
'\\' && lpServiceName
[1] != L
':')
1743 *lpCanonName
= LocalAlloc(LMEM_ZEROINIT
, ServiceNameLen
* sizeof(WCHAR
) + sizeof(WCHAR
));
1745 if (*lpCanonName
== NULL
)
1747 DPRINT("Error allocating memory for canonized service name!\n");
1748 return ERROR_NOT_ENOUGH_MEMORY
;
1751 /* Just copy it over without changing */
1752 wcscpy(*lpCanonName
, lpServiceName
);
1757 /* It seems to be a DOS path, convert it */
1758 if (!RtlDosPathNameToNtPathName_U(lpServiceName
, &NtServiceName
, NULL
, NULL
))
1760 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
1761 return ERROR_INVALID_PARAMETER
;
1764 *lpCanonName
= LocalAlloc(LMEM_ZEROINIT
, NtServiceName
.Length
+ sizeof(WCHAR
));
1766 if (*lpCanonName
== NULL
)
1768 DPRINT("Error allocating memory for canonized service name!\n");
1769 RtlFreeUnicodeString(&NtServiceName
);
1770 return ERROR_NOT_ENOUGH_MEMORY
;
1773 /* Copy the string */
1774 wcsncpy(*lpCanonName
, NtServiceName
.Buffer
, NtServiceName
.Length
/ sizeof(WCHAR
));
1776 /* The unicode string is not needed anymore */
1777 RtlFreeUnicodeString(&NtServiceName
);
1779 if (dwStartType
!= SERVICE_BOOT_START
)
1781 DPRINT("Canonicalized name %S\n", *lpCanonName
);
1785 /* The service is boot-started, so must be relative */
1786 Result
= ScmConvertToBootPathName(*lpCanonName
, &RelativeName
);
1789 /* There is a problem, free name and return */
1790 LocalFree(*lpCanonName
);
1791 DPRINT("Error converting named!\n");
1795 ASSERT(RelativeName
);
1797 /* Copy that string */
1798 wcscpy(*lpCanonName
, RelativeName
+ 12);
1800 /* Free the allocated buffer */
1801 LocalFree(RelativeName
);
1803 DPRINT("Canonicalized name %S\n", *lpCanonName
);
1811 DWORD
RCreateServiceW(
1812 SC_RPC_HANDLE hSCManager
,
1813 LPCWSTR lpServiceName
,
1814 LPCWSTR lpDisplayName
,
1815 DWORD dwDesiredAccess
,
1816 DWORD dwServiceType
,
1818 DWORD dwErrorControl
,
1819 LPCWSTR lpBinaryPathName
,
1820 LPCWSTR lpLoadOrderGroup
,
1822 LPBYTE lpDependencies
,
1824 LPCWSTR lpServiceStartName
,
1827 LPSC_RPC_HANDLE lpServiceHandle
)
1829 PMANAGER_HANDLE hManager
;
1830 DWORD dwError
= ERROR_SUCCESS
;
1831 PSERVICE lpService
= NULL
;
1832 SC_HANDLE hServiceHandle
= NULL
;
1833 LPWSTR lpImagePath
= NULL
;
1834 HKEY hServiceKey
= NULL
;
1835 LPWSTR lpObjectName
;
1837 DPRINT("RCreateServiceW() called\n");
1838 DPRINT("lpServiceName = %S\n", lpServiceName
);
1839 DPRINT("lpDisplayName = %S\n", lpDisplayName
);
1840 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess
);
1841 DPRINT("dwServiceType = %lu\n", dwServiceType
);
1842 DPRINT("dwStartType = %lu\n", dwStartType
);
1843 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
1844 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName
);
1845 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup
);
1848 return ERROR_SHUTDOWN_IN_PROGRESS
;
1850 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
1851 if (hManager
== NULL
)
1853 DPRINT1("Invalid service manager handle!\n");
1854 return ERROR_INVALID_HANDLE
;
1857 /* Check access rights */
1858 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
1859 SC_MANAGER_CREATE_SERVICE
))
1861 DPRINT("Insufficient access rights! 0x%lx\n",
1862 hManager
->Handle
.DesiredAccess
);
1863 return ERROR_ACCESS_DENIED
;
1866 if (wcslen(lpServiceName
) == 0)
1868 return ERROR_INVALID_NAME
;
1871 if (wcslen(lpBinaryPathName
) == 0)
1873 return ERROR_INVALID_PARAMETER
;
1876 if ((dwServiceType
== (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
1877 (lpServiceStartName
))
1879 return ERROR_INVALID_PARAMETER
;
1882 if ((dwServiceType
> SERVICE_WIN32_SHARE_PROCESS
) &&
1883 (dwServiceType
!= (SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)) &&
1884 (dwServiceType
!= (SERVICE_WIN32_SHARE_PROCESS
| SERVICE_INTERACTIVE_PROCESS
)))
1886 return ERROR_INVALID_PARAMETER
;
1889 if (dwStartType
> SERVICE_DISABLED
)
1891 return ERROR_INVALID_PARAMETER
;
1894 /* Lock the service database exclusively */
1895 ScmLockDatabaseExclusive();
1897 lpService
= ScmGetServiceEntryByName(lpServiceName
);
1900 /* Unlock the service database */
1901 ScmUnlockDatabase();
1903 /* check if it is marked for deletion */
1904 if (lpService
->bDeleted
)
1905 return ERROR_SERVICE_MARKED_FOR_DELETE
;
1906 /* Return Error exist */
1907 return ERROR_SERVICE_EXISTS
;
1910 if (lpDisplayName
!= NULL
&&
1911 ScmGetServiceEntryByDisplayName(lpDisplayName
) != NULL
)
1913 /* Unlock the service database */
1914 ScmUnlockDatabase();
1916 return ERROR_DUPLICATE_SERVICE_NAME
;
1919 if (dwServiceType
& SERVICE_DRIVER
)
1921 dwError
= ScmCanonDriverImagePath(dwStartType
,
1924 if (dwError
!= ERROR_SUCCESS
)
1929 if (dwStartType
== SERVICE_BOOT_START
||
1930 dwStartType
== SERVICE_SYSTEM_START
)
1932 /* Unlock the service database */
1933 ScmUnlockDatabase();
1935 return ERROR_INVALID_PARAMETER
;
1939 /* Allocate a new service entry */
1940 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
1942 if (dwError
!= ERROR_SUCCESS
)
1945 /* Fill the new service entry */
1946 lpService
->Status
.dwServiceType
= dwServiceType
;
1947 lpService
->dwStartType
= dwStartType
;
1948 lpService
->dwErrorControl
= dwErrorControl
;
1950 /* Fill the display name */
1951 if (lpDisplayName
!= NULL
&&
1952 *lpDisplayName
!= 0 &&
1953 _wcsicmp(lpService
->lpDisplayName
, lpDisplayName
) != 0)
1955 lpService
->lpDisplayName
= (WCHAR
*) HeapAlloc(GetProcessHeap(), 0,
1956 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
1957 if (lpService
->lpDisplayName
== NULL
)
1959 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1962 wcscpy(lpService
->lpDisplayName
, lpDisplayName
);
1965 /* Assign the service to a group */
1966 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
1968 dwError
= ScmSetServiceGroup(lpService
,
1970 if (dwError
!= ERROR_SUCCESS
)
1974 /* Assign a new tag */
1975 if (lpdwTagId
!= NULL
)
1977 dwError
= ScmAssignNewTag(lpService
);
1978 if (dwError
!= ERROR_SUCCESS
)
1982 /* Write service data to the registry */
1983 /* Create the service key */
1984 dwError
= ScmCreateServiceKey(lpServiceName
,
1987 if (dwError
!= ERROR_SUCCESS
)
1990 /* Set the display name */
1991 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
1993 RegSetValueExW(hServiceKey
,
1997 (LPBYTE
)lpDisplayName
,
1998 (wcslen(lpDisplayName
) + 1) * sizeof(WCHAR
));
2001 /* Set the service type */
2002 dwError
= RegSetValueExW(hServiceKey
,
2006 (LPBYTE
)&dwServiceType
,
2008 if (dwError
!= ERROR_SUCCESS
)
2011 /* Set the start value */
2012 dwError
= RegSetValueExW(hServiceKey
,
2016 (LPBYTE
)&dwStartType
,
2018 if (dwError
!= ERROR_SUCCESS
)
2021 /* Set the error control value */
2022 dwError
= RegSetValueExW(hServiceKey
,
2026 (LPBYTE
)&dwErrorControl
,
2028 if (dwError
!= ERROR_SUCCESS
)
2031 /* Set the image path */
2032 if (dwServiceType
& SERVICE_WIN32
)
2034 dwError
= RegSetValueExW(hServiceKey
,
2038 (LPBYTE
)lpBinaryPathName
,
2039 (wcslen(lpBinaryPathName
) + 1) * sizeof(WCHAR
));
2040 if (dwError
!= ERROR_SUCCESS
)
2043 else if (dwServiceType
& SERVICE_DRIVER
)
2045 dwError
= RegSetValueExW(hServiceKey
,
2049 (LPBYTE
)lpImagePath
,
2050 (wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2051 if (dwError
!= ERROR_SUCCESS
)
2055 /* Set the group name */
2056 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
2058 dwError
= RegSetValueExW(hServiceKey
,
2062 (LPBYTE
)lpLoadOrderGroup
,
2063 (wcslen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
2064 if (dwError
!= ERROR_SUCCESS
)
2068 if (lpdwTagId
!= NULL
)
2070 dwError
= RegSetValueExW(hServiceKey
,
2074 (LPBYTE
)&lpService
->dwTag
,
2076 if (dwError
!= ERROR_SUCCESS
)
2080 /* Write dependencies */
2081 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
2083 dwError
= ScmWriteDependencies(hServiceKey
,
2084 (LPWSTR
)lpDependencies
,
2086 if (dwError
!= ERROR_SUCCESS
)
2090 /* Write service start name */
2091 if (dwServiceType
& SERVICE_WIN32
)
2093 lpObjectName
= (lpServiceStartName
!= NULL
) ? (LPWSTR
)lpServiceStartName
: L
"LocalSystem";
2094 dwError
= RegSetValueExW(hServiceKey
,
2098 (LPBYTE
)lpObjectName
,
2099 (wcslen(lpObjectName
) + 1) * sizeof(WCHAR
));
2100 if (dwError
!= ERROR_SUCCESS
)
2104 if (lpPassword
!= NULL
)
2106 /* FIXME: Write password */
2109 dwError
= ScmCreateServiceHandle(lpService
,
2111 if (dwError
!= ERROR_SUCCESS
)
2114 dwError
= ScmCheckAccess(hServiceHandle
,
2116 if (dwError
!= ERROR_SUCCESS
)
2119 lpService
->dwRefCount
= 1;
2120 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService
->dwRefCount
);
2123 /* Unlock the service database */
2124 ScmUnlockDatabase();
2126 if (hServiceKey
!= NULL
)
2127 RegCloseKey(hServiceKey
);
2129 if (dwError
== ERROR_SUCCESS
)
2131 DPRINT("hService %p\n", hServiceHandle
);
2132 *lpServiceHandle
= (SC_RPC_HANDLE
)hServiceHandle
;
2134 if (lpdwTagId
!= NULL
)
2135 *lpdwTagId
= lpService
->dwTag
;
2139 /* Release the display name buffer */
2140 if (lpService
->lpServiceName
!= NULL
)
2141 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
2145 /* Remove the service handle */
2146 HeapFree(GetProcessHeap(), 0, hServiceHandle
);
2149 if (lpService
!= NULL
)
2151 /* FIXME: remove the service entry */
2155 if (lpImagePath
!= NULL
)
2156 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2158 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError
);
2165 DWORD
REnumDependentServicesW(
2166 SC_RPC_HANDLE hService
,
2167 DWORD dwServiceState
,
2170 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2171 LPBOUNDED_DWORD_256K lpServicesReturned
)
2173 DWORD dwError
= ERROR_SUCCESS
;
2174 DWORD dwServicesReturned
= 0;
2175 DWORD dwServiceCount
;
2176 HKEY hServicesKey
= NULL
;
2177 PSERVICE_HANDLE hSvc
;
2178 PSERVICE lpService
= NULL
;
2179 PSERVICE
*lpServicesArray
= NULL
;
2180 LPENUM_SERVICE_STATUSW lpServicesPtr
= NULL
;
2183 *pcbBytesNeeded
= 0;
2184 *lpServicesReturned
= 0;
2186 DPRINT("REnumDependentServicesW() called\n");
2188 hSvc
= ScmGetServiceFromHandle(hService
);
2191 DPRINT1("Invalid service handle!\n");
2192 return ERROR_INVALID_HANDLE
;
2195 lpService
= hSvc
->ServiceEntry
;
2197 /* Check access rights */
2198 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2199 SC_MANAGER_ENUMERATE_SERVICE
))
2201 DPRINT("Insufficient access rights! 0x%lx\n",
2202 hSvc
->Handle
.DesiredAccess
);
2203 return ERROR_ACCESS_DENIED
;
2206 /* Open the Services Reg key */
2207 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2208 L
"System\\CurrentControlSet\\Services",
2212 if (dwError
!= ERROR_SUCCESS
)
2215 /* First determine the bytes needed and get the number of dependent services */
2216 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2221 &dwServicesReturned
);
2222 if (dwError
!= ERROR_SUCCESS
)
2225 /* If buffer size is less than the bytes needed or pointer is null */
2226 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
2228 dwError
= ERROR_MORE_DATA
;
2232 /* Allocate memory for array of service pointers */
2233 lpServicesArray
= HeapAlloc(GetProcessHeap(),
2235 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
2236 if (!lpServicesArray
)
2238 DPRINT("Could not allocate a buffer!!\n");
2239 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
2243 dwServicesReturned
= 0;
2244 *pcbBytesNeeded
= 0;
2246 dwError
= Int_EnumDependentServicesW(hServicesKey
,
2251 &dwServicesReturned
);
2252 if (dwError
!= ERROR_SUCCESS
)
2257 lpServicesPtr
= (LPENUM_SERVICE_STATUSW
) lpServices
;
2258 lpStr
= (LPWSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
)));
2260 /* Copy EnumDepenedentService to Buffer */
2261 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
2263 lpService
= lpServicesArray
[dwServiceCount
];
2265 /* Copy status info */
2266 memcpy(&lpServicesPtr
->ServiceStatus
,
2268 sizeof(SERVICE_STATUS
));
2270 /* Copy display name */
2271 wcscpy(lpStr
, lpService
->lpDisplayName
);
2272 lpServicesPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2273 lpStr
+= (wcslen(lpService
->lpDisplayName
) + 1);
2275 /* Copy service name */
2276 wcscpy(lpStr
, lpService
->lpServiceName
);
2277 lpServicesPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
2278 lpStr
+= (wcslen(lpService
->lpServiceName
) + 1);
2283 *lpServicesReturned
= dwServicesReturned
;
2286 if (lpServicesArray
!= NULL
)
2287 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
2289 RegCloseKey(hServicesKey
);
2291 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError
);
2298 DWORD
REnumServicesStatusW(
2299 SC_RPC_HANDLE hSCManager
,
2300 DWORD dwServiceType
,
2301 DWORD dwServiceState
,
2304 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
2305 LPBOUNDED_DWORD_256K lpServicesReturned
,
2306 LPBOUNDED_DWORD_256K lpResumeHandle
)
2308 PMANAGER_HANDLE hManager
;
2310 DWORD dwError
= ERROR_SUCCESS
;
2311 PLIST_ENTRY ServiceEntry
;
2312 PSERVICE CurrentService
;
2314 DWORD dwRequiredSize
;
2315 DWORD dwServiceCount
;
2317 DWORD dwLastResumeCount
= 0;
2318 LPENUM_SERVICE_STATUSW lpStatusPtr
;
2321 DPRINT("REnumServicesStatusW() called\n");
2324 return ERROR_SHUTDOWN_IN_PROGRESS
;
2326 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2327 if (hManager
== NULL
)
2329 DPRINT1("Invalid service manager handle!\n");
2330 return ERROR_INVALID_HANDLE
;
2334 *pcbBytesNeeded
= 0;
2335 *lpServicesReturned
= 0;
2337 if ((dwServiceType
!=SERVICE_DRIVER
) && (dwServiceType
!=SERVICE_WIN32
))
2339 DPRINT("Not a valid Service Type!\n");
2340 return ERROR_INVALID_PARAMETER
;
2343 if ((dwServiceState
<SERVICE_ACTIVE
) || (dwServiceState
>SERVICE_STATE_ALL
))
2345 DPRINT("Not a valid Service State!\n");
2346 return ERROR_INVALID_PARAMETER
;
2349 /* Check access rights */
2350 if (!RtlAreAllAccessesGranted(hManager
->Handle
.DesiredAccess
,
2351 SC_MANAGER_ENUMERATE_SERVICE
))
2353 DPRINT("Insufficient access rights! 0x%lx\n",
2354 hManager
->Handle
.DesiredAccess
);
2355 return ERROR_ACCESS_DENIED
;
2359 dwLastResumeCount
= *lpResumeHandle
;
2361 /* Lock the service database shared */
2362 ScmLockDatabaseShared();
2364 lpService
= ScmGetServiceEntryByResumeCount(dwLastResumeCount
);
2365 if (lpService
== NULL
)
2367 dwError
= ERROR_SUCCESS
;
2374 for (ServiceEntry
= &lpService
->ServiceListEntry
;
2375 ServiceEntry
!= &ServiceListHead
;
2376 ServiceEntry
= ServiceEntry
->Flink
)
2378 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
2382 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
2385 dwState
= SERVICE_ACTIVE
;
2386 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
2387 dwState
= SERVICE_INACTIVE
;
2389 if ((dwState
& dwServiceState
) == 0)
2392 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
2393 ((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
2394 ((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2396 if (dwRequiredSize
+ dwSize
> dwBufSize
)
2398 DPRINT("Service name: %S no fit\n", CurrentService
->lpServiceName
);
2402 DPRINT("Service name: %S fit\n", CurrentService
->lpServiceName
);
2403 dwRequiredSize
+= dwSize
;
2405 dwLastResumeCount
= CurrentService
->dwResumeCount
;
2408 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize
);
2409 DPRINT("dwServiceCount: %lu\n", dwServiceCount
);
2412 ServiceEntry
!= &ServiceListHead
;
2413 ServiceEntry
= ServiceEntry
->Flink
)
2415 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
2419 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
2422 dwState
= SERVICE_ACTIVE
;
2423 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
2424 dwState
= SERVICE_INACTIVE
;
2426 if ((dwState
& dwServiceState
) == 0)
2429 dwRequiredSize
+= (sizeof(ENUM_SERVICE_STATUSW
) +
2430 ((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
2431 ((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
)));
2433 dwError
= ERROR_MORE_DATA
;
2436 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize
);
2439 *lpResumeHandle
= dwLastResumeCount
;
2441 *lpServicesReturned
= dwServiceCount
;
2442 *pcbBytesNeeded
= dwRequiredSize
;
2444 lpStatusPtr
= (LPENUM_SERVICE_STATUSW
)lpBuffer
;
2445 lpStringPtr
= (LPWSTR
)((ULONG_PTR
)lpBuffer
+
2446 dwServiceCount
* sizeof(ENUM_SERVICE_STATUSW
));
2449 for (ServiceEntry
= &lpService
->ServiceListEntry
;
2450 ServiceEntry
!= &ServiceListHead
;
2451 ServiceEntry
= ServiceEntry
->Flink
)
2453 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
2457 if ((CurrentService
->Status
.dwServiceType
& dwServiceType
) == 0)
2460 dwState
= SERVICE_ACTIVE
;
2461 if (CurrentService
->Status
.dwCurrentState
== SERVICE_STOPPED
)
2462 dwState
= SERVICE_INACTIVE
;
2464 if ((dwState
& dwServiceState
) == 0)
2467 dwSize
= sizeof(ENUM_SERVICE_STATUSW
) +
2468 ((wcslen(CurrentService
->lpServiceName
) + 1) * sizeof(WCHAR
)) +
2469 ((wcslen(CurrentService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2471 if (dwRequiredSize
+ dwSize
> dwBufSize
)
2474 /* Copy the service name */
2475 wcscpy(lpStringPtr
, CurrentService
->lpServiceName
);
2476 lpStatusPtr
->lpServiceName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
2477 lpStringPtr
+= (wcslen(CurrentService
->lpServiceName
) + 1);
2479 /* Copy the display name */
2480 wcscpy(lpStringPtr
, CurrentService
->lpDisplayName
);
2481 lpStatusPtr
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStringPtr
- (ULONG_PTR
)lpBuffer
);
2482 lpStringPtr
+= (wcslen(CurrentService
->lpDisplayName
) + 1);
2484 /* Copy the status information */
2485 memcpy(&lpStatusPtr
->ServiceStatus
,
2486 &CurrentService
->Status
,
2487 sizeof(SERVICE_STATUS
));
2490 dwRequiredSize
+= dwSize
;
2495 *pcbBytesNeeded
= 0;
2496 if (lpResumeHandle
) *lpResumeHandle
= 0;
2500 /* Unlock the service database */
2501 ScmUnlockDatabase();
2503 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError
);
2510 DWORD
ROpenSCManagerW(
2511 LPWSTR lpMachineName
,
2512 LPWSTR lpDatabaseName
,
2513 DWORD dwDesiredAccess
,
2514 LPSC_RPC_HANDLE lpScHandle
)
2519 DPRINT("ROpenSCManagerW() called\n");
2520 DPRINT("lpMachineName = %p\n", lpMachineName
);
2521 DPRINT("lpMachineName: %S\n", lpMachineName
);
2522 DPRINT("lpDataBaseName = %p\n", lpDatabaseName
);
2523 DPRINT("lpDataBaseName: %S\n", lpDatabaseName
);
2524 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2527 return ERROR_SHUTDOWN_IN_PROGRESS
;
2530 return ERROR_INVALID_PARAMETER
;
2532 dwError
= ScmCreateManagerHandle(lpDatabaseName
,
2534 if (dwError
!= ERROR_SUCCESS
)
2536 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError
);
2540 /* Check the desired access */
2541 dwError
= ScmCheckAccess(hHandle
,
2542 dwDesiredAccess
| SC_MANAGER_CONNECT
);
2543 if (dwError
!= ERROR_SUCCESS
)
2545 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2546 HeapFree(GetProcessHeap(), 0, hHandle
);
2550 *lpScHandle
= (SC_RPC_HANDLE
)hHandle
;
2551 DPRINT("*hScm = %p\n", *lpScHandle
);
2553 DPRINT("ROpenSCManagerW() done\n");
2555 return ERROR_SUCCESS
;
2560 DWORD
ROpenServiceW(
2561 SC_RPC_HANDLE hSCManager
,
2562 LPWSTR lpServiceName
,
2563 DWORD dwDesiredAccess
,
2564 LPSC_RPC_HANDLE lpServiceHandle
)
2567 PMANAGER_HANDLE hManager
;
2569 DWORD dwError
= ERROR_SUCCESS
;
2571 DPRINT("ROpenServiceW() called\n");
2572 DPRINT("hSCManager = %p\n", hSCManager
);
2573 DPRINT("lpServiceName = %p\n", lpServiceName
);
2574 DPRINT("lpServiceName: %S\n", lpServiceName
);
2575 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess
);
2578 return ERROR_SHUTDOWN_IN_PROGRESS
;
2580 hManager
= ScmGetServiceManagerFromHandle(hSCManager
);
2581 if (hManager
== NULL
)
2583 DPRINT1("Invalid service manager handle!\n");
2584 return ERROR_INVALID_HANDLE
;
2587 if (!lpServiceHandle
)
2588 return ERROR_INVALID_PARAMETER
;
2591 return ERROR_INVALID_ADDRESS
;
2593 /* Lock the service database exclusive */
2594 ScmLockDatabaseExclusive();
2596 /* Get service database entry */
2597 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2598 if (lpService
== NULL
)
2600 DPRINT("Could not find a service!\n");
2601 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
2605 /* Create a service handle */
2606 dwError
= ScmCreateServiceHandle(lpService
,
2608 if (dwError
!= ERROR_SUCCESS
)
2610 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError
);
2614 /* Check the desired access */
2615 dwError
= ScmCheckAccess(hHandle
,
2617 if (dwError
!= ERROR_SUCCESS
)
2619 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError
);
2620 HeapFree(GetProcessHeap(), 0, hHandle
);
2624 lpService
->dwRefCount
++;
2625 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService
->dwRefCount
);
2627 *lpServiceHandle
= (SC_RPC_HANDLE
)hHandle
;
2628 DPRINT("*hService = %p\n", *lpServiceHandle
);
2631 /* Unlock the service database */
2632 ScmUnlockDatabase();
2634 DPRINT("ROpenServiceW() done\n");
2641 DWORD
RQueryServiceConfigW(
2642 SC_RPC_HANDLE hService
,
2643 LPBYTE lpBuf
, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2645 LPBOUNDED_DWORD_8K pcbBytesNeeded
)
2647 LPQUERY_SERVICE_CONFIGW lpServiceConfig
= (LPQUERY_SERVICE_CONFIGW
)lpBuf
;
2648 DWORD dwError
= ERROR_SUCCESS
;
2649 PSERVICE_HANDLE hSvc
;
2650 PSERVICE lpService
= NULL
;
2651 HKEY hServiceKey
= NULL
;
2652 LPWSTR lpImagePath
= NULL
;
2653 LPWSTR lpServiceStartName
= NULL
;
2654 LPWSTR lpDependencies
= NULL
;
2655 DWORD dwDependenciesLength
= 0;
2656 DWORD dwRequiredSize
;
2657 LPQUERY_SERVICE_CONFIGW lpConfig
= NULL
;
2658 WCHAR lpEmptyString
[] = {0,0};
2661 DPRINT("RQueryServiceConfigW() called\n");
2664 return ERROR_SHUTDOWN_IN_PROGRESS
;
2666 hSvc
= ScmGetServiceFromHandle(hService
);
2669 DPRINT1("Invalid service handle!\n");
2670 return ERROR_INVALID_HANDLE
;
2673 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2674 SERVICE_QUERY_CONFIG
))
2676 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2677 return ERROR_ACCESS_DENIED
;
2680 lpService
= hSvc
->ServiceEntry
;
2681 if (lpService
== NULL
)
2683 DPRINT("lpService == NULL!\n");
2684 return ERROR_INVALID_HANDLE
;
2687 /* Lock the service database shared */
2688 ScmLockDatabaseShared();
2690 dwError
= ScmOpenServiceKey(lpService
->lpServiceName
,
2693 if (dwError
!= ERROR_SUCCESS
)
2696 /* Read the image path */
2697 dwError
= ScmReadString(hServiceKey
,
2700 if (dwError
!= ERROR_SUCCESS
)
2703 /* Read the service start name */
2704 ScmReadString(hServiceKey
,
2706 &lpServiceStartName
);
2708 /* Read the dependencies */
2709 ScmReadDependencies(hServiceKey
,
2711 &dwDependenciesLength
);
2713 dwRequiredSize
= sizeof(QUERY_SERVICE_CONFIGW
);
2715 if (lpImagePath
!= NULL
)
2716 dwRequiredSize
+= ((wcslen(lpImagePath
) + 1) * sizeof(WCHAR
));
2718 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2720 if (lpService
->lpGroup
!= NULL
)
2721 dwRequiredSize
+= ((wcslen(lpService
->lpGroup
->lpGroupName
) + 1) * sizeof(WCHAR
));
2723 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2725 if (lpDependencies
!= NULL
)
2726 dwRequiredSize
+= dwDependenciesLength
* sizeof(WCHAR
);
2728 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2730 if (lpServiceStartName
!= NULL
)
2731 dwRequiredSize
+= ((wcslen(lpServiceStartName
) + 1) * sizeof(WCHAR
));
2733 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2735 if (lpService
->lpDisplayName
!= NULL
)
2736 dwRequiredSize
+= ((wcslen(lpService
->lpDisplayName
) + 1) * sizeof(WCHAR
));
2738 dwRequiredSize
+= 2 * sizeof(WCHAR
);
2740 if (lpServiceConfig
== NULL
|| cbBufSize
< dwRequiredSize
)
2742 dwError
= ERROR_INSUFFICIENT_BUFFER
;
2746 lpConfig
= (LPQUERY_SERVICE_CONFIGW
)lpServiceConfig
;
2747 lpConfig
->dwServiceType
= lpService
->Status
.dwServiceType
;
2748 lpConfig
->dwStartType
= lpService
->dwStartType
;
2749 lpConfig
->dwErrorControl
= lpService
->dwErrorControl
;
2750 lpConfig
->dwTagId
= lpService
->dwTag
;
2752 lpStr
= (LPWSTR
)(lpConfig
+ 1);
2754 /* Append the image path */
2755 if (lpImagePath
!= NULL
)
2757 wcscpy(lpStr
, lpImagePath
);
2761 wcscpy(lpStr
, lpEmptyString
);
2764 lpConfig
->lpBinaryPathName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2765 lpStr
+= (wcslen(lpStr
) + 1);
2767 /* Append the group name */
2768 if (lpService
->lpGroup
!= NULL
)
2770 wcscpy(lpStr
, lpService
->lpGroup
->lpGroupName
);
2774 wcscpy(lpStr
, lpEmptyString
);
2777 lpConfig
->lpLoadOrderGroup
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2778 lpStr
+= (wcslen(lpStr
) + 1);
2780 /* Append Dependencies */
2781 if (lpDependencies
!= NULL
)
2785 dwDependenciesLength
* sizeof(WCHAR
));
2789 wcscpy(lpStr
, lpEmptyString
);
2792 lpConfig
->lpDependencies
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2793 if (lpDependencies
!= NULL
)
2794 lpStr
+= dwDependenciesLength
* sizeof(WCHAR
);
2796 lpStr
+= (wcslen(lpStr
) + 1);
2798 /* Append the service start name */
2799 if (lpServiceStartName
!= NULL
)
2801 wcscpy(lpStr
, lpServiceStartName
);
2805 wcscpy(lpStr
, lpEmptyString
);
2808 lpConfig
->lpServiceStartName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2809 lpStr
+= (wcslen(lpStr
) + 1);
2811 /* Append the display name */
2812 if (lpService
->lpDisplayName
!= NULL
)
2814 wcscpy(lpStr
, lpService
->lpDisplayName
);
2818 wcscpy(lpStr
, lpEmptyString
);
2821 lpConfig
->lpDisplayName
= (LPWSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpConfig
);
2824 if (pcbBytesNeeded
!= NULL
)
2825 *pcbBytesNeeded
= dwRequiredSize
;
2828 /* Unlock the service database */
2829 ScmUnlockDatabase();
2831 if (lpImagePath
!= NULL
)
2832 HeapFree(GetProcessHeap(), 0, lpImagePath
);
2834 if (lpServiceStartName
!= NULL
)
2835 HeapFree(GetProcessHeap(), 0, lpServiceStartName
);
2837 if (lpDependencies
!= NULL
)
2838 HeapFree(GetProcessHeap(), 0, lpDependencies
);
2840 if (hServiceKey
!= NULL
)
2841 RegCloseKey(hServiceKey
);
2843 DPRINT("RQueryServiceConfigW() done\n");
2850 DWORD
RQueryServiceLockStatusW(
2851 SC_RPC_HANDLE hSCManager
,
2852 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2854 LPBOUNDED_DWORD_4K pcbBytesNeeded
)
2857 return ERROR_CALL_NOT_IMPLEMENTED
;
2862 DWORD
RStartServiceW(
2863 SC_RPC_HANDLE hService
,
2865 LPSTRING_PTRSW argv
)
2867 DWORD dwError
= ERROR_SUCCESS
;
2868 PSERVICE_HANDLE hSvc
;
2869 PSERVICE lpService
= NULL
;
2872 DPRINT("RStartServiceW(%p %lu %p) called\n", hService
, argc
, argv
);
2873 DPRINT(" argc: %lu\n", argc
);
2876 for (i
= 0; i
< argc
; i
++)
2878 DPRINT(" argv[%lu]: %S\n", i
, argv
[i
]);
2883 return ERROR_SHUTDOWN_IN_PROGRESS
;
2885 hSvc
= ScmGetServiceFromHandle(hService
);
2888 DPRINT1("Invalid service handle!\n");
2889 return ERROR_INVALID_HANDLE
;
2892 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
2895 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
2896 return ERROR_ACCESS_DENIED
;
2899 lpService
= hSvc
->ServiceEntry
;
2900 if (lpService
== NULL
)
2902 DPRINT("lpService == NULL!\n");
2903 return ERROR_INVALID_HANDLE
;
2906 if (lpService
->dwStartType
== SERVICE_DISABLED
)
2907 return ERROR_SERVICE_DISABLED
;
2909 if (lpService
->bDeleted
)
2910 return ERROR_SERVICE_MARKED_FOR_DELETE
;
2912 /* Start the service */
2913 dwError
= ScmStartService(lpService
, argc
, (LPWSTR
*)argv
);
2920 DWORD
RGetServiceDisplayNameW(
2921 SC_RPC_HANDLE hSCManager
,
2922 LPCWSTR lpServiceName
,
2923 LPWSTR lpDisplayName
,
2926 // PMANAGER_HANDLE hManager;
2931 DPRINT("RGetServiceDisplayNameW() called\n");
2932 DPRINT("hSCManager = %p\n", hSCManager
);
2933 DPRINT("lpServiceName: %S\n", lpServiceName
);
2934 DPRINT("lpDisplayName: %p\n", lpDisplayName
);
2935 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
2937 // hManager = (PMANAGER_HANDLE)hSCManager;
2938 // if (hManager->Handle.Tag != MANAGER_TAG)
2940 // DPRINT("Invalid manager handle!\n");
2941 // return ERROR_INVALID_HANDLE;
2944 /* Get service database entry */
2945 lpService
= ScmGetServiceEntryByName(lpServiceName
);
2946 if (lpService
== NULL
)
2948 DPRINT("Could not find a service!\n");
2950 /* If the service could not be found and lpcchBuffer is less than 2, windows
2951 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2952 if (*lpcchBuffer
< 2)
2955 if (lpDisplayName
!= NULL
)
2957 *lpDisplayName
= '\0';
2961 return ERROR_SERVICE_DOES_NOT_EXIST
;
2964 if (!lpService
->lpDisplayName
)
2966 dwLength
= wcslen(lpService
->lpServiceName
);
2968 if (lpDisplayName
!= NULL
&&
2969 *lpcchBuffer
> dwLength
)
2971 wcscpy(lpDisplayName
, lpService
->lpServiceName
);
2976 dwLength
= wcslen(lpService
->lpDisplayName
);
2978 if (lpDisplayName
!= NULL
&&
2979 *lpcchBuffer
> dwLength
)
2981 wcscpy(lpDisplayName
, lpService
->lpDisplayName
);
2985 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
2987 *lpcchBuffer
= dwLength
;
2994 DWORD
RGetServiceKeyNameW(
2995 SC_RPC_HANDLE hSCManager
,
2996 LPCWSTR lpDisplayName
,
2997 LPWSTR lpServiceName
,
3000 // PMANAGER_HANDLE hManager;
3005 DPRINT("RGetServiceKeyNameW() called\n");
3006 DPRINT("hSCManager = %p\n", hSCManager
);
3007 DPRINT("lpDisplayName: %S\n", lpDisplayName
);
3008 DPRINT("lpServiceName: %p\n", lpServiceName
);
3009 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer
);
3011 // hManager = (PMANAGER_HANDLE)hSCManager;
3012 // if (hManager->Handle.Tag != MANAGER_TAG)
3014 // DPRINT("Invalid manager handle!\n");
3015 // return ERROR_INVALID_HANDLE;
3018 /* Get service database entry */
3019 lpService
= ScmGetServiceEntryByDisplayName(lpDisplayName
);
3020 if (lpService
== NULL
)
3022 DPRINT("Could not find a service!\n");
3024 /* If the service could not be found and lpcchBuffer is less than 2, windows
3025 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3026 if (*lpcchBuffer
< 2)
3029 if (lpServiceName
!= NULL
)
3031 *lpServiceName
= '\0';
3035 return ERROR_SERVICE_DOES_NOT_EXIST
;
3038 dwLength
= wcslen(lpService
->lpServiceName
);
3040 if (lpServiceName
!= NULL
&&
3041 *lpcchBuffer
> dwLength
)
3043 wcscpy(lpServiceName
, lpService
->lpServiceName
);
3044 *lpcchBuffer
= dwLength
;
3045 return ERROR_SUCCESS
;
3048 dwError
= (*lpcchBuffer
> dwLength
) ? ERROR_SUCCESS
: ERROR_INSUFFICIENT_BUFFER
;
3050 *lpcchBuffer
= dwLength
;
3057 DWORD
RI_ScSetServiceBitsA(
3058 RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
3059 DWORD dwServiceBits
,
3061 int bUpdateImmediately
,
3065 return ERROR_CALL_NOT_IMPLEMENTED
;
3070 DWORD
RChangeServiceConfigA(
3071 SC_RPC_HANDLE hService
,
3072 DWORD dwServiceType
,
3074 DWORD dwErrorControl
,
3075 LPSTR lpBinaryPathName
,
3076 LPSTR lpLoadOrderGroup
,
3078 LPSTR lpDependencies
,
3080 LPSTR lpServiceStartName
,
3083 LPSTR lpDisplayName
)
3085 DWORD dwError
= ERROR_SUCCESS
;
3086 PSERVICE_HANDLE hSvc
;
3087 PSERVICE lpService
= NULL
;
3088 HKEY hServiceKey
= NULL
;
3089 LPWSTR lpDisplayNameW
= NULL
;
3090 // LPWSTR lpBinaryPathNameW = NULL;
3091 LPWSTR lpLoadOrderGroupW
= NULL
;
3092 LPWSTR lpDependenciesW
= NULL
;
3093 // LPWSTR lpPasswordW = NULL;
3095 DPRINT("RChangeServiceConfigA() called\n");
3096 DPRINT("dwServiceType = %lu\n", dwServiceType
);
3097 DPRINT("dwStartType = %lu\n", dwStartType
);
3098 DPRINT("dwErrorControl = %lu\n", dwErrorControl
);
3099 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName
);
3100 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup
);
3101 DPRINT("lpDisplayName = %s\n", lpDisplayName
);
3104 return ERROR_SHUTDOWN_IN_PROGRESS
;
3106 hSvc
= ScmGetServiceFromHandle(hService
);
3109 DPRINT1("Invalid service handle!\n");
3110 return ERROR_INVALID_HANDLE
;
3113 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3114 SERVICE_CHANGE_CONFIG
))
3116 DPRINT("Insufficient access rights! 0x%lx\n", hSvc
->Handle
.DesiredAccess
);
3117 return ERROR_ACCESS_DENIED
;
3120 lpService
= hSvc
->ServiceEntry
;
3121 if (lpService
== NULL
)
3123 DPRINT("lpService == NULL!\n");
3124 return ERROR_INVALID_HANDLE
;
3127 /* Lock the service database exclusively */
3128 ScmLockDatabaseExclusive();
3130 if (lpService
->bDeleted
)
3132 DPRINT("The service has already been marked for delete!\n");
3133 dwError
= ERROR_SERVICE_MARKED_FOR_DELETE
;
3137 /* Open the service key */
3138 dwError
= ScmOpenServiceKey(lpService
->szServiceName
,
3141 if (dwError
!= ERROR_SUCCESS
)
3144 /* Write service data to the registry */
3146 if (lpDisplayName
!= NULL
&& *lpDisplayName
!= 0)
3148 /* Set the display name */
3149 lpDisplayNameW
= HeapAlloc(GetProcessHeap(),
3151 (strlen(lpDisplayName
) + 1) * sizeof(WCHAR
));
3152 if (lpDisplayNameW
== NULL
)
3154 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3158 MultiByteToWideChar(CP_ACP
,
3163 strlen(lpDisplayName
) + 1);
3165 RegSetValueExW(hServiceKey
,
3169 (LPBYTE
)lpDisplayNameW
,
3170 (wcslen(lpDisplayNameW
) + 1) * sizeof(WCHAR
));
3172 /* Update lpService->lpDisplayName */
3173 if (lpService
->lpDisplayName
)
3174 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
3176 lpService
->lpDisplayName
= lpDisplayNameW
;
3179 if (dwServiceType
!= SERVICE_NO_CHANGE
)
3181 /* Set the service type */
3182 dwError
= RegSetValueExW(hServiceKey
,
3186 (LPBYTE
)&dwServiceType
,
3188 if (dwError
!= ERROR_SUCCESS
)
3191 lpService
->Status
.dwServiceType
= dwServiceType
;
3194 if (dwStartType
!= SERVICE_NO_CHANGE
)
3196 /* Set the start value */
3197 dwError
= RegSetValueExW(hServiceKey
,
3201 (LPBYTE
)&dwStartType
,
3203 if (dwError
!= ERROR_SUCCESS
)
3206 lpService
->dwStartType
= dwStartType
;
3209 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
3211 /* Set the error control value */
3212 dwError
= RegSetValueExW(hServiceKey
,
3216 (LPBYTE
)&dwErrorControl
,
3218 if (dwError
!= ERROR_SUCCESS
)
3221 lpService
->dwErrorControl
= dwErrorControl
;
3225 /* FIXME: set the new ImagePath value */
3227 /* Set the image path */
3228 if (dwServiceType
& SERVICE_WIN32
)
3230 if (lpBinaryPathName
!= NULL
&& *lpBinaryPathName
!= 0)
3232 lpBinaryPathNameW
=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName
)+1) * sizeof(WCHAR
));
3233 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, strlen(lpBinaryPathName
)+1);
3234 dwError
= RegSetValueExW(hServiceKey
,
3238 (LPBYTE
)lpBinaryPathNameW
,
3239 (wcslen(lpBinaryPathNameW
) + 1) * sizeof(WCHAR
));
3240 if (dwError
!= ERROR_SUCCESS
)
3244 else if (dwServiceType
& SERVICE_DRIVER
)
3246 if (lpImagePath
!= NULL
&& *lpImagePath
!= 0)
3248 dwError
= RegSetValueExW(hServiceKey
,
3252 (LPBYTE
)lpImagePath
,
3253 (wcslen(lpImagePath
) + 1) *sizeof(WCHAR
));
3254 if (dwError
!= ERROR_SUCCESS
)
3260 /* Set the group name */
3261 if (lpLoadOrderGroup
!= NULL
&& *lpLoadOrderGroup
!= 0)
3263 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(),
3265 (strlen(lpLoadOrderGroup
) + 1) * sizeof(WCHAR
));
3266 if (lpLoadOrderGroupW
== NULL
)
3268 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3272 MultiByteToWideChar(CP_ACP
,
3277 strlen(lpLoadOrderGroup
) + 1);
3279 dwError
= RegSetValueExW(hServiceKey
,
3283 (LPBYTE
)lpLoadOrderGroupW
,
3284 (wcslen(lpLoadOrderGroupW
) + 1) * sizeof(WCHAR
));
3285 if (dwError
!= ERROR_SUCCESS
)
3287 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3291 dwError
= ScmSetServiceGroup(lpService
,
3294 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3296 if (dwError
!= ERROR_SUCCESS
)
3300 if (lpdwTagId
!= NULL
)
3302 dwError
= ScmAssignNewTag(lpService
);
3303 if (dwError
!= ERROR_SUCCESS
)
3306 dwError
= RegSetValueExW(hServiceKey
,
3310 (LPBYTE
)&lpService
->dwTag
,
3312 if (dwError
!= ERROR_SUCCESS
)
3315 *lpdwTagId
= lpService
->dwTag
;
3318 /* Write dependencies */
3319 if (lpDependencies
!= NULL
&& *lpDependencies
!= 0)
3321 lpDependenciesW
= HeapAlloc(GetProcessHeap(),
3323 (strlen(lpDependencies
) + 1) * sizeof(WCHAR
));
3324 if (lpDependenciesW
== NULL
)
3326 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3330 MultiByteToWideChar(CP_ACP
,
3335 strlen(lpDependencies
) + 1);
3337 dwError
= ScmWriteDependencies(hServiceKey
,
3338 (LPWSTR
)lpDependenciesW
,
3341 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3344 if (lpPassword
!= NULL
)
3346 /* FIXME: Write password */
3350 /* Unlock the service database */
3351 ScmUnlockDatabase();
3353 if (hServiceKey
!= NULL
)
3354 RegCloseKey(hServiceKey
);
3356 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError
);
3363 DWORD
RCreateServiceA(
3364 SC_RPC_HANDLE hSCManager
,
3365 LPSTR lpServiceName
,
3366 LPSTR lpDisplayName
,
3367 DWORD dwDesiredAccess
,
3368 DWORD dwServiceType
,
3370 DWORD dwErrorControl
,
3371 LPSTR lpBinaryPathName
,
3372 LPSTR lpLoadOrderGroup
,
3374 LPBYTE lpDependencies
,
3376 LPSTR lpServiceStartName
,
3379 LPSC_RPC_HANDLE lpServiceHandle
)
3381 DWORD dwError
= ERROR_SUCCESS
;
3382 LPWSTR lpServiceNameW
= NULL
;
3383 LPWSTR lpDisplayNameW
= NULL
;
3384 LPWSTR lpBinaryPathNameW
= NULL
;
3385 LPWSTR lpLoadOrderGroupW
= NULL
;
3386 LPWSTR lpDependenciesW
= NULL
;
3387 LPWSTR lpServiceStartNameW
= NULL
;
3388 DWORD dwDependenciesLength
= 0;
3395 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, NULL
, 0);
3396 lpServiceNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3397 if (!lpServiceNameW
)
3399 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3402 MultiByteToWideChar(CP_ACP
, 0, lpServiceName
, -1, lpServiceNameW
, len
);
3407 len
= MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, NULL
, 0);
3408 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3409 if (!lpDisplayNameW
)
3411 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3414 MultiByteToWideChar(CP_ACP
, 0, lpDisplayName
, -1, lpDisplayNameW
, len
);
3417 if (lpBinaryPathName
)
3419 len
= MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, NULL
, 0);
3420 lpBinaryPathNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3421 if (!lpBinaryPathNameW
)
3423 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3426 MultiByteToWideChar(CP_ACP
, 0, lpBinaryPathName
, -1, lpBinaryPathNameW
, len
);
3429 if (lpLoadOrderGroup
)
3431 len
= MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, NULL
, 0);
3432 lpLoadOrderGroupW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3433 if (!lpLoadOrderGroupW
)
3435 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3438 MultiByteToWideChar(CP_ACP
, 0, lpLoadOrderGroup
, -1, lpLoadOrderGroupW
, len
);
3443 lpStr
= (LPSTR
)lpDependencies
;
3446 dwLength
= strlen(lpStr
) + 1;
3447 dwDependenciesLength
+= dwLength
;
3448 lpStr
= lpStr
+ dwLength
;
3450 dwDependenciesLength
++;
3452 lpDependenciesW
= HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength
* sizeof(WCHAR
));
3453 if (!lpDependenciesW
)
3455 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3458 MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)lpDependencies
, dwDependenciesLength
, lpDependenciesW
, dwDependenciesLength
);
3461 if (lpServiceStartName
)
3463 len
= MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, NULL
, 0);
3464 lpServiceStartNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3465 if (!lpServiceStartNameW
)
3467 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3470 MultiByteToWideChar(CP_ACP
, 0, lpServiceStartName
, -1, lpServiceStartNameW
, len
);
3473 dwError
= RCreateServiceW(hSCManager
,
3483 (LPBYTE
)lpDependenciesW
,
3484 dwDependenciesLength
,
3485 lpServiceStartNameW
,
3491 if (lpServiceNameW
!=NULL
)
3492 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
3494 if (lpDisplayNameW
!= NULL
)
3495 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
3497 if (lpBinaryPathNameW
!= NULL
)
3498 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW
);
3500 if (lpLoadOrderGroupW
!= NULL
)
3501 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW
);
3503 if (lpDependenciesW
!= NULL
)
3504 HeapFree(GetProcessHeap(), 0, lpDependenciesW
);
3506 if (lpServiceStartNameW
!= NULL
)
3507 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW
);
3514 DWORD
REnumDependentServicesA(
3515 SC_RPC_HANDLE hService
,
3516 DWORD dwServiceState
,
3519 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3520 LPBOUNDED_DWORD_256K lpServicesReturned
)
3522 DWORD dwError
= ERROR_SUCCESS
;
3523 DWORD dwServicesReturned
= 0;
3524 DWORD dwServiceCount
;
3525 HKEY hServicesKey
= NULL
;
3526 PSERVICE_HANDLE hSvc
;
3527 PSERVICE lpService
= NULL
;
3528 PSERVICE
*lpServicesArray
= NULL
;
3529 LPENUM_SERVICE_STATUSA lpServicesPtr
= NULL
;
3532 *pcbBytesNeeded
= 0;
3533 *lpServicesReturned
= 0;
3535 DPRINT("REnumDependentServicesA() called\n");
3537 hSvc
= ScmGetServiceFromHandle(hService
);
3540 DPRINT1("Invalid service handle!\n");
3541 return ERROR_INVALID_HANDLE
;
3544 lpService
= hSvc
->ServiceEntry
;
3546 /* Check access rights */
3547 if (!RtlAreAllAccessesGranted(hSvc
->Handle
.DesiredAccess
,
3548 SC_MANAGER_ENUMERATE_SERVICE
))
3550 DPRINT("Insufficient access rights! 0x%lx\n",
3551 hSvc
->Handle
.DesiredAccess
);
3552 return ERROR_ACCESS_DENIED
;
3555 /* Open the Services Reg key */
3556 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
3557 L
"System\\CurrentControlSet\\Services",
3562 if (dwError
!= ERROR_SUCCESS
)
3565 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3566 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3567 are the same for both. Verified in WINXP. */
3569 /* First determine the bytes needed and get the number of dependent services*/
3570 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3575 &dwServicesReturned
);
3576 if (dwError
!= ERROR_SUCCESS
)
3579 /* If buffer size is less than the bytes needed or pointer is null*/
3580 if ((!lpServices
) || (cbBufSize
< *pcbBytesNeeded
))
3582 dwError
= ERROR_MORE_DATA
;
3586 /* Allocate memory for array of service pointers */
3587 lpServicesArray
= HeapAlloc(GetProcessHeap(),
3589 (dwServicesReturned
+ 1) * sizeof(PSERVICE
));
3590 if (!lpServicesArray
)
3592 DPRINT("Could not allocate a buffer!!\n");
3593 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
3597 dwServicesReturned
= 0;
3598 *pcbBytesNeeded
= 0;
3600 dwError
= Int_EnumDependentServicesW(hServicesKey
,
3605 &dwServicesReturned
);
3606 if (dwError
!= ERROR_SUCCESS
)
3611 lpServicesPtr
= (LPENUM_SERVICE_STATUSA
)lpServices
;
3612 lpStr
= (LPSTR
)(lpServices
+ (dwServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
)));
3614 /* Copy EnumDepenedentService to Buffer */
3615 for (dwServiceCount
= 0; dwServiceCount
< dwServicesReturned
; dwServiceCount
++)
3617 lpService
= lpServicesArray
[dwServiceCount
];
3619 /* Copy the status info */
3620 memcpy(&lpServicesPtr
->ServiceStatus
,
3622 sizeof(SERVICE_STATUS
));
3624 /* Copy display name */
3625 WideCharToMultiByte(CP_ACP
,
3627 lpService
->lpDisplayName
,
3630 wcslen(lpService
->lpDisplayName
),
3633 lpServicesPtr
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3634 lpStr
+= strlen(lpStr
) + 1;
3636 /* Copy service name */
3637 WideCharToMultiByte(CP_ACP
,
3639 lpService
->lpServiceName
,
3642 wcslen(lpService
->lpServiceName
),
3645 lpServicesPtr
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStr
- (ULONG_PTR
)lpServices
);
3646 lpStr
+= strlen(lpStr
) + 1;
3651 *lpServicesReturned
= dwServicesReturned
;
3654 if (lpServicesArray
)
3655 HeapFree(GetProcessHeap(), 0, lpServicesArray
);
3657 RegCloseKey(hServicesKey
);
3659 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError
);
3666 DWORD
REnumServicesStatusA(
3667 SC_RPC_HANDLE hSCManager
,
3668 DWORD dwServiceType
,
3669 DWORD dwServiceState
,
3672 LPBOUNDED_DWORD_256K pcbBytesNeeded
,
3673 LPBOUNDED_DWORD_256K lpServicesReturned
,
3674 LPBOUNDED_DWORD_256K lpResumeHandle
)
3676 LPENUM_SERVICE_STATUSW lpStatusPtrW
= NULL
;
3677 LPENUM_SERVICE_STATUSA lpStatusPtrA
= NULL
;
3678 LPWSTR lpStringPtrW
;
3681 DWORD dwServiceCount
;
3683 DPRINT("REnumServicesStatusA() called\n");
3685 if ((dwBufSize
> 0) && (lpBuffer
))
3687 lpStatusPtrW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwBufSize
);
3690 DPRINT("Failed to allocate buffer!\n");
3691 return ERROR_NOT_ENOUGH_MEMORY
;
3695 dwError
= REnumServicesStatusW(hSCManager
,
3698 (LPBYTE
)lpStatusPtrW
,
3704 /* if no services were returned then we are Done */
3705 if (*lpServicesReturned
== 0)
3708 lpStatusPtrA
= (LPENUM_SERVICE_STATUSA
)lpBuffer
;
3709 lpStringPtrA
= (LPSTR
)((ULONG_PTR
)lpBuffer
+
3710 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSA
));
3711 lpStringPtrW
= (LPWSTR
)((ULONG_PTR
)lpStatusPtrW
+
3712 *lpServicesReturned
* sizeof(ENUM_SERVICE_STATUSW
));
3714 for (dwServiceCount
= 0; dwServiceCount
< *lpServicesReturned
; dwServiceCount
++)
3716 /* Copy the service name */
3717 WideCharToMultiByte(CP_ACP
,
3722 wcslen(lpStringPtrW
),
3726 lpStatusPtrA
->lpServiceName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3727 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3728 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3730 /* Copy the display name */
3731 WideCharToMultiByte(CP_ACP
,
3736 wcslen(lpStringPtrW
),
3740 lpStatusPtrA
->lpDisplayName
= (LPSTR
)((ULONG_PTR
)lpStringPtrA
- (ULONG_PTR
)lpBuffer
);
3741 lpStringPtrA
+= wcslen(lpStringPtrW
) + 1;
3742 lpStringPtrW
+= wcslen(lpStringPtrW
) + 1;
3744 /* Copy the status information */
3745 memcpy(&lpStatusPtrA
->ServiceStatus
,
3746 &lpStatusPtrW
->ServiceStatus
,
3747 sizeof(SERVICE_STATUS
));
3754 HeapFree(GetProcessHeap(), 0, lpStatusPtrW
);
3756 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError
);
3763 DWORD
ROpenSCManagerA(
3764 LPSTR lpMachineName
,
3765 LPSTR lpDatabaseName
,
3766 DWORD dwDesiredAccess
,
3767 LPSC_RPC_HANDLE lpScHandle
)
3769 UNICODE_STRING MachineName
;
3770 UNICODE_STRING DatabaseName
;
3773 DPRINT("ROpenSCManagerA() called\n");
3776 RtlCreateUnicodeStringFromAsciiz(&MachineName
,
3780 RtlCreateUnicodeStringFromAsciiz(&DatabaseName
,