diff --git a/reactos/include/idl/svcctl.idl b/reactos/include/idl/svcctl.idl index 1bd65c06709..24436eae702 100644 --- a/reactos/include/idl/svcctl.idl +++ b/reactos/include/idl/svcctl.idl @@ -77,23 +77,23 @@ cpp_quote("#endif") /* Function 12 */ -// DWORD ScmrCreateServiceW([in] handle_t BindingHandle, -// [in] SC_HANDLE hSCManager, -// [in, string, ref] LPCWSTR lpServiceName, -// [in, string, ref] LPCWSTR lpDisplayName, -// [in] DWORD dwDesiredAccess, -// [in] DWORD dwServiceType, -// [in] DWORD dwStartType, -// [in] DWORD dwErrorControl, -// [in, string, ref] LPCWSTR lpBinaryPathName, -// [in, string, unique] LPCWSTR lpLoadOrderGroup, -// [out] LPDWORD lpdwTagId, -// [in, size_is(dwDepwndenciesLength), unique] LPCWSTR lpDependencies, -// [in] DWORD dwDependenciesLength, -// [in, string, unique] LPCWSTR lpServiceStartName, -// [in, size_is(dwPasswordLength), unique] LPCWSTR lpPassword, -// [in] DWORD dwPasswordLength, -// [out] SC_HANDLE *hService); + DWORD ScmrCreateServiceW([in] handle_t BindingHandle, + [in] SC_HANDLE hSCManager, + [in, string, ref] LPCWSTR lpServiceName, + [in, string, unique] LPCWSTR lpDisplayName, + [in] DWORD dwDesiredAccess, + [in] DWORD dwServiceType, + [in] DWORD dwStartType, + [in] DWORD dwErrorControl, + [in, string, ref] LPCWSTR lpBinaryPathName, + [in, string, unique] LPCWSTR lpLoadOrderGroup, + [in, out, unique] LPDWORD lpdwTagId, + [in, size_is(dwDependenciesLength), unique] LPCWSTR lpDependencies, + [in] DWORD dwDependenciesLength, + [in, string, unique] LPCWSTR lpServiceStartName, + [in, size_is(dwPasswordLength), unique] LPCWSTR lpPassword, + [in] DWORD dwPasswordLength, + [out] SC_HANDLE *hService); /* Function 15 */ diff --git a/reactos/lib/advapi32/service/scm.c b/reactos/lib/advapi32/service/scm.c index 5e91b2fa3e7..47f7c4f27bf 100644 --- a/reactos/lib/advapi32/service/scm.c +++ b/reactos/lib/advapi32/service/scm.c @@ -245,25 +245,54 @@ CreateServiceA( * * @unimplemented */ -SC_HANDLE -STDCALL -CreateServiceW( - SC_HANDLE hSCManager, - LPCWSTR lpServiceName, - LPCWSTR lpDisplayName, - DWORD dwDesiredAccess, - DWORD dwServiceType, - DWORD dwStartType, - DWORD dwErrorControl, - LPCWSTR lpBinaryPathName, - LPCWSTR lpLoadOrderGroup, - LPDWORD lpdwTagId, - LPCWSTR lpDependencies, - LPCWSTR lpServiceStartName, - LPCWSTR lpPassword) +SC_HANDLE STDCALL +CreateServiceW(SC_HANDLE hSCManager, + LPCWSTR lpServiceName, + LPCWSTR lpDisplayName, + DWORD dwDesiredAccess, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + LPCWSTR lpBinaryPathName, + LPCWSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, + LPCWSTR lpDependencies, + LPCWSTR lpServiceStartName, + LPCWSTR lpPassword) { - DPRINT1("CreateServiceW is unimplemented, but returning INVALID_HANDLE_VALUE instead of NULL\n"); - return INVALID_HANDLE_VALUE; + SC_HANDLE hService = NULL; + DWORD dwError; + + DPRINT1("CreateServiceW() called\n"); + + HandleBind(); + + /* Call to services.exe using RPC */ + dwError = ScmrCreateServiceW(BindingHandle, + (unsigned int)hSCManager, + (LPWSTR)lpServiceName, + (LPWSTR)lpDisplayName, + dwDesiredAccess, + dwServiceType, + dwStartType, + dwErrorControl, + (LPWSTR)lpBinaryPathName, + (LPWSTR)lpLoadOrderGroup, + lpdwTagId, + NULL, /* FIXME: lpDependencies */ + 0, /* FIXME: dwDependenciesLength */ + (LPWSTR)lpServiceStartName, + NULL, /* FIXME: lpPassword */ + 0, /* FIXME: dwPasswordLength */ + (unsigned int *)&hService); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("ScmrCreateServiceW() failed (Error %lu)\n", dwError); + SetLastError(dwError); + return INVALID_HANDLE_VALUE; + } + + return hService; } diff --git a/reactos/subsys/system/services/database.c b/reactos/subsys/system/services/database.c index c5d8e2ca3e6..8310327319a 100644 --- a/reactos/subsys/system/services/database.c +++ b/reactos/subsys/system/services/database.c @@ -25,9 +25,14 @@ /* INCLUDES *****************************************************************/ -#include "services.h" +#include +#define NTOS_MODE_USER +#include + #include +#include "services.h" + #define NDEBUG #include @@ -46,13 +51,13 @@ typedef struct _SERVICE_GROUP } SERVICE_GROUP, *PSERVICE_GROUP; - - /* GLOBALS *******************************************************************/ LIST_ENTRY GroupListHead; LIST_ENTRY ServiceListHead; +static RTL_RESOURCE DatabaseLock; + /* FUNCTIONS *****************************************************************/ @@ -66,18 +71,18 @@ ScmGetServiceEntryByName(PUNICODE_STRING ServiceName) ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) - { - CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, - ServiceListEntry); - if (RtlEqualUnicodeString(&CurrentService->ServiceName, ServiceName, TRUE)) { - DPRINT("Found service: '%wZ'\n", &CurrentService->ServiceName); - return CurrentService; - } + CurrentService = CONTAINING_RECORD(ServiceEntry, + SERVICE, + ServiceListEntry); + if (RtlEqualUnicodeString(&CurrentService->ServiceName, ServiceName, TRUE)) + { + DPRINT("Found service: '%wZ'\n", &CurrentService->ServiceName); + return CurrentService; + } - ServiceEntry = ServiceEntry->Flink; - } + ServiceEntry = ServiceEntry->Flink; + } DPRINT("Couldn't find a matching service\n"); @@ -87,48 +92,50 @@ ScmGetServiceEntryByName(PUNICODE_STRING ServiceName) static NTSTATUS STDCALL CreateGroupOrderListRoutine(PWSTR ValueName, - ULONG ValueType, - PVOID ValueData, - ULONG ValueLength, - PVOID Context, - PVOID EntryContext) + ULONG ValueType, + PVOID ValueData, + ULONG ValueLength, + PVOID Context, + PVOID EntryContext) { - PSERVICE_GROUP Group; + PSERVICE_GROUP Group; - DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n", - ValueName, ValueType, ValueData, ValueLength, Context, EntryContext); + DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n", + ValueName, ValueType, ValueData, ValueLength, Context, EntryContext); - if (ValueType == REG_BINARY && - ValueData != NULL && - ValueLength >= sizeof(DWORD) && - ValueLength >= (*(PULONG)ValueData + 1) * sizeof(DWORD)) + if (ValueType == REG_BINARY && + ValueData != NULL && + ValueLength >= sizeof(DWORD) && + ValueLength >= (*(PULONG)ValueData + 1) * sizeof(DWORD)) { - Group = (PSERVICE_GROUP)Context; - Group->TagCount = ((PULONG)ValueData)[0]; - if (Group->TagCount > 0) + Group = (PSERVICE_GROUP)Context; + Group->TagCount = ((PULONG)ValueData)[0]; + if (Group->TagCount > 0) { - if (ValueLength >= (Group->TagCount + 1) * sizeof(DWORD)) + if (ValueLength >= (Group->TagCount + 1) * sizeof(DWORD)) { - Group->TagArray = (PULONG)HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - Group->TagCount * sizeof(DWORD)); - if (Group->TagArray == NULL) - { - Group->TagCount = 0; - return STATUS_INSUFFICIENT_RESOURCES; - } - RtlCopyMemory(Group->TagArray, - (PULONG)ValueData + 1, - Group->TagCount * sizeof(DWORD)); - } - else - { - Group->TagCount = 0; - return STATUS_UNSUCCESSFUL; - } - } + Group->TagArray = (PULONG)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + Group->TagCount * sizeof(DWORD)); + if (Group->TagArray == NULL) + { + Group->TagCount = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(Group->TagArray, + (PULONG)ValueData + 1, + Group->TagCount * sizeof(DWORD)); + } + else + { + Group->TagCount = 0; + return STATUS_UNSUCCESSFUL; + } + } } - return STATUS_SUCCESS; + + return STATUS_SUCCESS; } @@ -140,45 +147,44 @@ CreateGroupListRoutine(PWSTR ValueName, PVOID Context, PVOID EntryContext) { - PSERVICE_GROUP Group; - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; - NTSTATUS Status; + PSERVICE_GROUP Group; + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + NTSTATUS Status; - if (ValueType == REG_SZ) + if (ValueType == REG_SZ) { - DPRINT("Data: '%S'\n", (PWCHAR)ValueData); + DPRINT("Data: '%S'\n", (PWCHAR)ValueData); - Group = (PSERVICE_GROUP)HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(SERVICE_GROUP)); - if (Group == NULL) - { - return STATUS_INSUFFICIENT_RESOURCES; - } + Group = (PSERVICE_GROUP)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(SERVICE_GROUP)); + if (Group == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } - if (!RtlCreateUnicodeString(&Group->GroupName, - (PWSTR)ValueData)) - { - return STATUS_INSUFFICIENT_RESOURCES; - } + if (!RtlCreateUnicodeString(&Group->GroupName, + (PWSTR)ValueData)) + { + return STATUS_INSUFFICIENT_RESOURCES; + } - RtlZeroMemory(&QueryTable, sizeof(QueryTable)); - QueryTable[0].Name = (PWSTR)ValueData; - QueryTable[0].QueryRoutine = CreateGroupOrderListRoutine; + RtlZeroMemory(&QueryTable, sizeof(QueryTable)); + QueryTable[0].Name = (PWSTR)ValueData; + QueryTable[0].QueryRoutine = CreateGroupOrderListRoutine; - Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, - L"GroupOrderList", - QueryTable, - (PVOID)Group, - NULL); - DPRINT("%x %d %S\n", Status, Group->TagCount, (PWSTR)ValueData); + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"GroupOrderList", + QueryTable, + (PVOID)Group, + NULL); + DPRINT("%x %d %S\n", Status, Group->TagCount, (PWSTR)ValueData); - - InsertTailList(&GroupListHead, - &Group->GroupListEntry); + InsertTailList(&GroupListHead, + &Group->GroupListEntry); } - return STATUS_SUCCESS; + return STATUS_SUCCESS; } @@ -296,7 +302,7 @@ ScmCreateServiceDataBase(VOID) { RTL_QUERY_REGISTRY_TABLE QueryTable[2]; OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING ServicesKeyName = + UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"); UNICODE_STRING SubKeyName; HKEY ServicesKey; @@ -313,6 +319,9 @@ ScmCreateServiceDataBase(VOID) InitializeListHead(&GroupListHead); InitializeListHead(&ServiceListHead); + /* Initialize the database lock */ + RtlInitializeResource(&DatabaseLock); + /* Build group order list */ RtlZeroMemory(&QueryTable, sizeof(QueryTable)); @@ -328,6 +337,9 @@ ScmCreateServiceDataBase(VOID) if (!NT_SUCCESS(Status)) return Status; + RtlInitUnicodeString(&ServicesKeyName, + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"); + InitializeObjectAttributes(&ObjectAttributes, &ServicesKeyName, OBJ_CASE_INSENSITIVE, @@ -926,4 +938,13 @@ ScmAutoStartServices(VOID) } } + +DWORD +ScmMarkServiceForDelete(PSERVICE pService) +{ + DPRINT1("ScmMarkServiceForDelete() called\n"); + + return ERROR_SUCCESS; +} + /* EOF */ diff --git a/reactos/subsys/system/services/rpcserver.c b/reactos/subsys/system/services/rpcserver.c index 5edd4e05fb2..d735dcacebc 100644 --- a/reactos/subsys/system/services/rpcserver.c +++ b/reactos/subsys/system/services/rpcserver.c @@ -4,6 +4,10 @@ /* INCLUDES ****************************************************************/ +#include +#define NTOS_MODE_USER +#include + #include "services.h" #include "svcctl_s.h" @@ -107,13 +111,13 @@ ScmStartRpcServer(VOID) DPRINT("ScmStartRpcServer() called"); - Status = RpcServerUseProtseqEp(L"ncacn_np", - 10, - L"\\pipe\\ntsvcs", - NULL); + Status = RpcServerUseProtseqEpW(L"ncacn_np", + 10, + L"\\pipe\\ntsvcs", + NULL); if (Status != RPC_S_OK) { - DPRINT1("RpcServerUseProtseqEp() failed (Status %lx)\n", Status); + DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status); return; } @@ -142,7 +146,7 @@ ScmCreateManagerHandle(LPWSTR lpDatabaseName, SC_HANDLE *Handle) { PMANAGER_HANDLE Ptr; - + if (lpDatabaseName == NULL) lpDatabaseName = SERVICES_ACTIVE_DATABASEW; @@ -325,6 +329,7 @@ ScmrDeleteService(handle_t BindingHandle, { PSERVICE_HANDLE hSvc; PSERVICE lpService; + DWORD dwError; DPRINT1("ScmrDeleteService() called\n"); @@ -343,9 +348,16 @@ ScmrDeleteService(handle_t BindingHandle, return ERROR_INVALID_HANDLE; } - /* FIXME: Mark service for delete */ + /* FIXME: Acquire service database lock exclusively */ - return ERROR_SUCCESS; + /* Mark service for delete */ + dwError = ScmMarkServiceForDelete(lpService); + + /* FIXME: Release service database lock */ + + DPRINT1("ScmrDeleteService() done\n"); + + return dwError; } @@ -471,9 +483,49 @@ ScmrNotifyBootConfigStatus(handle_t BindingHandle, } +#if 0 +static DWORD +CreateServiceKey(LPWSTR lpServiceName, PHKEY phKey) +{ + HKEY hServicesKey = NULL; + DWORD dwDisposition; + DWORD dwError; + + *phKey = NULL; + + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"System\\CurrentControlSet\\Services", + 0, + KEY_WRITE, + &hServicesKey); + if (dwError != ERROR_SUCCESS) + return dwError; + + dwError = RegCreateKeyExW(hServicesKey, + lpServiceName, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, + phKey, + &dwDisposition); + if ((dwError == ERROR_SUCCESS) && + (dwDisposition == REG_OPENED_EXISTING_KEY)) + { + RegCloseKey(*phKey); + *phKey = NULL; + dwError = ERROR_SERVICE_EXISTS; + } + + RegCloseKey(hServicesKey); + + return dwError; +} +#endif + /* Function 12 */ -#if 0 unsigned long ScmrCreateServiceW(handle_t BindingHandle, unsigned int hSCManager, @@ -485,18 +537,169 @@ ScmrCreateServiceW(handle_t BindingHandle, unsigned long dwErrorControl, wchar_t *lpBinaryPathName, wchar_t *lpLoadOrderGroup, - unsigned long *lpdwTagId, + unsigned long *lpdwTagId, /* in, out */ wchar_t *lpDependencies, + unsigned long dwDependenciesLength, wchar_t *lpServiceStartName, - wchar_t *lpPassword) + wchar_t *lpPassword, + unsigned long dwPasswordLength, + unsigned int *hService) /* out */ { - DPRINT1("ScmrCreateServiceW() called\n"); - if (lpdwTagId != NULL) - *lpdwTagId = 0; - return ERROR_SUCCESS; -} + PMANAGER_HANDLE hManager; + DWORD dwError = ERROR_SUCCESS; +#if 0 + HKEY hServiceKey = NULL; + LPWSTR lpImagePath = NULL; #endif + DPRINT1("ScmrCreateServiceW() called\n"); + DPRINT1("lpServiceName = %S\n", lpServiceName); + DPRINT1("lpDisplayName = %S\n", lpDisplayName); + DPRINT1("dwDesiredAccess = %lx\n", dwDesiredAccess); + DPRINT1("dwServiceType = %lu\n", dwServiceType); + DPRINT1("dwStartType = %lu\n", dwStartType); + DPRINT1("dwErrorControl = %lu\n", dwErrorControl); + DPRINT1("lpBinaryPathName = %S\n", lpBinaryPathName); + DPRINT1("lpLoadOrderGroup = %S\n", lpLoadOrderGroup); + + hManager = (PMANAGER_HANDLE)hSCManager; + if (hManager->Handle.Tag != MANAGER_TAG) + { + DPRINT1("Invalid manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Check access rights */ + if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, + SC_MANAGER_CREATE_SERVICE)) + { + DPRINT1("Insufficient access rights! 0x%lx\n", + hManager->Handle.DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + /* FIXME: Fail if the service already exists! */ + +#if 0 + if (dwServiceType & SERVICE_DRIVER) + { + /* FIXME: Adjust the image path */ + lpImagePath = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + wcslen(lpBinaryPathName) + sizeof(WCHAR)); + if (lpImagePath == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + wcscpy(lpImagePath, lpBinaryPathName); + } + + /* FIXME: Allocate and fill a service entry */ + +// if (lpdwTagId != NULL) +// *lpdwTagId = 0; + +// *hService = 0; + + + /* Write service data to the registry */ + /* Create the service key */ + dwError = CreateServiceKey(lpServiceName, &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto done; + + if ((lpDisplayName != NULL) && (wcslen(lpDisplayName) > 0)) + { + RegSetValueExW(hServiceKey, + L"DisplayName", + 0, + REG_SZ, + (LPBYTE)lpDisplayName, + (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); + } + + /* Set the service type */ + dwError = RegSetValueExW(hServiceKey, + L"Type", + 0, + REG_DWORD, + (LPBYTE)&dwServiceType, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Set the start value */ + dwError = RegSetValueExW(hServiceKey, + L"Start", + 0, + REG_DWORD, + (LPBYTE)&dwStartType, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Set the error control value */ + dwError = RegSetValueExW(hServiceKey, + L"ErrorControl", + 0, + REG_DWORD, + (LPBYTE)&dwErrorControl, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Set the image path */ + if (dwServiceType & SERVICE_WIN32) + { + dwError = RegSetValueExW(hServiceKey, + L"ImagePath", + 0, + REG_SZ, + (LPBYTE)lpBinaryPathName, + (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + } + else if (dwServiceType & SERVICE_DRIVER) + { + /* FIXME: Adjust the path name */ + dwError = RegSetValueExW(hServiceKey, + L"ImagePath", + 0, + REG_SZ, + (LPBYTE)lpImagePath, + (wcslen(lpImagePath) + 1) *sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + } + + /* Set the group name */ + if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) + { + dwError = RegSetValueExW(hServiceKey, + L"Group", + 0, + REG_SZ, + (LPBYTE)lpLoadOrderGroup, + (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + } + +done:; + if (hServiceKey != NULL) + RegCloseKey(hServiceKey); + + if (lpImagePath != NULL) + HeapFree(GetProcessHeap(), 0, lpImagePath); +#endif + + DPRINT1("ScmrCreateServiceW() done (Error %lu)\n", dwError); + + return dwError; +} + /* Function 15 */ unsigned long diff --git a/reactos/subsys/system/services/services.c b/reactos/subsys/system/services/services.c index 6a7eb53c870..8235c503718 100644 --- a/reactos/subsys/system/services/services.c +++ b/reactos/subsys/system/services/services.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * service control manager * * ReactOS Operating System @@ -29,6 +28,10 @@ /* INCLUDES *****************************************************************/ +#include +#define NTOS_MODE_USER +#include + #include "services.h" #define NDEBUG diff --git a/reactos/subsys/system/services/services.h b/reactos/subsys/system/services/services.h index d2847f5f961..489343eb046 100644 --- a/reactos/subsys/system/services/services.h +++ b/reactos/subsys/system/services/services.h @@ -1,12 +1,12 @@ +/* + * services.h + */ + #include #include #define NTOS_MODE_USER #include -/* - * services.h - */ - typedef struct _SERVICE { LIST_ENTRY ServiceListEntry; @@ -45,8 +45,8 @@ NTSTATUS ScmCreateServiceDataBase(VOID); VOID ScmGetBootAndSystemDriverState(VOID); VOID ScmAutoStartServices(VOID); -PSERVICE -ScmGetServiceEntryByName(PUNICODE_STRING ServiceName); +PSERVICE ScmGetServiceEntryByName(PUNICODE_STRING ServiceName); +DWORD ScmMarkServiceForDelete(PSERVICE pService); /* rpcserver.c */