diff --git a/reactos/include/services/services.h b/reactos/include/services/services.h new file mode 100644 index 00000000000..95818c026a3 --- /dev/null +++ b/reactos/include/services/services.h @@ -0,0 +1,24 @@ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: include/services/services.h + * PURPOSE: Private interface between SERVICES.EXE and ADVAPI32.DLL + * PROGRAMMER: Eric Kohl + */ + +#ifndef __SERVICES_SERVICES_H__ +#define __SERVICES_SERVICES_H__ + +#define SCM_START_COMMAND 1 + +typedef struct _SCM_START_PACKET +{ + ULONG Command; + ULONG Size; + WCHAR Arguments[1]; +} SCM_START_PACKET, *PSCM_START_PACKET; + +#endif /* __SERVICES_SERVICES_H__ */ + +/* EOF */ diff --git a/reactos/lib/advapi32/service/sctrl.c b/reactos/lib/advapi32/service/sctrl.c index 7b033a5341f..defa64c0152 100644 --- a/reactos/lib/advapi32/service/sctrl.c +++ b/reactos/lib/advapi32/service/sctrl.c @@ -13,6 +13,8 @@ /* INCLUDES ******************************************************************/ #include "advapi32.h" +#include + #define NDEBUG #include @@ -23,9 +25,15 @@ typedef struct _ACTIVE_SERVICE { DWORD ThreadId; UNICODE_STRING ServiceName; - LPSERVICE_MAIN_FUNCTIONW MainFunction; + union + { + LPSERVICE_MAIN_FUNCTIONA lpFuncA; + LPSERVICE_MAIN_FUNCTIONW lpFuncW; + } Main; LPHANDLER_FUNCTION HandlerFunction; SERVICE_STATUS ServiceStatus; + BOOL bUnicode; + LPWSTR Arguments; } ACTIVE_SERVICE, *PACTIVE_SERVICE; @@ -33,7 +41,6 @@ typedef struct _ACTIVE_SERVICE static DWORD dwActiveServiceCount = 0; static PACTIVE_SERVICE lpActiveServices = NULL; -/* static PHANDLE ActiveServicesThreadHandles; */ /* uncomment when in use */ /* FUNCTIONS *****************************************************************/ @@ -80,15 +87,53 @@ static DWORD WINAPI ScServiceMainStub(LPVOID Context) { PACTIVE_SERVICE lpService; + DWORD dwArgCount = 0; + DWORD dwLength = 0; lpService = (PACTIVE_SERVICE)Context; DPRINT("ScServiceMainStub() called\n"); - /* FIXME: Send argc and argv (from command line) as arguments */ + /* Count arguments */ + while (lpService->Arguments[dwLength]) + { + dwLength += wcslen(&lpService->Arguments[dwLength]) + 1; + dwArgCount++; + } + /* Build the argument vector and call the main service routine */ + if (lpService->bUnicode) + { + LPWSTR *lpArgVector; + LPWSTR Ptr; - (lpService->MainFunction)(0, NULL); + lpArgVector = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (dwArgCount + 1) * sizeof(LPWSTR)); + if (lpArgVector == NULL) + return ERROR_OUTOFMEMORY; + + dwArgCount = 0; + Ptr = lpService->Arguments; + while (*Ptr) + { + lpArgVector[dwArgCount] = Ptr; + + dwArgCount++; + Ptr += (wcslen(Ptr) + 1); + } + lpArgVector[dwArgCount] = NULL; + + (lpService->Main.lpFuncW)(dwArgCount, lpArgVector); + + HeapFree(GetProcessHeap(), + 0, + lpArgVector); + } + else + { + (lpService->Main.lpFuncA)(0, NULL); + } return ERROR_SUCCESS; } @@ -141,17 +186,29 @@ ScConnectControlPipe(HANDLE *hPipe) } -static BOOL -ScServiceDispatcher(HANDLE hPipe, - PUCHAR lpBuffer, - DWORD dwBufferSize) + +static DWORD +ScStartService(PSCM_START_PACKET StartPacket) { PACTIVE_SERVICE lpService; HANDLE ThreadHandle; - DPRINT("ScDispatcherLoop() called\n"); + DPRINT("Size: %lu\n", StartPacket->Size); + DPRINT("Service: %S\n", &StartPacket->Arguments[0]); - lpService = &lpActiveServices[0]; + lpService = ScLookupServiceByServiceName(&StartPacket->Arguments[0]); + if (lpService == NULL) + return ERROR_SERVICE_DOES_NOT_EXIST; + + lpService->Arguments = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + StartPacket->Size); + if (lpService->Arguments == NULL) + return ERROR_OUTOFMEMORY; + + memcpy(lpService->Arguments, + StartPacket->Arguments, + StartPacket->Size * sizeof(WCHAR)); ThreadHandle = CreateThread(NULL, 0, @@ -160,21 +217,63 @@ ScServiceDispatcher(HANDLE hPipe, CREATE_SUSPENDED, &lpService->ThreadId); if (ThreadHandle == NULL) - return FALSE; + return ERROR_SERVICE_NO_THREAD; ResumeThread(ThreadHandle); - CloseHandle(ThreadHandle); -#if 0 + return ERROR_SUCCESS; +} + + +static BOOL +ScServiceDispatcher(HANDLE hPipe, + PUCHAR lpBuffer, + DWORD dwBufferSize) +{ + LPDWORD Buffer; + DWORD Count; + BOOL bResult; + + DPRINT("ScDispatcherLoop() called\n"); + + Buffer = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + 1024); + if (Buffer == NULL) + return FALSE; + while (TRUE) { /* Read command from the control pipe */ + bResult = ReadFile(hPipe, + Buffer, + 1024, + &Count, + NULL); + if (bResult == FALSE) + { + DPRINT1("Pipe read failed\n"); + return FALSE; + } /* Execute command */ + switch (Buffer[0]) + { + case SCM_START_COMMAND: + DPRINT("Start command\n"); + ScStartService((PSCM_START_PACKET)Buffer); + break; + default: + DPRINT1("Unknown command %lu", Buffer[0]); + break; + } } -#endif + + HeapFree(GetProcessHeap(), + 0, + Buffer); return TRUE; } @@ -324,7 +423,8 @@ StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable) { RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName, lpServiceStartTable[i].lpServiceName); - lpActiveServices[i].MainFunction = (LPSERVICE_MAIN_FUNCTIONW)lpServiceStartTable[i].lpServiceProc; + lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc; + lpActiveServices[i].bUnicode = FALSE; } dwError = ScConnectControlPipe(&hPipe); @@ -400,7 +500,8 @@ StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable) { RtlCreateUnicodeString(&lpActiveServices[i].ServiceName, lpServiceStartTable[i].lpServiceName); - lpActiveServices[i].MainFunction = lpServiceStartTable[i].lpServiceProc; + lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc; + lpActiveServices[i].bUnicode = TRUE; } dwError = ScConnectControlPipe(&hPipe); diff --git a/reactos/subsys/system/services/database.c b/reactos/subsys/system/services/database.c index 6348f3d0707..033e01916e1 100644 --- a/reactos/subsys/system/services/database.c +++ b/reactos/subsys/system/services/database.c @@ -32,6 +32,7 @@ #include #include +#include #include "services.h" #define NDEBUG @@ -521,8 +522,72 @@ ScmGetBootAndSystemDriverState(VOID) static NTSTATUS -ScmStartService(PSERVICE Service, - PSERVICE_GROUP Group) +ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments) +{ + PSCM_START_PACKET StartPacket; + DWORD TotalLength; +#if 0 + DWORD Length; +#endif + PWSTR Ptr; + DWORD Count; + + DPRINT("ScmSendStartCommand() called\n"); + + /* Calculate the total length of the start command line */ + TotalLength = wcslen(Service->ServiceName.Buffer) + 1; +#if 0 + if (Arguments != NULL) + { + Ptr = Arguments; + while (*Ptr) + { + Length = wcslen(Ptr) + 1; + TotalLength += Length; + Ptr += Length; + } + } +#endif + TotalLength++; + + /* Allocate start command packet */ + StartPacket = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR)); + if (StartPacket == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + StartPacket->Command = SCM_START_COMMAND; + StartPacket->Size = TotalLength; + Ptr = &StartPacket->Arguments[0]; + wcscpy(Ptr, Service->ServiceName.Buffer); + Ptr += (wcslen(Service->ServiceName.Buffer) + 1); + + /* FIXME: Copy argument list */ + + *Ptr = 0; + + /* Send the start command */ + WriteFile(Service->ControlPipeHandle, + StartPacket, + sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR), + &Count, + NULL); + + /* FIXME: Read the reply */ + + HeapFree(GetProcessHeap(), + 0, + StartPacket); + + DPRINT("ScmSendStartCommand() done\n"); + + return STATUS_SUCCESS; +} + + +static NTSTATUS +ScmStartUserModeService(PSERVICE Service) { RTL_QUERY_REGISTRY_TABLE QueryTable[3]; PROCESS_INFORMATION ProcessInformation; @@ -532,6 +597,149 @@ ScmStartService(PSERVICE Service, BOOL Result; NTSTATUS Status; + RtlInitUnicodeString(&ImagePath, NULL); + + /* Get service data */ + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].Name = L"Type"; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].EntryContext = &Type; + + QueryTable[1].Name = L"ImagePath"; + QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[1].EntryContext = &ImagePath; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, + Service->ServiceName.Buffer, + QueryTable, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); + return Status; + } + DPRINT("ImagePath: '%S'\n", ImagePath.Buffer); + DPRINT("Type: %lx\n", Type); + + /* Create '\\.\pipe\net\NtControlPipe' instance */ + Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe", + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 100, + 8000, + 4, + 30000, + NULL); + DPRINT("CreateNamedPipeW() done\n"); + if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE) + { + DPRINT1("Failed to create control pipe!\n"); + return STATUS_UNSUCCESSFUL; + } + + StartupInfo.cb = sizeof(StartupInfo); + StartupInfo.lpReserved = NULL; + StartupInfo.lpDesktop = NULL; + StartupInfo.lpTitle = NULL; + StartupInfo.dwFlags = 0; + StartupInfo.cbReserved2 = 0; + StartupInfo.lpReserved2 = 0; + + Result = CreateProcessW(ImagePath.Buffer, + NULL, + NULL, + NULL, + FALSE, + DETACHED_PROCESS | CREATE_SUSPENDED, + NULL, + NULL, + &StartupInfo, + &ProcessInformation); + RtlFreeUnicodeString(&ImagePath); + + if (!Result) + { + /* Close control pipe */ + CloseHandle(Service->ControlPipeHandle); + Service->ControlPipeHandle = INVALID_HANDLE_VALUE; + + DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer); + return STATUS_UNSUCCESSFUL; + } + + DPRINT("Process Id: %lu Handle %lx\n", + ProcessInformation.dwProcessId, + ProcessInformation.hProcess); + DPRINT("Thread Id: %lu Handle %lx\n", + ProcessInformation.dwThreadId, + ProcessInformation.hThread); + + /* Get process and thread ids */ + Service->ProcessId = ProcessInformation.dwProcessId; + Service->ThreadId = ProcessInformation.dwThreadId; + + /* Resume Thread */ + ResumeThread(ProcessInformation.hThread); + + /* Connect control pipe */ + if (ConnectNamedPipe(Service->ControlPipeHandle, NULL)) + { + DWORD dwProcessId = 0; + DWORD dwRead = 0; + + DPRINT("Control pipe connected!\n"); + + /* Read thread id from pipe */ + if (!ReadFile(Service->ControlPipeHandle, + (LPVOID)&dwProcessId, + sizeof(DWORD), + &dwRead, + NULL)) + { + DPRINT1("Reading the service control pipe failed (Error %lu)\n", + GetLastError()); + Status = STATUS_UNSUCCESSFUL; + } + else + { + DPRINT("Received process id %lu\n", dwProcessId); + + /* FIXME: Send start command */ + + Status = STATUS_SUCCESS; + } + } + else + { + DPRINT("Connecting control pipe failed!\n"); + + /* Close control pipe */ + CloseHandle(Service->ControlPipeHandle); + Service->ControlPipeHandle = INVALID_HANDLE_VALUE; + Service->ProcessId = 0; + Service->ThreadId = 0; + Status = STATUS_UNSUCCESSFUL; + } + + ScmSendStartCommand(Service, NULL); + + /* Close process and thread handle */ + CloseHandle(ProcessInformation.hThread); + CloseHandle(ProcessInformation.hProcess); + + return Status; +} + + +static NTSTATUS +ScmStartService(PSERVICE Service, + PSERVICE_GROUP Group) +{ + NTSTATUS Status; + DPRINT("ScmStartService() called\n"); Service->ControlPipeHandle = INVALID_HANDLE_VALUE; @@ -547,138 +755,10 @@ ScmStartService(PSERVICE Service, } else { - RtlInitUnicodeString(&ImagePath, NULL); - - /* Get service data */ - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].Name = L"Type"; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].EntryContext = &Type; - - QueryTable[1].Name = L"ImagePath"; - QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[1].EntryContext = &ImagePath; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, - Service->ServiceName.Buffer, - QueryTable, - NULL, - NULL); - if (NT_SUCCESS(Status)) - { - DPRINT("ImagePath: '%S'\n", ImagePath.Buffer); - DPRINT("Type: %lx\n", Type); - - /* FIXME: create '\\.\pipe\net\NtControlPipe' instance */ - Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe", - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, - 100, - 8000, - 4, - 30000, - NULL); - DPRINT("CreateNamedPipeW() done\n"); - if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE) - { - DPRINT1("Failed to create control pipe!\n"); - Status = STATUS_UNSUCCESSFUL; - goto Done; - } - - StartupInfo.cb = sizeof(StartupInfo); - StartupInfo.lpReserved = NULL; - StartupInfo.lpDesktop = NULL; - StartupInfo.lpTitle = NULL; - StartupInfo.dwFlags = 0; - StartupInfo.cbReserved2 = 0; - StartupInfo.lpReserved2 = 0; - - Result = CreateProcessW(ImagePath.Buffer, - NULL, - NULL, - NULL, - FALSE, - DETACHED_PROCESS | CREATE_SUSPENDED, - NULL, - NULL, - &StartupInfo, - &ProcessInformation); - RtlFreeUnicodeString(&ImagePath); - - if (!Result) - { - /* Close control pipe */ - CloseHandle(Service->ControlPipeHandle); - Service->ControlPipeHandle = INVALID_HANDLE_VALUE; - - DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer); - Status = STATUS_UNSUCCESSFUL; - } - else - { - DPRINT("Process Id: %lu Handle %lx\n", - ProcessInformation.dwProcessId, - ProcessInformation.hProcess); - DPRINT("Thread Id: %lu Handle %lx\n", - ProcessInformation.dwThreadId, - ProcessInformation.hThread); - - /* Get process and thread ids */ - Service->ProcessId = ProcessInformation.dwProcessId; - Service->ThreadId = ProcessInformation.dwThreadId; - - /* Resume Thread */ - ResumeThread(ProcessInformation.hThread); - - /* Connect control pipe */ - if (ConnectNamedPipe(Service->ControlPipeHandle, NULL)) - { - DWORD dwProcessId = 0; - DWORD dwRead = 0; - - DPRINT("Control pipe connected!\n"); - - /* FIXME: Read thread id from pipe */ - if (!ReadFile(Service->ControlPipeHandle, - (LPVOID)&dwProcessId, - sizeof(DWORD), - &dwRead, - NULL)) - { - DPRINT1("Reading the service control pipe failed (Error %lu)\n", GetLastError()); - } - else - { - DPRINT("Received process id %lu\n", dwProcessId); - - /* FIXME: Send start command */ - - Status = STATUS_SUCCESS; - } - } - else - { - DPRINT("Connecting control pipe failed!\n"); - - /* Close control pipe */ - CloseHandle(Service->ControlPipeHandle); - Service->ControlPipeHandle = INVALID_HANDLE_VALUE; - Service->ProcessId = 0; - Service->ThreadId = 0; - Status = STATUS_UNSUCCESSFUL; - } - - /* Close process and thread handle */ - CloseHandle(ProcessInformation.hThread); - CloseHandle(ProcessInformation.hProcess); - } - } + /* Start user-mode service */ + Status = ScmStartUserModeService(Service); } -Done: DPRINT("ScmStartService() done (Status %lx)\n", Status); if (NT_SUCCESS(Status))